Compare commits

..

79 Commits

Author SHA1 Message Date
33011ede30 [DOCS] Added partition table tutorial (#6758)
* Added partition table guide

* Using a custom partition file

* Added some more examples for partitions

* Fixed the app partition offset

* Added bare_minimum_2MB partition table file

* PR review changes
2022-05-30 13:47:53 +03:00
f3e416217d update adafruit boards tinyuf2 and partition scheme (#6770)
- add tinyuf2 suffix to variant bootloader, cvs
- also update adafruit esp32s3 menu to match latest esp32s3dev one
2022-05-30 13:46:51 +03:00
0efa90df6e Add support for Connaxio's Espoir (#6822)
Description of Change

This PR adds support for Espoir, a mikroBUS PoE+ devboard, by Connaxio inc. However, the ESP32-MINI-1 is a single core CPU, so Connaxio will provide the builds for its devboard until single core CPUs are officially supported. Adding these modifications to the official repository will limit discrepancies between Connaxio's fork and the main repo.

Tests scenarios

Tests include Ethernet, SPI, USB, I2C, UART (1-wire).

More info: https://www.connaxio.com/electronics/espoir/
2022-05-30 11:58:43 +03:00
548412952b CTS / RTS pins were swapped in this API (#6816)
espressif/esp-idf / components/driver/include/driver/uart.h defines the API:
esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int **rts_io_num**, int **cts_io_num**);
uartSetPins uses that api but alls it with swapped CTS/RTS pins as its API uses a different pin ordering: 
uart_set_pin(uart->num, txPin, rxPin, **ctsPin**, **rtsPin**); 

This fixes the wrong order in the function uartSetPins
2022-05-28 01:15:53 +03:00
3e8f7fe8d4 PlatformIO: Fix linking to make initVariant() work (#6809) 2022-05-27 13:35:32 +03:00
832c08e9fb Remove nonexisting folder from include path (#6798) 2022-05-27 13:33:15 +03:00
99ba0e1cc5 Remove -Wextra warnings (#6782)
When building the core with `-Wextra` a few locations have `case:`
fall throughs or skipped field initializers.

Add proper comments for B64 cases to avoid GCC warnings

Initialized unused fields in Tone and WiFiGeneric to avoid missing
field initializer warnings.

````
2022-05-19T17:40:42.2280300Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/libb64/cdecode.c: In function 'base64_decode_block_signed':
2022-05-19T17:40:42.2282122Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/libb64/cdecode.c:42:23: warning: this statement may fall through [-Wimplicit-fallthrough=]
2022-05-19T17:40:42.2283247Z          *plainchar    = (fragment & 0x03f) << 2;
2022-05-19T17:40:42.2284240Z          ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
2022-05-19T17:40:42.2285087Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/libb64/cdecode.c:43:7: note: here
2022-05-19T17:40:42.2285435Z        case step_b:
2022-05-19T17:40:42.2285691Z        ^~~~
2022-05-19T17:40:42.2286515Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/libb64/cdecode.c:53:23: warning: this statement may fall through [-Wimplicit-fallthrough=]
2022-05-19T17:40:42.2286932Z          *plainchar    = (fragment & 0x00f) << 4;
2022-05-19T17:40:42.2287219Z          ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
2022-05-19T17:40:42.2287609Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/libb64/cdecode.c:54:7: note: here
2022-05-19T17:40:42.2287909Z        case step_c:
2022-05-19T17:40:42.2288200Z        ^~~~
2022-05-19T17:40:42.2288972Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/libb64/cdecode.c:64:23: warning: this statement may fall through [-Wimplicit-fallthrough=]
2022-05-19T17:40:42.2289491Z          *plainchar    = (fragment & 0x003) << 6;
2022-05-19T17:40:42.2289745Z          ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
2022-05-19T17:40:42.2290162Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/libb64/cdecode.c:65:7: note: here
2022-05-19T17:40:42.2290509Z        case step_d:
2022-05-19T17:40:42.2290714Z        ^~~~
2022-05-19T17:40:42.2482744Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/libb64/cencode.c: In function 'base64_encode_block':
2022-05-19T17:40:42.2484713Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/libb64/cencode.c:46:20: warning: this statement may fall through [-Wimplicit-fallthrough=]
2022-05-19T17:40:42.2485415Z              result = (fragment & 0x003) << 4;
2022-05-19T17:40:42.2486713Z              ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
2022-05-19T17:40:42.2487696Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/libb64/cencode.c:47:9: note: here
2022-05-19T17:40:42.2488519Z          case step_B:
2022-05-19T17:40:42.2489175Z          ^~~~
2022-05-19T17:40:42.2492458Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/libb64/cencode.c:56:20: warning: this statement may fall through [-Wimplicit-fallthrough=]
2022-05-19T17:40:42.2493351Z              result = (fragment & 0x00f) << 2;
2022-05-19T17:40:42.2494227Z              ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
2022-05-19T17:40:42.2496324Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/libb64/cencode.c:57:9: note: here
2022-05-19T17:40:42.2496937Z          case step_C:
2022-05-19T17:40:42.2497261Z          ^~~~
2022-05-19T17:40:44.6354962Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/Tone.cpp: In function 'void setToneChannel(uint8_t)':
2022-05-19T17:40:44.6356417Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/Tone.cpp:99:5: warning: missing initializer for member 'tone_msg_t::pin' [-Wmissing-field-initializers]
2022-05-19T17:40:44.6357120Z      };
2022-05-19T17:40:44.6358732Z      ^
2022-05-19T17:40:44.6364470Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/Tone.cpp:99:5: warning: missing initializer for member 'tone_msg_t::frequency' [-Wmissing-field-initializers]
2022-05-19T17:40:44.6367914Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/Tone.cpp:99:5: warning: missing initializer for member 'tone_msg_t::duration' [-Wmissing-field-initializers]
2022-05-19T17:40:44.6372875Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/Tone.cpp: In function 'void noTone(uint8_t)':
2022-05-19T17:40:44.6373943Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/Tone.cpp:110:5: warning: missing initializer for member 'tone_msg_t::frequency' [-Wmissing-field-initializers]
2022-05-19T17:40:44.6375154Z      };
2022-05-19T17:40:44.6375825Z      ^
2022-05-19T17:40:44.6379852Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/Tone.cpp:110:5: warning: missing initializer for member 'tone_msg_t::duration' [-Wmissing-field-initializers]
2022-05-19T17:40:44.6383291Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/Tone.cpp:110:5: warning: missing initializer for member 'tone_msg_t::channel' [-Wmissing-field-initializers]
2022-05-19T17:40:44.6388688Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/Tone.cpp: In function 'void tone(uint8_t, unsigned int, long unsigned int)':
2022-05-19T17:40:44.6389829Z /home/runner/arduino_ide/hardware/espressif/esp32/cores/esp32/Tone.cpp:128:5: warning: missing initializer for member 'tone_msg_t::channel' [-Wmissing-field-initializers]
2022-05-19T17:40:44.6390677Z      };
2022-05-19T17:40:44.6391420Z      ^
2022-05-19T17:42:00.6768353Z /home/runner/arduino_ide/hardware/espressif/esp32/libraries/WiFi/src/WiFiGeneric.cpp: In static member function 'static bool WiFiGenericClass::setDualAntennaConfig(uint8_t, uint8_t, wifi_rx_ant_t, wifi_tx_ant_t)':
2022-05-19T17:42:00.6769293Z /home/runner/arduino_ide/hardware/espressif/esp32/libraries/WiFi/src/WiFiGeneric.cpp:1333:5: warning: missing initializer for member 'wifi_ant_config_t::rx_ant_default' [-Wmissing-field-initializers]
2022-05-19T17:42:00.6769658Z      };
2022-05-19T17:42:00.6769824Z      ^
````
2022-05-27 12:39:00 +03:00
d32d70dc0d Update littlefsbuilder.py (#6774)
add a comment to make it clear, since platformIO still creating the `spiffs.bin` for filesystem image. The file name `spiffs.bin` is so much CONFUSING! it makes the user fill the LittleFS creating is fail.
2022-05-27 12:37:39 +03:00
6b93a6c21e workflows/upload-idf-component.yml: Fix the wildcard. (#6771)
The asterisk needs to be quoted.

Signed-off-by: Abdelatif Guettouche <abdelatif.guettouche@espressif.com>
2022-05-27 12:36:52 +03:00
f9423ab83f Fix timerAttachInterrupt() and timerDetachInterrupt() in esp32-hal-timer.c (#6763)
* Fix timerAttachInterrupt() and timerDetachInterrupt() for migration to IDF 4.4

* Fixing log messages as per request
2022-05-27 12:31:16 +03:00
e5913c36ea reduce stack size requirement for this library by 4k my moving a buffer to heap. (#6745)
Better allocate the buffer for f_mkfs from the heap otherwise the stack requirement of this library is huge due to a work buffer allocated for f_mkfs in sdcard_mount. The work buffer is only needed if argument format_if_empty is set true (which is by default false). 
This change is quite important if you plan to use this library in a task. as now it increased the tasks stacks size by 4k, even this memory is never used if users are not aware of the large stack requirement during init this library may have other variables on stack that would have written memory outsides its range which can cause various side effects.

Co-authored-by: Jan Procházka <90197375+P-R-O-C-H-Y@users.noreply.github.com>
2022-05-27 12:21:24 +03:00
247bca8bda BluetoothSerial : Re-set _isRemoteAddressSet to false if connect() fails. (#6728)
The internal _isRemoteAddressSet variable is set to true
when calling connect() functions. If connecting fails _isRemoteAddressSet
needs to be re-set to false, otherwise other functions, such as
discover() will fail without clear error messages.
2022-05-27 12:20:43 +03:00
46a026a45d Doc: remove specific mention of wifi encryption... (#6671)
... as availability depends on compilation parameters.
2022-05-27 12:19:16 +03:00
2cb664eeec adc fixes and improvements (#6799)
Fixed channel / unit selection for ESP32C3 (has only 5 channels on 1 adc unit).

Removed unnecessary includes.

Fixed different attenuation on channels to be taken in care in __analogReadMilliVolt.

All chips in __analogReadMilliVolts now use adc characteristics + calculation from raw to voltage as ESP32 does.
2022-05-27 12:17:51 +03:00
2cde553e17 adds verbose message for WPA3 (#6812) 2022-05-27 11:40:49 +03:00
adb88d7bed Update bootloaders with dont-append-digest (#6800)
Fixes inability to flash the bootloader with esptool 4.x on device with flash size different than the default
2022-05-25 19:01:55 +03:00
1a7962ece8 Add option to skip image verification after OTA (#6779)
Fixes: https://github.com/espressif/arduino-esp32/issues/5871
2022-05-19 15:52:13 +03:00
2b67a4e68a HW TEST - Timer (#6754)
* Added HW timer unit test

* Adde setUp and tearDown functions
2022-05-18 11:25:36 +03:00
722c4641c4 Extends String to print 64-bit integers (#6768) 2022-05-18 11:24:03 +03:00
ba6e82c30d Adds DHCP Range Setup to APMode (#6731)
* Adds DHCP Range Setup to APMode

* ready for supporting any netmask in DHCP server
2022-05-16 20:58:02 +03:00
ad14258d2c workflows/hil.yml: Don't run the scheduled HIL workflow on forks. (#6753)
Signed-off-by: Abdelatif Guettouche <abdelatif.guettouche@espressif.com>
2022-05-16 20:56:31 +03:00
ed33e15752 Adjustable Serial Event Task Stack Size And Priority (#6685)
* Adjustable Serial Event Task Stack Size And Priority

* Added options to Kconfig

* Added Core Affinity

* Added CONFIG_FREERTOS_UNICORE

* Removed _CONFIG from FREERTOS_UNICORE

* Fixing Core choice for OnReceive() 

Makes it alligned to changes in #6718
Also eliminates conflict with #6718 for merging

Co-authored-by: Rodrigo Garcia <rodrigo.garcia@espressif.com>
Co-authored-by: Me No Dev <me-no-dev@users.noreply.github.com>
2022-05-13 13:57:13 +03:00
5482315036 Change SPI::transfer signature to match official Arduino API (#6734) 2022-05-13 13:19:47 +03:00
09c0a39d2a Update Kconfig to autoselect the proper running core (#6718)
* Update Kconfig to autoselect the proper cunning core

* Always run UDP on Core0 by default
2022-05-13 13:15:06 +03:00
a9d77ac66e Add new board XIAO_WIFI (#6702)
* Add new board XIAO_WIFI
2022-05-11 13:06:59 +03:00
14156d8071 Bugfix WiFiGeneric - SoftAP DHCPServer Corrupt Log Entry (#6719)
Fixes corrupt log entry printed by SoftAP DHCPServer.  Converts String() to expected cstr format.
2022-05-11 13:05:45 +03:00
b42b20850b Added overload on send to cleanly handle char arrays (#6721) 2022-05-11 13:01:11 +03:00
edd2bd2dab Add support for NINA-W106 with bigger flash size (#6722)
NINA-W106-00B : 32Mb / 4MB
NINA-W106-10B : 16Mb / 8MB

older NINA-W101/W102 : had 16Mb / 2MB only
2022-05-11 12:59:08 +03:00
1fed09bc74 Adds Arduino standard macro-functions (#6726)
* Adds Arduino standard functions

* Fixes round()

Adds Arduino basic math Macros with '_' prefix.
2022-05-11 12:57:50 +03:00
49bdd5f053 Add 2.0.3 option to issue template 2022-05-10 19:43:21 +03:00
709029996f fix: compiler warnings about printf-format for pointers in esp32-hal-cpu.c (#6705)
* fix(hal.cpu) compiler warn about printf-format for pointers >

warning was:
```
framework-arduinoespressif32/cores/esp32/esp32-hal-cpu.c:132:9: note: in expansion of macro 'log_e'
         log_e("not found func=%08X arg=%08X",cb,arg);
         ^~~~~
framework-arduinoespressif32/tools/sdk/esp32/include/log/include/esp_log.h:276:27: warning: format '%X' expects argument of type 'unsigned int', but argument 7 has type 'void *' [-Wformat=]

```

* fix(tone.cpp) compiler warn about printf-format for pointers >

format-str expected plain uint while `duration` is long-uint.

Warning was:
```
.../cores/esp32/esp32-hal-log.h:115:32: note: in expansion of macro 'ESP_LOG_LEVEL_LOCAL'
 #define log_d(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_DEBUG, TAG, format, ##__VA_ARGS__);}while(0)
                                ^~~~~~~~~~~~~~~~~~~
.../cores/esp32/Tone.cpp:31:9: note: in expansion of macro 'log_d'
         log_d("Task received from queue TONE_START: _pin=%d, frequency=%u Hz, duration=%u ms", tone_msg.pin, tone_msg.frequency, tone_msg.duration);
         ^~~~~
.../tools/sdk/esp32/include/log/include/esp_log.h:276:27: warning: format '%u' expects argument of type 'unsigned int', but argument 8 has type 'long unsigned int' [-Wformat=]
```
2022-05-09 23:40:44 +03:00
bdeef89cc6 fixing beginTransaction() thread safety (#6425) 2022-05-09 23:38:59 +03:00
ca77502ceb Added compiler.warning_flags to platform.txt; fixing #6118 (#6596)
Summary

Added compiler.warning_flags to all chips in platform.txt to reflect users setting of warning level output during compilation (set up in Arduino IDE preferences)

Impact

When a warning is set to none the compilation will no longer display warnings

Related links

Solves issue #6118
2022-05-09 23:17:12 +03:00
d302091267 Changed pinMode() default interrupt type DISABLED to previously set (#6695)
* Changed in pinMode() default  intr_type

pins default configuration has intr_type =  GPIO_INTR_DISABLE
With this implementation, it will set the intr_type to previously set intr_type. It will no longer disable interrupt, when pinmode is called multiple times on same pin with interrupt enabled.
2022-05-09 23:14:59 +03:00
5dc4226cc5 hil.yml: Run the Event-file job only when the PR is labeled or the (#6717)
Workflow is scheduled.

It looks like the depedency on the Test job was not enough and the Event
job was triggering even without the label.

Signed-off-by: Abdelatif Guettouche <abdelatif.guettouche@espressif.com>
2022-05-09 16:00:42 +03:00
85ec66a4e0 fixed timer_dev definition (#6716) 2022-05-09 16:00:09 +03:00
44beee2f2c Fixes DNS Server Memory Leak when deleted (#6707) 2022-05-09 15:59:24 +03:00
0b3f1a9fa9 Update core version 2022-05-04 18:55:21 +03:00
6707ceb63c Upload component to the registry on any tag (#6688)
upload-idf-component.yml action was only running for tags like v*, while in this project tags like 2.0.3 are used. With this change, the workflow will run for all tags.
2022-05-04 18:50:51 +03:00
142fceb856 Fix uploader tool for ESPduino32 board (#6665) 2022-05-04 14:36:15 +03:00
ba591fd958 Added non-destructive TinyUF2 support for UM ESP32-S3 boards (#6668)
Implemented a new method for allowing folks to preserve their TinyUF2 bootloader setup when flashing their boards via Arduino IDE, without being locked out of not using it if they want to use a different partition.

Adafruit had already added support for keeping (reflashing) the TinyUF2 bootloader when flashing via Arduino IDE (thanks @ladyada ), but the issue with it is it doesn't allow users to not choose to use it. Even if they select a specific partition scheme from the partition drop down list, it ignores that selection and only does the TinyUF2 partitioning/bootloader thing.

We wanted to let users choose between keeping their TinyUF2 partitioning and bootloader, or choose another partition scheme and have the TinyUF2 support disabled and just operate like they would expect.

We've implemented this by adding the TinyUF2 support as a partition scheme option, and using these build options in platform.txt to choose to use teh UF2 path or use the standard path.
2022-05-04 14:35:46 +03:00
4453ca5493 Properly handle ARDUINO_PARTITION define in PlatformIO (#6681)
This fixes possible issues when developers specify arbitrary partition files
using relative or absolute paths.

Additionally, hyphens in filenames are replaced with underscores to
avoid compilation warnings "ISO C++11 requires whitespace after the macro name"

Resolves platformio/platform-espressif32#787
2022-05-04 14:31:30 +03:00
ce2cd111a1 Fixes INADDR_NONE (#6659)
Description of Change

Fixes IPAddress INADDR_NONE declaration when using Arduino WiFi or ETH.
This symbol was defined as 0xffffffff by lwip /inet.h, making it impossible to use INADDR_NONE correctly.

This PR only works when <wifi-provisioning/wifi_config.h> has a modification to include <lwip/ip4_addr.h> instead of <lwip/inet.h>. This will be done directly to the sdk folder in the github structure and it has been fixed in IDF by a separated Merge Request. This will be reflected in the future, for good.

Tests scenarios

This PR was tested with all Arduino WiFi examples, including AsyncUDP. Also with ETH examples.
It was also tested for #6610 test cases.
Testing done for ESP32, ESP32-S2, ESP32-C3 and ESP32-S3.

Related links

fixes #6610
fixes #6247
fixes #4732
2022-04-29 11:13:07 +03:00
5f6d093d4a Add more controls over WiFi.begin and WiFi.scan (#6651)
Added options to WiFi STA for connect:
- setMinSecurity: default WIFI_AUTH_WPA2_PSK
- setScanMethod: default WIFI_FAST_SCAN
- setSortMethod: default WIFI_CONNECT_AP_BY_SIGNAL (required all channels scan method)

Added parameters for SSID and BSSID to WiFi.scanNetworks()

Fixes: #6485
Fixes: Any issue about WiFi connecting slower now than in 1.0.x
2022-04-28 11:01:58 +03:00
51bf1832b8 Fix onRequest being called for every slave address (#6649)
Fixes: https://github.com/espressif/arduino-esp32/issues/5907
2022-04-28 02:31:32 +03:00
384dbc2081 Added support for Trueverit ESP32 Universal IoT Driver MK III (#6640)
Add support for the Trueverit Universal IoT Driver MK III (https://www.trueverit.com/)

The board will be released on market using electronic distributors soon, as the other one board added via #5269

This new board (referred as MK III) has onboard Texas Instruments RTL8201 Eth PHY chip.
2022-04-27 12:45:23 +03:00
f2cfe78705 Fix HTTP Client failing to connect because of wrong timeout (#6633) 2022-04-27 03:36:38 +03:00
45583af189 [Docs] Actualize PlatformIO installation instructions (#6629)
* Actualize PlatformIO installation instructions

Split instructions for stable and upstream versions

* Add link to platformio.ini documentation
2022-04-26 14:29:54 +01:00
f60cd8a069 Add CI job which tries to build arduino-esp32 as a component (#5842)
Co-authored-by: Me No Dev <me-no-dev@users.noreply.github.com>
2022-04-26 15:10:17 +03:00
5fa0c2010e Added Unexpected Maker Reflow Master Pro (UM RMP) board (#6630)
Fixed wrong SCK and MISO pins for TinyS2
2022-04-26 14:55:19 +03:00
adfaaecc65 add AirM2M_CORE_ESP32C3 board (#6613)
* add AirM2M_CORE_ESP32C3 board
2022-04-26 14:50:14 +03:00
0dd517dc9f enh(log) salvage TAG from ESP_IDF log-statements > (#6567)
by converting result log-rows from the 1st line to the 2nd (`NET` is the tag):
```
[ 73419][D][telelogger.cpp:915] telemetry(): state: 33C

[ 73419][D][telelogger.cpp:915] telemetry(): [NET] state: 33C
```

Co-authored-by: Me No Dev <me-no-dev@users.noreply.github.com>
2022-04-26 14:46:42 +03:00
823fe77e41 Uniform behaviour of WiFiClientSecure and WiFiClient setTimeout() (#6562)
* Uniform timeout WiFiClient-WiFiClientSecure

* Added missing prototype

* Add socket check on setTimeout
2022-04-26 14:46:07 +03:00
a9d33de70e Call i2c_set_timeout in i2cSetClock (#6537) 2022-04-26 14:45:14 +03:00
d7ffd573d0 Fixes stream load memory leak in WifiSecureClient for SSL CACert, Certificate, and (#6387)
Private Key. Issue presented during any subsequent invocation of loadCACert, loadCertificate, and
loadPrivateKey, respectively, after the first invocation.
2022-04-26 14:44:37 +03:00
b88a70a0bd Allow BluetoothSerial::connect() with specified channel and more options (#6380)
* BTAddress const, add bool()

* BTAdvertisedDevice: const functions

* BluetoothSerial: add: getChannels, add isClosed, add read/peek timeout, add connect with channel#

* BluetoothSerial: add sec_mask, role in ::connect

* BluetoothSerial add discover and connect with channel number example

* DiscoverConnect: add SPP_ENABLED check

* DiscoverConnect: disable on esp32s3
2022-04-26 14:41:29 +03:00
f3bdfb31f9 Touch change to init only selected GPIO. (#6609)
* Separated init for touch / channel called by touchRead()

* compile error

* Fixed touch_V2 + ISR
2022-04-26 14:34:50 +03:00
d8a99ed449 Added RainMaker support on Arduino IDE for ESP32-C3/S2/S3 (#6598)
* Added RainMaker support on Arduino IDE for ESP32-C3/S2/S3

Closes #6573
Note related to the issue #6435
2022-04-26 14:12:20 +03:00
0a1ba74b60 Update LittleFS PlatformIO example (#6617) 2022-04-26 14:02:14 +03:00
1aa16104ff Enable LittleFs sketches for C3 (#6618)
* LittleFs is working with C3

* Delete .skip.esp32c3
2022-04-26 14:00:14 +03:00
22c51579da publish.yml: Remove a leftover parenthesis that was making the workflow (#6620)
Description of Change

Remove a leftover parenthesis that was making the workflow that was making the workflow invalid.

Tests scenarios

Github Workflow.

Related links

https://github.com/espressif/arduino-esp32/actions/runs/2213167501

Signed-off-by: Abdelatif Guettouche <abdelatif.guettouche@espressif.com>
2022-04-26 13:59:03 +03:00
f0636d515f Add support for extra flash images (#6625)
This PR adds support for uploading additional flash images (e.g. Adafruit Tiny UF2 bootloader) specified in board manifests.

Additionally, the PR switches the PlatformIO CI script to the upstream version of the ESP32 dev-platform (basically reverts changes introduced in #5387 as they are no longer required).
2022-04-26 13:58:16 +03:00
b3c203db26 Pull request/Issue Templates and Readme update (#6577)
* Templates and readme

* Templates_and_readme
2022-04-21 17:54:50 +03:00
323bbbf63b workflows/publish.yml: Run the workflow on success and failure only. (#6531)
* workflows/publish.yml: Run the workflow on success and failure only.
This prevents trying to run when the trigger was cancelled or skipped.
In these cases there will be no event file to upload.

Signed-off-by: Abdelatif Guettouche <abdelatif.guettouche@espressif.com>

* scripts/sketch_utils.sh: Move the logic that gets the build dir after
the part that retrieves the arguments.

Signed-off-by: Abdelatif Guettouche <abdelatif.guettouche@espressif.com>

* workflows/hil.yml: Update the HIL runners tags.

Signed-off-by: Abdelatif Guettouche <abdelatif.guettouche@espressif.com>

* workflows/hil.yml: Remove the Check Artifacts step.  That was only
useful for debugging.

Signed-off-by: Abdelatif Guettouche <abdelatif.guettouche@espressif.com>
2022-04-21 17:53:37 +03:00
02f4178b72 BUGFIX: FS read + speed improvements for SD (#6569)
* Revert "Edited VFSFileImpl::read to use both read/fread (#6456)"

This reverts commit 7b89b39e10.

* Added default file buffer size + function to change it by user
2022-04-21 17:51:44 +03:00
e1c9606531 Changed type of LEDC frequency from double to uint32_t (#6570) 2022-04-21 17:50:55 +03:00
fb60efd592 Change pinMode OUTPUT to INPUT_OUTPUT (#6602)
* Change OUTPUT to INPUT_OUTPUT

To match the official Arduino API.
2022-04-21 17:49:54 +03:00
12045d335b Update camera example to support face detection and recognition (#6603)
Fixes: #6508
2022-04-21 17:48:47 +03:00
45b7fa05b6 IDF release/v4.4 b8050b365e (#6594) 2022-04-20 12:23:18 +03:00
d3340837c7 Delete stale.yml 2022-04-20 10:54:46 +03:00
6cfe4613e4 Amend "GPIO refactoring (#6259)" (#6527) 2022-04-05 11:28:59 +03:00
7dc8ca4e1e Update OTA Command for IDE 2.0 2022-04-05 03:33:42 +03:00
d4e20294e5 Add support for ArduinoIDE 2.0.0 (#6506)
OTA is not yet working properly on the new IDE. Info: https://github.com/arduino/arduino-ide/issues/740#issuecomment-1086595394
2022-04-04 17:19:23 +03:00
f1acc432af Fix Ticker::Active crash if _ticker null (#6511) (#6513) 2022-04-04 14:45:14 +03:00
6fe1c4c5d6 Correct less- and greater-than operators (#6521)
Lets Manufacturer ranges in bluetooth address space be filtered correctly
2022-04-04 14:44:32 +03:00
5d6b9d0939 Compiler error (#6523)
Error on compile Arduino as an ESP-IDF component
2022-04-04 14:29:45 +03:00
6b72fee59b add S3 board (#6518) 2022-04-04 14:27:53 +03:00
a1409ef90d add package.json to release zip (#6501)
* add package.json to release zip

so it is directly useable from PlatformIO
2022-04-04 14:24:17 +03:00
ab197e12a9 Fix - wrong path to file (#6505) 2022-03-31 16:54:33 +03:00
310 changed files with 4595 additions and 1297 deletions

View File

@ -39,7 +39,9 @@ body:
label: Version
description: What version of Arduino ESP32 are you running? If possible, consider updating to the latest version.
options:
- latest master
- latest master (checkout manually)
- latest development Release Candidate (RC-X)
- v2.0.3
- v2.0.2
- v2.0.1
- v2.0.0
@ -52,7 +54,7 @@ body:
attributes:
label: IDE Name
description: What IDE are you using?
placeholder: eg. Arduino IDE, PlatformIO, IDF component...
placeholder: eg. Arduino IDE, PlatformIO, Sloeber...
validations:
required: true
- type: input
@ -101,8 +103,8 @@ body:
id: sketch
attributes:
label: Sketch
description: Please provide your sketch/code which was run
placeholder: ex. related part of the code
description: Please provide full minimal sketch/code which can be run to reproduce your issue
placeholder: ex. Related part of the code to replicate the issue
render: cpp
validations:
required: true
@ -128,4 +130,4 @@ body:
description: You agree to check all the resources above before opening a new issue.
options:
- label: I confirm I have checked existing issues, online documentation and Troubleshooting guide.
required: true
required: true

View File

@ -1,18 +1,23 @@
*By completing this PR sufficiently, you help us to improve the quality of Release Notes*
*By completing this PR sufficiently, you help us to review this Pull Request quicker and also help improve the quality of Release Notes*
### Checklist
1. [ ] Please provide specific title of the PR describing the change, including the component name (eg. *„Update of Documentation link on Readme.md“*)
2. [ ] Please provide related links (eg. Issue, other Project, submodule PR..)
3. [ ] Please check [Contributing guide](https://docs.espressif.com/projects/arduino-esp32/en/latest/contributing.html)
1. [ ] Please provide specific title of the PR describing the change, including the component name (*eg. „Update of Documentation link on Readme.md“*)
2. [ ] Please provide related links (*eg. Issue which will be closed by this Pull Request*)
3. [ ] Please **update relevant Documentation** if applicable
4. [ ] Please check [Contributing guide](https://docs.espressif.com/projects/arduino-esp32/en/latest/contributing.html)
*This entire section above can be deleted if all items are checked.*
-----------
## Summary
Please describe your proposed PR and what it contains.
## Description of Change
Please describe your proposed Pull Request and it's impact.
## Impact
Please describe impact of your PR and it's function.
## Tests scenarios
Please describe on what Hardware and Software combinations you have tested this Pull Request and how.
(*eg. I have tested my Pull Request on Arduino-esp32 core v2.0.2 with ESP32 and ESP32-S2 Board with this scenario*)
## Related links
Please provide links to related issue, PRs etc.
(*eg. Closes #number of issue*)

View File

@ -1,7 +1,7 @@
#!/bin/bash
export PLATFORMIO_ESP32_PATH="$HOME/.platformio/packages/framework-arduinoespressif32"
PLATFORMIO_ESP32_URL="https://github.com/platformio/platform-espressif32.git#feature/arduino-idf-master"
PLATFORMIO_ESP32_URL="https://github.com/platformio/platform-espressif32.git"
TOOLCHAIN_VERSION="8.4.0+2021r2-patch3"
ESPTOOLPY_VERSION="~1.30100.0"

View File

@ -172,6 +172,7 @@ mkdir -p "$PKG_DIR/tools"
# Copy all core files to the package folder
echo "Copying files for packaging ..."
cp -f "$GITHUB_WORKSPACE/boards.txt" "$PKG_DIR/"
cp -f "$GITHUB_WORKSPACE/package.json" "$PKG_DIR/"
cp -f "$GITHUB_WORKSPACE/programmers.txt" "$PKG_DIR/"
cp -Rf "$GITHUB_WORKSPACE/cores" "$PKG_DIR/"
cp -Rf "$GITHUB_WORKSPACE/libraries" "$PKG_DIR/"

View File

@ -7,12 +7,6 @@ function build_sketch(){ # build_sketch <ide_path> <user_path> <fqbn> <path-to-i
return 1
fi
ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp"
if [ -z "$ARDUINO_BUILD_DIR" ]; then
build_dir="$(dirname $sketch)/build"
else
build_dir="$ARDUINO_BUILD_DIR"
fi
local ide_path=$1
local usr_path=$2
local fqbn=$3
@ -20,6 +14,15 @@ function build_sketch(){ # build_sketch <ide_path> <user_path> <fqbn> <path-to-i
local xtra_opts=$5
local win_opts=$6
ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp"
if [ -z "$ARDUINO_BUILD_DIR" ]; then
build_dir="$(dirname $sketch)/build"
else
build_dir="$ARDUINO_BUILD_DIR"
fi
echo $sketch
rm -rf "$build_dir"
mkdir -p "$build_dir"
mkdir -p "$ARDUINO_CACHE_DIR"

View File

@ -1,5 +1,9 @@
#!/bin/bash
# For reference: add tools for all boards by replacing one line in each board
# "[board].upload.tool=esptool_py" to "[board].upload.tool=esptool_py\n[board].upload.tool.default=esptool_py\n[board].upload.tool.network=esp_ota"
#cat boards.txt | sed "s/\([a-zA-Z0-9_\-]*\)\.upload\.tool\=esptool_py/\1\.upload\.tool\=esptool_py\\n\1\.upload\.tool\.default\=esptool_py\\n\1\.upload\.tool\.network\=esp_ota/"
if [ ! $# -eq 3 ]; then
echo "Bad number of arguments: $#" >&2
echo "usage: $0 <major> <minor> <patch>" >&2

26
.github/stale.yml vendored
View File

@ -1,26 +0,0 @@
# This workflow firstly warns and then closes issues that have had no activity for a specified amount of time.
#
# You can adjust the behavior by modifying this file.
# For more information can be found here: https://github.com/actions/stale
name: Mark stale issues
on:
schedule:
- cron: '30 9 * * *'
jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: '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.'
days-before-stale: 60
days-before-close: 14
exempt-issue-labels: 'Type: For reference,Type: To be implemented,Type: Feature request'
stale-issue-label: 'Status: Stale'

View File

@ -18,7 +18,7 @@ jobs:
gen_chunks:
if: |
contains(github.event.pull_request.labels.*.name, 'hil_test') ||
github.event_name == 'schedule'
(github.event_name == 'schedule' && github.repository == 'espressif/arduino-esp32')
name: Generate Chunks matrix
runs-on: ubuntu-latest
outputs:
@ -67,7 +67,12 @@ jobs:
Test:
needs: [gen_chunks, Build]
name: ${{matrix.chip}}-Test#${{matrix.chunks}}
runs-on: ESP32
runs-on:
- ESP32
- ESP32-S2
- ESP32-S3
- ESP32-C3
strategy:
fail-fast: false
matrix:
@ -87,11 +92,6 @@ jobs:
name: ${{matrix.chip}}-${{matrix.chunks}}.artifacts
path: tests/
- name: Check Artifacts
run: |
ls -R tests
cat tests/*/build/build.options.json
- name: Install dependencies
run: |
pip install -U pip
@ -110,7 +110,9 @@ jobs:
event_file:
name: "Event File"
if: ${{ always() }}
if: |
contains(github.event.pull_request.labels.*.name, 'hil_test') ||
github.event_name == 'schedule'
needs: Test
runs-on: ubuntu-latest
steps:

View File

@ -14,7 +14,8 @@ jobs:
runs-on: ubuntu-latest
if: |
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion != 'skipped'
(github.event.workflow_run.conclusion == 'success' ||
github.event.workflow_run.conclusion == 'failure')
steps:
- name: Download and Extract Artifacts
env:

View File

@ -78,3 +78,30 @@ jobs:
python-version: '3.x'
- name: Build Sketches
run: bash ./.github/scripts/on-push.sh 1 1 #equal and non-zero to trigger PIO
build-esp-idf-component:
name: Build with ESP-IDF ${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
runs-on: ubuntu-20.04
strategy:
matrix:
# The version names here correspond to the versions of espressif/idf Docker image.
# See https://hub.docker.com/r/espressif/idf/tags and
# https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-docker-image.html
# for details.
idf_ver: ["release-v4.4"]
idf_target: ["esp32", "esp32s2", "esp32s3", "esp32c3"]
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Check out arduino-esp32 as a component
uses: actions/checkout@v2
with:
submodules: recursive
path: components/arduino-esp32
- name: Build
env:
IDF_TARGET: ${{ matrix.idf_target }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
idf.py create-project test
idf.py -C test -DEXTRA_COMPONENT_DIRS=$PWD/components build

View File

@ -2,7 +2,7 @@ name: Push components to https://components.espressif.com
on:
push:
tags:
- v*
- '*'
jobs:
upload_components:
runs-on: ubuntu-latest

View File

@ -95,6 +95,8 @@ set(LIBRARY_SRCS
libraries/RainMaker/src/RMakerParam.cpp
libraries/RainMaker/src/RMakerDevice.cpp
libraries/RainMaker/src/RMakerType.cpp
libraries/RainMaker/src/RMakerQR.cpp
libraries/RainMaker/src/RMakerUtils.cpp
libraries/SD_MMC/src/SD_MMC.cpp
libraries/SD/src/SD.cpp
libraries/SD/src/sd_diskio.cpp

View File

@ -21,7 +21,8 @@ config AUTOSTART_ARDUINO
choice ARDUINO_RUNNING_CORE
bool "Core on which Arduino's setup() and loop() are running"
default ARDUINO_RUN_CORE1
default ARDUINO_RUN_CORE0 if FREERTOS_UNICORE
default ARDUINO_RUN_CORE1 if !FREERTOS_UNICORE
help
Select on which core Arduino's setup() and loop() functions run
@ -29,8 +30,10 @@ choice ARDUINO_RUNNING_CORE
bool "CORE 0"
config ARDUINO_RUN_CORE1
bool "CORE 1"
depends on !FREERTOS_UNICORE
config ARDUINO_RUN_NO_AFFINITY
bool "BOTH"
depends on !FREERTOS_UNICORE
endchoice
@ -48,7 +51,8 @@ config ARDUINO_LOOP_STACK_SIZE
choice ARDUINO_EVENT_RUNNING_CORE
bool "Core on which Arduino's event handler is running"
default ARDUINO_EVENT_RUN_CORE1
default ARDUINO_EVENT_RUN_CORE0 if FREERTOS_UNICORE
default ARDUINO_EVENT_RUN_CORE1 if !FREERTOS_UNICORE
help
Select on which core Arduino's WiFi.onEvent() run
@ -56,8 +60,10 @@ choice ARDUINO_EVENT_RUNNING_CORE
bool "CORE 0"
config ARDUINO_EVENT_RUN_CORE1
bool "CORE 1"
depends on !FREERTOS_UNICORE
config ARDUINO_EVENT_RUN_NO_AFFINITY
bool "BOTH"
depends on !FREERTOS_UNICORE
endchoice
@ -67,9 +73,45 @@ config ARDUINO_EVENT_RUNNING_CORE
default 1 if ARDUINO_EVENT_RUN_CORE1
default -1 if ARDUINO_EVENT_RUN_NO_AFFINITY
choice ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE
bool "Core on which Arduino's Serial Event task is running"
default ARDUINO_SERIAL_EVENT_RUN_CORE0 if FREERTOS_UNICORE
default ARDUINO_SERIAL_EVENT_RUN_NO_AFFINITY if !FREERTOS_UNICORE
help
Select on which core Arduino's Serial Event task run
config ARDUINO_SERIAL_EVENT_RUN_CORE0
bool "CORE 0"
config ARDUINO_SERIAL_EVENT_RUN_CORE1
bool "CORE 1"
depends on !FREERTOS_UNICORE
config ARDUINO_SERIAL_EVENT_RUN_NO_AFFINITY
bool "BOTH"
depends on !FREERTOS_UNICORE
endchoice
config ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE
int
default 0 if ARDUINO_SERIAL_EVENT_RUN_CORE0
default 1 if ARDUINO_SERIAL_EVENT_RUN_CORE1
default -1 if ARDUINO_SERIAL_EVENT_RUN_NO_AFFINITY
config ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE
int "Serial Event task stack size"
default 2048
help
Amount of stack available for the Serial Event task.
config ARDUINO_SERIAL_EVENT_TASK_PRIORITY
int "Priority of the Serial Event task"
default 24
help
Select at what priority you want the Serial Event task to run.
choice ARDUINO_UDP_RUNNING_CORE
bool "Core on which Arduino's UDP is running"
default ARDUINO_UDP_RUN_CORE1
default ARDUINO_UDP_RUN_CORE0
help
Select on which core Arduino's UDP run
@ -77,23 +119,25 @@ choice ARDUINO_UDP_RUNNING_CORE
bool "CORE 0"
config ARDUINO_UDP_RUN_CORE1
bool "CORE 1"
depends on !FREERTOS_UNICORE
config ARDUINO_UDP_RUN_NO_AFFINITY
bool "BOTH"
depends on !FREERTOS_UNICORE
endchoice
config ARDUINO_UDP_TASK_PRIORITY
int "Priority of the UDP task"
default 3
help
Select at what priority you want the UDP task to run.
config ARDUINO_UDP_RUNNING_CORE
int
default 0 if ARDUINO_UDP_RUN_CORE0
default 1 if ARDUINO_UDP_RUN_CORE1
default -1 if ARDUINO_UDP_RUN_NO_AFFINITY
config ARDUINO_UDP_TASK_PRIORITY
int "Priority of the UDP task"
default 3
help
Select at what priority you want the UDP task to run.
config ARDUINO_ISR_IRAM
bool "Run interrupts in IRAM"
default "n"
@ -356,3 +400,4 @@ config ARDUINO_SELECTIVE_Wire
endmenu

View File

@ -2,13 +2,17 @@
![Build Status](https://github.com/espressif/arduino-esp32/workflows/ESP32%20Arduino%20CI/badge.svg) [![Documentation Status](https://readthedocs.com/projects/espressif-arduino-esp32/badge/?version=latest)](https://docs.espressif.com/projects/arduino-esp32/en/latest/?badge=latest)
### Need help or have a question? Join the chat at [![https://gitter.im/espressif/arduino-esp32](https://badges.gitter.im/espressif/arduino-esp32.svg)](https://gitter.im/espressif/arduino-esp32?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
### Need help or have a question? Join the chat at [![https://gitter.im/espressif/arduino-esp32](https://badges.gitter.im/espressif/arduino-esp32.svg)](https://gitter.im/espressif/arduino-esp32?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) or [open a new Discussion](https://github.com/espressif/arduino-esp32/discussions)
## Contents
- [Development Status](#development-status)
- [Decoding Exceptions](#decoding-exceptions)
- [Issue/Bug report template](#issuebug-report-template)
- [Development Status](#development-status)
- [Development Planning](#development-planning)
- [Documentation](#documentation)
- [Supported Chips](#supported-chips)
- [Decoding exceptions](#decoding-exceptions)
- [Issue/Bug report template](#issuebug-report-template)
- [Contributing](#contributing)
### Development Status
@ -16,9 +20,15 @@ Latest Stable Release [![Release Version](https://img.shields.io/github/release
Latest Development Release [![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32/all.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/) [![Release Date](https://img.shields.io/github/release-date-pre/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/) [![Downloads](https://img.shields.io/github/downloads-pre/espressif/arduino-esp32/latest/total.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/)
### Development Planning
Our Development is fully tracked on this public **[Roadmap 🎉](https://github.com/orgs/espressif/projects/3)**
For even more information you can take a look at [Sprint Meeting notes](https://github.com/espressif/arduino-esp32/discussions/categories/sprints-meeting-notes) or join [Monthly Community Meetings 🔔](https://github.com/espressif/arduino-esp32/discussions/categories/monthly-community-meetings)
### Documentation
You can use [Arduino-ESP32 Online Documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/) to get all information about this project.
You can use the [Arduino-ESP32 Online Documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/) to get all information about this project.
* [Getting Started](https://docs.espressif.com/projects/arduino-esp32/en/latest/getting_started.html)
* [Installing (Windows, Linux and macOS)](https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html)
@ -36,6 +46,7 @@ Visit the [supported chips](https://docs.espressif.com/projects/arduino-esp32/en
You can use [EspExceptionDecoder](https://github.com/me-no-dev/EspExceptionDecoder) to get meaningful call trace.
### Issue/Bug report template
Before reporting an issue, make sure you've searched for similar one that was already created. Also make sure to go through all the issues labelled as [Type: For reference](https://github.com/espressif/arduino-esp32/issues?q=is%3Aissue+label%3A%22Type%3A+For+reference%22+).
Finally, if you are sure no one else had the issue, follow the **Issue template** or **Feature request template** while reporting any [new Issue](https://github.com/espressif/arduino-esp32/issues/new/choose).

1918
boards.txt Executable file → Normal file

File diff suppressed because it is too large Load Diff

View File

@ -69,7 +69,12 @@
#define __STRINGIFY(a) #a
#endif
// can't define max() / min() because of conflicts with C++
#define _min(a,b) ((a)<(b)?(a):(b))
#define _max(a,b) ((a)>(b)?(a):(b))
#define _abs(x) ((x)>0?(x):-(x)) // abs() comes from STL
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#define _round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) // round() comes from STL
#define radians(deg) ((deg)*DEG_TO_RAD)
#define degrees(rad) ((rad)*RAD_TO_DEG)
#define sq(x) ((x)*(x))
@ -89,6 +94,7 @@
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitToggle(value, bit) ((value) ^= (1UL << (bit)))
#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit))
// avr-libc defines _NOP() since 1.6.2
@ -168,12 +174,13 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
#include "Esp.h"
#include "esp32/spiram.h"
// Use float-compatible stl abs() and round(), we don't use Arduino macros to avoid issues with the C++ libraries
using std::abs;
using std::isinf;
using std::isnan;
using std::max;
using std::min;
using ::round;
using std::round;
uint16_t makeWord(uint16_t w);
uint16_t makeWord(uint8_t h, uint8_t l);
@ -203,9 +210,6 @@ void noTone(uint8_t _pin);
long random(long);
#endif /* __cplusplus */
#define _min(a,b) ((a)<(b)?(a):(b))
#define _max(a,b) ((a)>(b)?(a):(b))
#include "pins_arduino.h"
#endif /* _ESP32_CORE_ARDUINO_H_ */

View File

@ -9,6 +9,18 @@
#include "driver/uart.h"
#include "freertos/queue.h"
#ifndef ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE
#define ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE 2048
#endif
#ifndef ARDUINO_SERIAL_EVENT_TASK_PRIORITY
#define ARDUINO_SERIAL_EVENT_TASK_PRIORITY (configMAX_PRIORITIES-1)
#endif
#ifndef ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE
#define ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE -1
#endif
#ifndef SOC_RX0
#if CONFIG_IDF_TARGET_ESP32
#define SOC_RX0 3
@ -159,7 +171,7 @@ HardwareSerial::~HardwareSerial()
void HardwareSerial::_createEventTask(void *args)
{
// Creating UART event Task
xTaskCreate(_uartEventTask, "uart_event_task", 2048, this, configMAX_PRIORITIES - 1, &_eventTask);
xTaskCreateUniversal(_uartEventTask, "uart_event_task", ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE, this, ARDUINO_SERIAL_EVENT_TASK_PRIORITY, &_eventTask, ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE);
if (_eventTask == NULL) {
log_e(" -- UART%d Event Task not Created!", _uart_nr);
}

View File

@ -120,3 +120,6 @@ bool IPAddress::fromString(const char *address)
_address.bytes[3] = acc;
return true;
}
// declared one time - as external in IPAddress.h
IPAddress INADDR_NONE(0, 0, 0, 0);

View File

@ -91,6 +91,6 @@ public:
friend class DNSClient;
};
const IPAddress INADDR_NONE(0, 0, 0, 0);
// changed to extern because const declaration creates copies in BSS of INADDR_NONE for each CPP unit that includes it
extern IPAddress INADDR_NONE;
#endif

View File

@ -28,7 +28,7 @@ static void tone_task(void*){
xQueueReceive(_tone_queue, &tone_msg, portMAX_DELAY);
switch(tone_msg.tone_cmd){
case TONE_START:
log_d("Task received from queue TONE_START: _pin=%d, frequency=%u Hz, duration=%u ms", tone_msg.pin, tone_msg.frequency, tone_msg.duration);
log_d("Task received from queue TONE_START: _pin=%d, frequency=%u Hz, duration=%lu ms", tone_msg.pin, tone_msg.frequency, tone_msg.duration);
log_d("Setup LED controll on channel %d", _channel);
// ledcSetup(_channel, tone_msg.frequency, 11);
@ -95,6 +95,9 @@ void setToneChannel(uint8_t channel){
if(tone_init()){
tone_msg_t tone_msg = {
.tone_cmd = TONE_SET_CHANNEL,
.pin = 0, // Ignored
.frequency = 0, // Ignored
.duration = 0, // Ignored
.channel = channel
};
xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY);
@ -106,7 +109,10 @@ void noTone(uint8_t _pin){
if(tone_init()){
tone_msg_t tone_msg = {
.tone_cmd = TONE_END,
.pin = _pin
.pin = _pin,
.frequency = 0, // Ignored
.duration = 0, // Ignored
.channel = 0 // Ignored
};
xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY);
}
@ -118,13 +124,14 @@ void noTone(uint8_t _pin){
// duration - time in ms - how long will the signal be outputted.
// If not provided, or 0 you must manually call noTone to end output
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){
log_d("_pin=%d, frequency=%u Hz, duration=%u ms", _pin, frequency, duration);
log_d("_pin=%d, frequency=%u Hz, duration=%lu ms", _pin, frequency, duration);
if(tone_init()){
tone_msg_t tone_msg = {
.tone_cmd = TONE_START,
.pin = _pin,
.frequency = frequency,
.duration = duration
.duration = duration,
.channel = 0 // Ignored
};
xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY);
}

View File

@ -137,6 +137,24 @@ String::String(double value, unsigned int decimalPlaces) {
}
}
String::String(long long value, unsigned char base) {
init();
char buf[2 + 8 * sizeof(long long)];
if (base==10) {
sprintf(buf, "%lld", value); // NOT SURE - NewLib Nano ... does it support %lld?
} else {
lltoa(value, buf, base);
}
*this = buf;
}
String::String(unsigned long long value, unsigned char base) {
init();
char buf[1 + 8 * sizeof(unsigned long long)];
ulltoa(value, buf, base);
*this = buf;
}
String::~String() {
invalidate();
}
@ -408,6 +426,17 @@ unsigned char String::concat(double num) {
return concat(string, strlen(string));
}
unsigned char String::concat(long long num) {
char buf[2 + 3 * sizeof(long long)];
return concat(buf, sprintf(buf, "%lld", num)); // NOT SURE - NewLib Nano ... does it support %lld?
}
unsigned char String::concat(unsigned long long num) {
char buf[1 + 3 * sizeof(unsigned long long)];
ulltoa(num, buf, 10);
return concat(buf, strlen(buf));
}
unsigned char String::concat(const __FlashStringHelper * str) {
if (!str) return 0;
int length = strlen_P((PGM_P)str);
@ -493,6 +522,20 @@ StringSumHelper & operator +(const StringSumHelper &lhs, double num) {
return a;
}
StringSumHelper & operator +(const StringSumHelper &lhs, long long num) {
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
if(!a.concat(num))
a.invalidate();
return a;
}
StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long long num) {
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
if(!a.concat(num))
a.invalidate();
return a;
}
StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs)
{
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);

View File

@ -73,6 +73,8 @@ class String {
explicit String(unsigned long, unsigned char base = 10);
explicit String(float, unsigned int decimalPlaces = 2);
explicit String(double, unsigned int decimalPlaces = 2);
explicit String(long long, unsigned char base = 10);
explicit String(unsigned long long, unsigned char base = 10);
~String(void);
// memory management
@ -122,6 +124,8 @@ class String {
unsigned char concat(unsigned long num);
unsigned char concat(float num);
unsigned char concat(double num);
unsigned char concat(long long num);
unsigned char concat(unsigned long long num);
unsigned char concat(const __FlashStringHelper * str);
// if there's not enough memory for the concatenated value, the string
@ -166,6 +170,14 @@ class String {
concat(num);
return (*this);
}
String & operator +=(long long num) {
concat(num);
return (*this);
}
String & operator +=(unsigned long long num) {
concat(num);
return (*this);
}
String & operator += (const __FlashStringHelper *str){
concat(str);
return (*this);
@ -182,6 +194,8 @@ class String {
friend StringSumHelper & operator +(const StringSumHelper &lhs, float num);
friend StringSumHelper & operator +(const StringSumHelper &lhs, double num);
friend StringSumHelper & operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs);
friend StringSumHelper & operator +(const StringSumHelper &lhs, long long num);
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long long num);
// comparison (only works w/ Strings and "strings")
operator StringIfHelperType() const {
@ -373,6 +387,12 @@ class StringSumHelper: public String {
StringSumHelper(double num) :
String(num) {
}
StringSumHelper(long long num) :
String(num) {
}
StringSumHelper(unsigned long long num) :
String(num) {
}
};
extern const String emptyString;

View File

@ -13,43 +13,16 @@
// limitations under the License.
#include "esp32-hal-adc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_attr.h"
#include "soc/rtc_cntl_reg.h"
#include "driver/adc.h"
#include "esp_system.h"
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp_adc_cal.h"
#if SOC_DAC_SUPPORTED //ESP32, ESP32S2
#include "soc/dac_channel.h"
#include "soc/sens_reg.h"
#include "soc/rtc_io_reg.h"
#include "esp32/rom/ets_sys.h"
#include "esp_intr_alloc.h"
#include "soc/dac_channel.h"
#endif
#define DEFAULT_VREF 1100
static esp_adc_cal_characteristics_t *__analogCharacteristics[2] = {NULL, NULL};
static uint16_t __analogVRef = 0;
static uint8_t __analogVRefPin = 0;
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/ets_sys.h"
#include "soc/sens_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/dac_channel.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/ets_sys.h"
#include "soc/sens_reg.h"
#include "soc/rtc_io_reg.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/ets_sys.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
#else // ESP32 Before IDF 4.0
#include "rom/ets_sys.h"
#include "esp_intr.h"
#endif
static uint8_t __analogAttenuation = 3;//11db
static uint8_t __analogWidth = ADC_WIDTH_MAX - 1; //3 for ESP32/ESP32C3; 4 for ESP32S2
@ -57,6 +30,11 @@ static uint8_t __analogReturnedWidth = SOC_ADC_MAX_BITWIDTH; //12 for ESP32/ESP3
static uint8_t __analogClockDiv = 1;
static adc_attenuation_t __pin_attenuation[SOC_GPIO_PIN_COUNT];
static uint16_t __analogVRef = 0;
#if CONFIG_IDF_TARGET_ESP32
static uint8_t __analogVRefPin = 0;
#endif
static inline uint16_t mapResolution(uint16_t value)
{
uint8_t from = __analogWidth + 9;
@ -117,8 +95,8 @@ void __analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation)
if(channel < 0 || attenuation > 3){
return ;
}
if(channel > 9){
adc2_config_channel_atten(channel - 10, attenuation);
if(channel > (SOC_ADC_MAX_CHANNEL_NUM - 1)){
adc2_config_channel_atten(channel - SOC_ADC_MAX_CHANNEL_NUM, attenuation);
} else {
adc1_config_channel_atten(channel, attenuation);
}
@ -181,8 +159,8 @@ uint16_t __analogRead(uint8_t pin)
return value;
}
__adcAttachPin(pin);
if(channel > 9){
channel -= 10;
if(channel > (SOC_ADC_MAX_CHANNEL_NUM - 1)){
channel -= SOC_ADC_MAX_CHANNEL_NUM;
r = adc2_get_raw( channel, __analogWidth, &value);
if ( r == ESP_OK ) {
return mapResolution(value);
@ -206,7 +184,7 @@ uint32_t __analogReadMilliVolts(uint8_t pin){
log_e("Pin %u is not ADC pin!", pin);
return 0;
}
#if CONFIG_IDF_TARGET_ESP32
if(!__analogVRef){
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) {
log_d("eFuse Two Point: Supported");
@ -218,6 +196,8 @@ uint32_t __analogReadMilliVolts(uint8_t pin){
}
if(!__analogVRef){
__analogVRef = DEFAULT_VREF;
#if CONFIG_IDF_TARGET_ESP32
if(__analogVRefPin){
esp_adc_cal_characteristics_t chars;
if(adc_vref_to_gpio(ADC_UNIT_2, __analogVRefPin) == ESP_OK){
@ -227,42 +207,44 @@ uint32_t __analogReadMilliVolts(uint8_t pin){
log_d("Vref to GPIO%u: %u", __analogVRefPin, __analogVRef);
}
}
#endif
}
}
uint8_t unit = 1;
if(channel > 9){
if(channel > (SOC_ADC_MAX_CHANNEL_NUM - 1)){
unit = 2;
}
uint16_t adc_reading = __analogRead(pin);
if(__analogCharacteristics[unit - 1] == NULL){
__analogCharacteristics[unit - 1] = calloc(1, sizeof(esp_adc_cal_characteristics_t));
if(__analogCharacteristics[unit - 1] == NULL){
return 0;
}
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, __analogAttenuation, __analogWidth, __analogVRef, __analogCharacteristics[unit - 1]);
uint8_t atten = __analogAttenuation;
if (__pin_attenuation[pin] != ADC_ATTENDB_MAX){
atten = __pin_attenuation[pin];
}
esp_adc_cal_characteristics_t chars = {};
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, __analogWidth, __analogVRef, &chars);
static bool print_chars_info = true;
if(print_chars_info)
{
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
log_i("ADC%u: Characterized using Two Point Value: %u\n", unit, __analogCharacteristics[unit - 1]->vref);
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
log_i("ADC%u: Characterized using eFuse Vref: %u\n", unit, __analogCharacteristics[unit - 1]->vref);
} else if(__analogVRef != DEFAULT_VREF){
log_i("ADC%u: Characterized using Vref to GPIO%u: %u\n", unit, __analogVRefPin, __analogCharacteristics[unit - 1]->vref);
} else {
log_i("ADC%u: Characterized using Default Vref: %u\n", unit, __analogCharacteristics[unit - 1]->vref);
log_i("ADC%u: Characterized using Two Point Value: %u\n", unit, chars.vref);
}
else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
log_i("ADC%u: Characterized using eFuse Vref: %u\n", unit, chars.vref);
}
#if CONFIG_IDF_TARGET_ESP32
else if(__analogVRef != DEFAULT_VREF){
log_i("ADC%u: Characterized using Vref to GPIO%u: %u\n", unit, __analogVRefPin, chars.vref);
}
#endif
else {
log_i("ADC%u: Characterized using Default Vref: %u\n", unit, chars.vref);
}
print_chars_info = false;
}
return esp_adc_cal_raw_to_voltage(adc_reading, __analogCharacteristics[unit - 1]);
#else
uint16_t adc_reading = __analogRead(pin);
uint16_t max_reading = 8191;
uint16_t max_mv = 1100;
switch(__analogAttenuation){
case 3: max_mv = 3900; break;
case 2: max_mv = 2200; break;
case 1: max_mv = 1500; break;
default: break;
}
return (adc_reading * max_mv) / max_reading;
#endif
return esp_adc_cal_raw_to_voltage((uint32_t)adc_reading, &chars);
}
#if CONFIG_IDF_TARGET_ESP32
@ -297,4 +279,3 @@ extern void analogSetVRefPin(uint8_t pin) __attribute__ ((weak, alias("__analogS
extern void analogSetWidth(uint8_t bits) __attribute__ ((weak, alias("__analogSetWidth")));
extern int hallRead() __attribute__ ((weak, alias("__hallRead")));
#endif

View File

@ -107,7 +107,7 @@ bool addApbChangeCallback(void * arg, apb_change_cb_t cb){
// look for duplicate callbacks
while( (r != NULL ) && !((r->cb == cb) && ( r->arg == arg))) r = r->next;
if (r) {
log_e("duplicate func=%08X arg=%08X",c->cb,c->arg);
log_e("duplicate func=%8p arg=%8p",c->cb,c->arg);
free(c);
xSemaphoreGive(apb_change_lock);
return false;
@ -129,7 +129,7 @@ bool removeApbChangeCallback(void * arg, apb_change_cb_t cb){
// look for matching callback
while( (r != NULL ) && !((r->cb == cb) && ( r->arg == arg))) r = r->next;
if ( r == NULL ) {
log_e("not found func=%08X arg=%08X",cb,arg);
log_e("not found func=%8p arg=%8p",cb,arg);
xSemaphoreGive(apb_change_lock);
return false;
}

View File

@ -91,30 +91,34 @@ static InterruptHandle_t __pinInterruptHandlers[SOC_GPIO_PIN_COUNT] = {0,};
extern void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode)
{
if (!GPIO_IS_VALID_GPIO(pin)) {
if (!GPIO_IS_VALID_GPIO(pin)) {
log_e("Invalid pin selected");
return;
}
gpio_config_t conf = {
.pin_bit_mask = (1ULL<<pin), /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */
.mode = GPIO_MODE_DISABLE, /*!< GPIO mode: set input/output mode */
.pull_up_en = GPIO_PULLUP_DISABLE, /*!< GPIO pull-up */
.pull_down_en = GPIO_PULLDOWN_DISABLE, /*!< GPIO pull-down */
.intr_type = GPIO_INTR_DISABLE /*!< GPIO interrupt type */
};
if (mode < 0x20) {//io
conf.mode = mode & (INPUT | OUTPUT);
if (mode & OPEN_DRAIN) {
conf.mode |= GPIO_MODE_DEF_OD;
}
if (mode & PULLUP) {
conf.pull_up_en = GPIO_PULLUP_ENABLE;
}
if (mode & PULLDOWN) {
conf.pull_down_en = GPIO_PULLDOWN_ENABLE;
}
}
if(gpio_config(&conf) != ESP_OK)
return;
}
gpio_hal_context_t gpiohal;
gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0);
gpio_config_t conf = {
.pin_bit_mask = (1ULL<<pin), /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */
.mode = GPIO_MODE_DISABLE, /*!< GPIO mode: set input/output mode */
.pull_up_en = GPIO_PULLUP_DISABLE, /*!< GPIO pull-up */
.pull_down_en = GPIO_PULLDOWN_DISABLE, /*!< GPIO pull-down */
.intr_type = gpiohal.dev->pin[pin].int_type /*!< GPIO interrupt type - previously set */
};
if (mode < 0x20) {//io
conf.mode = mode & (INPUT | OUTPUT);
if (mode & OPEN_DRAIN) {
conf.mode |= GPIO_MODE_DEF_OD;
}
if (mode & PULLUP) {
conf.pull_up_en = GPIO_PULLUP_ENABLE;
}
if (mode & PULLDOWN) {
conf.pull_down_en = GPIO_PULLDOWN_ENABLE;
}
}
if(gpio_config(&conf) != ESP_OK)
{
log_e("GPIO config failed");
return;

View File

@ -42,20 +42,15 @@ extern "C" {
//GPIO FUNCTIONS
#define INPUT 0x01
#define OUTPUT 0x02
// Changed OUTPUT from 0x02 to behave the same as Arduino pinMode(pin,OUTPUT)
// where you can read the state of pin even when it is set as OUTPUT
#define OUTPUT 0x03
#define PULLUP 0x04
#define INPUT_PULLUP 0x05
#define PULLDOWN 0x08
#define INPUT_PULLDOWN 0x09
#define OPEN_DRAIN 0x10
#define OUTPUT_OPEN_DRAIN 0x12
#define SPECIAL 0xF0
#define FUNCTION_1 0x00
#define FUNCTION_2 0x20
#define FUNCTION_3 0x40
#define FUNCTION_4 0x60
#define FUNCTION_5 0x80
#define FUNCTION_6 0xA0
#define ANALOG 0xC0
//Interrupt Modes

View File

@ -695,7 +695,6 @@ static void i2c_slave_isr_handler(void* arg)
uint32_t activeInt = i2c_ll_get_intsts_mask(i2c->dev);
i2c_ll_clr_intsts_mask(i2c->dev, activeInt);
uint8_t rx_fifo_len = i2c_ll_get_rxfifo_cnt(i2c->dev);
uint8_t tx_fifo_len = SOC_I2C_FIFO_LEN - i2c_ll_get_txfifo_len(i2c->dev);
bool slave_rw = i2c_ll_slave_rw(i2c->dev);
if(activeInt & I2C_RXFIFO_WM_INT_ENA){ // RX FiFo Full
@ -719,10 +718,12 @@ static void i2c_slave_isr_handler(void* arg)
}
if(slave_rw){ // READ
#if CONFIG_IDF_TARGET_ESP32
//SEND TX Event
i2c_slave_queue_event_t event;
event.event = I2C_SLAVE_EVT_TX;
pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event);
if(i2c->dev->status_reg.scl_main_state_last == 6){
//SEND TX Event
i2c_slave_queue_event_t event;
event.event = I2C_SLAVE_EVT_TX;
pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event);
}
#else
//reset TX data
i2c_ll_txfifo_rst(i2c->dev);

View File

@ -317,6 +317,8 @@ esp_err_t i2cSetClock(uint8_t i2c_num, uint32_t frequency){
hal.dev = I2C_LL_GET_HW(i2c_num);
i2c_hal_set_bus_timing(&(hal), frequency, src_clk);
bus[i2c_num].frequency = frequency;
//Clock Stretching Timeout: 20b:esp32, 5b:esp32-c3, 24b:esp32-s2
i2c_set_timeout((i2c_port_t)i2c_num, I2C_LL_MAX_TIMEOUT);
}
end:

View File

@ -54,7 +54,7 @@
uint8_t channels_resolution[LEDC_CHANNELS] = {0};
double ledcSetup(uint8_t chan, double freq, uint8_t bit_num)
uint32_t ledcSetup(uint8_t chan, uint32_t freq, uint8_t bit_num)
{
if(chan >= LEDC_CHANNELS || bit_num > LEDC_MAX_BIT_WIDTH){
log_e("No more LEDC channels available! (maximum %u) or bit width too big (maximum %u)", LEDC_CHANNELS, LEDC_MAX_BIT_WIDTH);
@ -106,7 +106,7 @@ uint32_t ledcRead(uint8_t chan)
return ledc_get_duty(group,channel);
}
double ledcReadFreq(uint8_t chan)
uint32_t ledcReadFreq(uint8_t chan)
{
if(!ledcRead(chan)){
return 0;
@ -115,7 +115,7 @@ double ledcReadFreq(uint8_t chan)
return ledc_get_freq(group,timer);
}
double ledcWriteTone(uint8_t chan, double freq)
uint32_t ledcWriteTone(uint8_t chan, uint32_t freq)
{
if(chan >= LEDC_CHANNELS){
return 0;
@ -142,12 +142,12 @@ double ledcWriteTone(uint8_t chan, double freq)
}
channels_resolution[chan] = 10;
double res_freq = ledc_get_freq(group,timer);
uint32_t res_freq = ledc_get_freq(group,timer);
ledcWrite(chan, 0x1FF);
return res_freq;
}
double ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){
uint32_t ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){
const uint16_t noteFrequencyBase[12] = {
// C C# D Eb E F F# G G# A Bb B
4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902
@ -156,7 +156,7 @@ double ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){
if(octave > 8 || note >= NOTE_MAX){
return 0;
}
double noteFreq = (double)noteFrequencyBase[note] / (double)(1 << (8-octave));
uint32_t noteFreq = (uint32_t)noteFrequencyBase[note] / (uint32_t)(1 << (8-octave));
return ledcWriteTone(chan, noteFreq);
}
@ -184,7 +184,7 @@ void ledcDetachPin(uint8_t pin)
pinMatrixOutDetach(pin, false, false);
}
double ledcChangeFrequency(uint8_t chan, double freq, uint8_t bit_num)
uint32_t ledcChangeFrequency(uint8_t chan, uint32_t freq, uint8_t bit_num)
{
if(chan >= LEDC_CHANNELS || bit_num > LEDC_MAX_BIT_WIDTH){
log_e("LEDC channel not available! (maximum %u) or bit width too big (maximum %u)", LEDC_CHANNELS, LEDC_MAX_BIT_WIDTH);

View File

@ -27,15 +27,15 @@ typedef enum {
} note_t;
//channel 0-15 resolution 1-16bits freq limits depend on resolution
double ledcSetup(uint8_t channel, double freq, uint8_t resolution_bits);
uint32_t ledcSetup(uint8_t channel, uint32_t freq, uint8_t resolution_bits);
void ledcWrite(uint8_t channel, uint32_t duty);
double ledcWriteTone(uint8_t channel, double freq);
double ledcWriteNote(uint8_t channel, note_t note, uint8_t octave);
uint32_t ledcWriteTone(uint8_t channel, uint32_t freq);
uint32_t ledcWriteNote(uint8_t channel, note_t note, uint8_t octave);
uint32_t ledcRead(uint8_t channel);
double ledcReadFreq(uint8_t channel);
uint32_t ledcReadFreq(uint8_t channel);
void ledcAttachPin(uint8_t pin, uint8_t channel);
void ledcDetachPin(uint8_t pin);
double ledcChangeFrequency(uint8_t channel, double freq, uint8_t resolution_bits);
uint32_t ledcChangeFrequency(uint8_t channel, uint32_t freq, uint8_t resolution_bits);
#ifdef __cplusplus

View File

@ -206,16 +206,16 @@ void log_print_buf(const uint8_t *b, size_t len);
#undef ESP_EARLY_LOGD
#undef ESP_EARLY_LOGV
#define ESP_LOGE(tag, ...) log_e(__VA_ARGS__)
#define ESP_LOGW(tag, ...) log_w(__VA_ARGS__)
#define ESP_LOGI(tag, ...) log_i(__VA_ARGS__)
#define ESP_LOGD(tag, ...) log_d(__VA_ARGS__)
#define ESP_LOGV(tag, ...) log_v(__VA_ARGS__)
#define ESP_EARLY_LOGE(tag, ...) isr_log_e(__VA_ARGS__)
#define ESP_EARLY_LOGW(tag, ...) isr_log_w(__VA_ARGS__)
#define ESP_EARLY_LOGI(tag, ...) isr_log_i(__VA_ARGS__)
#define ESP_EARLY_LOGD(tag, ...) isr_log_d(__VA_ARGS__)
#define ESP_EARLY_LOGV(tag, ...) isr_log_v(__VA_ARGS__)
#define ESP_LOGE(tag, format, ...) log_e("[%s] " format, tag, ##__VA_ARGS__)
#define ESP_LOGW(tag, format, ...) log_w("[%s] " format, tag, ##__VA_ARGS__)
#define ESP_LOGI(tag, format, ...) log_i("[%s] " format, tag, ##__VA_ARGS__)
#define ESP_LOGD(tag, format, ...) log_d("[%s] " format, tag, ##__VA_ARGS__)
#define ESP_LOGV(tag, format, ...) log_v("[%s] " format, tag, ##__VA_ARGS__)
#define ESP_EARLY_LOGE(tag, format, ...) isr_log_e("[%s] " format, tag, ##__VA_ARGS__)
#define ESP_EARLY_LOGW(tag, format, ...) isr_log_w("[%s] " format, tag, ##__VA_ARGS__)
#define ESP_EARLY_LOGI(tag, format, ...) isr_log_i("[%s] " format, tag, ##__VA_ARGS__)
#define ESP_EARLY_LOGD(tag, format, ...) isr_log_d("[%s] " format, tag, ##__VA_ARGS__)
#define ESP_EARLY_LOGV(tag, format, ...) isr_log_v("[%s] " format, tag, ##__VA_ARGS__)
#endif
#endif

View File

@ -200,9 +200,14 @@ void initVariant() {}
void init() __attribute__((weak));
void init() {}
#ifdef CONFIG_APP_ROLLBACK_ENABLE
bool verifyOta() __attribute__((weak));
bool verifyOta() { return true; }
bool verifyRollbackLater() __attribute__((weak));
bool verifyRollbackLater() { return false; }
#endif
#ifdef CONFIG_BT_ENABLED
//overwritten in esp32-hal-bt.c
bool btInUse() __attribute__((weak));
@ -212,15 +217,17 @@ bool btInUse(){ return false; }
void initArduino()
{
#ifdef CONFIG_APP_ROLLBACK_ENABLE
const esp_partition_t *running = esp_ota_get_running_partition();
esp_ota_img_states_t ota_state;
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
if (verifyOta()) {
esp_ota_mark_app_valid_cancel_rollback();
} else {
log_e("OTA verification failed! Start rollback to the previous version ...");
esp_ota_mark_app_invalid_rollback_and_reboot();
if(!verifyRollbackLater()){
const esp_partition_t *running = esp_ota_get_running_partition();
esp_ota_img_states_t ota_state;
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
if (verifyOta()) {
esp_ota_mark_app_valid_cancel_rollback();
} else {
log_e("OTA verification failed! Start rollback to the previous version ...");
esp_ota_mark_app_invalid_rollback_and_reboot();
}
}
}
}

View File

@ -32,13 +32,6 @@ typedef union {
#define NUM_OF_TIMERS SOC_TIMER_GROUP_TOTAL_TIMERS
typedef struct {
int timer_group;
int timer_idx;
int alarm_interval;
bool auto_reload;
} timer_info_t;
typedef struct hw_timer_s
{
uint8_t group;
@ -47,7 +40,7 @@ typedef struct hw_timer_s
// Works for all chips
static hw_timer_t timer_dev[4] = {
{0,0}, {1,0}, {1,0}, {1,1}
{0,0}, {1,0}, {0,1}, {1,1}
};
// NOTE: (in IDF 5.0 there wont be need to know groups/numbers
@ -194,7 +187,7 @@ static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb
hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
if(num >= NUM_OF_TIMERS)
{
log_e("Timer dont have that timer number.");
log_e("Timer number %u exceeds available number of Timers.", num);
return NULL;
}
@ -220,24 +213,23 @@ void timerEnd(hw_timer_t *timer){
timer_deinit(timer->group, timer->num);
}
bool IRAM_ATTR timerFnWrapper(void *arg){
void (*fn)(void) = arg;
fn();
// some additional logic or handling may be required here to approriately yield or not
return false;
}
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
if(edge){
log_w("EDGE timer interrupt is not supported! Setting to LEVEL...");
edge = false;
}
timer_enable_intr(timer->group, timer->num);
timer_info_t *timer_info = calloc(1, sizeof(timer_info_t));
timer_info->timer_group = timer->group;
timer_info->timer_idx = timer->num;
timer_info->auto_reload = timerGetAutoReload(timer);
timer_info->alarm_interval = timerAlarmRead(timer);
timer_isr_callback_add(timer->group, timer->num, (timer_isr_t)fn, timer_info, 0);
timer_isr_callback_add(timer->group, timer->num, timerFnWrapper, fn, 0);
}
void timerDetachInterrupt(hw_timer_t *timer){
timerAttachInterrupt(timer, NULL, false);
timer_isr_callback_remove(timer->group, timer->num);
}
uint64_t timerReadMicros(hw_timer_t *timer){

View File

@ -646,8 +646,9 @@ static void usb_device_task(void *param) {
/*
* PUBLIC API
* */
static const char *tinyusb_interface_names[USB_INTERFACE_MAX] = {"MSC", "DFU", "HID", "VENDOR", "CDC", "MIDI", "CUSTOM"};
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
const char *tinyusb_interface_names[USB_INTERFACE_MAX] = {"MSC", "DFU", "HID", "VENDOR", "CDC", "MIDI", "CUSTOM"};
#endif
static bool tinyusb_is_initialized = false;
esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descriptor_len, tinyusb_descriptor_cb_t cb)

View File

@ -119,11 +119,6 @@ static void __touchInit()
if (err != ESP_OK) {
goto err;
}
// Initial no Threshold and setup
for (int i = 0; i < SOC_TOUCH_SENSOR_NUM; i++) {
__touchInterruptHandlers[i].fn = NULL;
touch_pad_config(i, SOC_TOUCH_PAD_THRESHOLD_MAX); // returns ESP_OK
}
// keep ISR activated - it can run all together (ISR + touchRead())
err = touch_pad_isr_register(__touchISR, NULL);
if (err != ESP_OK) {
@ -148,18 +143,7 @@ static void __touchInit()
// Touch Sensor Timer initiated
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); // returns ESP_OK
touch_pad_fsm_start(); // returns ESP_OK
// Initial no Threshold and setup - TOUCH0 is internal denoise channel
for (int i = 1; i < SOC_TOUCH_SENSOR_NUM; i++) {
__touchInterruptHandlers[i].fn = NULL;
touch_pad_config(i); // returns ESP_OK
}
// keep ISR activated - it can run all together (ISR + touchRead())
err = touch_pad_isr_register(__touchISR, NULL, TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE);
if (err != ESP_OK) {
goto err;
}
touch_pad_intr_enable(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE); // returns ESP_OK
//ISR setup moved to __touchChannelInit
#endif
initialized = true;
@ -170,13 +154,43 @@ err:
return;
}
static void __touchChannelInit(int pad)
{
static bool channels_initialized[SOC_TOUCH_SENSOR_NUM] = { false };
if(channels_initialized[pad]){
return;
}
#if SOC_TOUCH_VERSION_1 // ESP32
// Initial no Threshold and setup
__touchInterruptHandlers[pad].fn = NULL;
touch_pad_config(pad, SOC_TOUCH_PAD_THRESHOLD_MAX); // returns ESP_OK
#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3
// Initial no Threshold and setup
__touchInterruptHandlers[pad].fn = NULL;
touch_pad_config(pad); // returns ESP_OK
// keep ISR activated - it can run all together (ISR + touchRead())
esp_err_t err = touch_pad_isr_register(__touchISR, NULL, TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE);
if (err != ESP_OK) {
log_e(" Touch sensor initialization error.");
return;
}
touch_pad_intr_enable(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE); // returns ESP_OK
#endif
channels_initialized[pad] = true;
delay(20); //delay needed before reading from touch channel after config
}
static touch_value_t __touchRead(uint8_t pin)
{
int8_t pad = digitalPinToTouchChannel(pin);
if(pad < 0){
return 0;
}
__touchInit();
__touchChannelInit(pad);
touch_value_t touch_value;
touch_pad_read_raw_data(pad, &touch_value);
@ -198,6 +212,9 @@ static void __touchConfigInterrupt(uint8_t pin, void (*userFunc)(void), void *Ar
} else {
// attach ISR User Call
__touchInit();
#if SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3
__touchChannelInit(pad);
#endif
__touchInterruptHandlers[pad].fn = userFunc;
__touchInterruptHandlers[pad].callWithArgs = callWithArgs;
__touchInterruptHandlers[pad].arg = Args;

View File

@ -115,7 +115,7 @@ void uartSetPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t
}
UART_MUTEX_LOCK();
// IDF uart_set_pin() will issue necessary Error Message and take care of all GPIO Number validation.
uart_set_pin(uart->num, txPin, rxPin, ctsPin, rtsPin);
uart_set_pin(uart->num, txPin, rxPin, rtsPin, ctsPin);
UART_MUTEX_UNLOCK();
}
@ -538,8 +538,6 @@ void uartStartDetectBaudrate(uart_t *uart) {
return;
}
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
#ifdef CONFIG_IDF_TARGET_ESP32C3
// ESP32-C3 requires further testing
@ -555,6 +553,7 @@ void uartStartDetectBaudrate(uart_t *uart) {
//hw->conf0.autobaud_en = 1;
#elif CONFIG_IDF_TARGET_ESP32S3
#else
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
hw->auto_baud.glitch_filt = 0x08;
hw->auto_baud.en = 0;
hw->auto_baud.en = 1;
@ -571,7 +570,6 @@ uartDetectBaudrate(uart_t *uart)
#ifndef CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3 requires further testing - Baud rate detection returns wrong values
static bool uartStateDetectingBaudrate = false;
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
if(!uartStateDetectingBaudrate) {
uartStartDetectBaudrate(uart);
@ -592,6 +590,7 @@ uartDetectBaudrate(uart_t *uart)
//hw->conf0.autobaud_en = 0;
#elif CONFIG_IDF_TARGET_ESP32S3
#else
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
hw->auto_baud.en = 0;
#endif
uartStateDetectingBaudrate = false; // Initialize for the next round

View File

@ -23,7 +23,7 @@ extern "C" {
/** Minor version number (x.X.x) */
#define ESP_ARDUINO_VERSION_MINOR 0
/** Patch version number (x.x.X) */
#define ESP_ARDUINO_VERSION_PATCH 3
#define ESP_ARDUINO_VERSION_PATCH 4
/**
* Macro to convert ARDUINO version number into an integer

View File

@ -40,6 +40,7 @@ static int base64_decode_block_signed(const int8_t* code_in, const int length_in
fragment = (int8_t)base64_decode_value_signed(*codechar++);
} while (fragment < 0);
*plainchar = (fragment & 0x03f) << 2;
// fall through
case step_b:
do {
if (codechar == code_in+length_in){
@ -51,6 +52,7 @@ static int base64_decode_block_signed(const int8_t* code_in, const int length_in
} while (fragment < 0);
*plainchar++ |= (fragment & 0x030) >> 4;
*plainchar = (fragment & 0x00f) << 4;
// fall through
case step_c:
do {
if (codechar == code_in+length_in){
@ -62,6 +64,7 @@ static int base64_decode_block_signed(const int8_t* code_in, const int length_in
} while (fragment < 0);
*plainchar++ |= (fragment & 0x03c) >> 2;
*plainchar = (fragment & 0x003) << 6;
// fall through
case step_d:
do {
if (codechar == code_in+length_in){

View File

@ -44,6 +44,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
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;
@ -54,6 +55,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
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;

View File

@ -67,6 +67,31 @@ char* ltoa(long value, char* result, int base) {
return result;
}
char* lltoa (long long val, char* result, int base) {
if(base < 2 || base > 16) {
*result = 0;
return result;
}
char* out = result;
long long quotient = val > 0 ? val : -val;
do {
const long long tmp = quotient / base;
*out = "0123456789abcdef"[quotient - (tmp * base)];
++out;
quotient = tmp;
} while(quotient);
// Apply negative sign
if(val < 0)
*out++ = '-';
reverse(result, out);
*out = 0;
return result;
}
char* ultoa(unsigned long value, char* result, int base) {
if(base < 2 || base > 16) {
*result = 0;
@ -88,6 +113,27 @@ char* ultoa(unsigned long value, char* result, int base) {
return result;
}
char* ulltoa (unsigned long long val, char* result, int base) {
if(base < 2 || base > 16) {
*result = 0;
return result;
}
char* out = result;
unsigned long long quotient = val;
do {
const unsigned long long tmp = quotient / base;
*out = "0123456789abcdef"[quotient - (tmp * base)];
++out;
quotient = tmp;
} while(quotient);
reverse(result, out);
*out = 0;
return result;
}
char * dtostrf(double number, signed int width, unsigned int prec, char *s) {
bool negative = false;
@ -160,3 +206,5 @@ char * dtostrf(double number, signed int width, unsigned int prec, char *s) {
*out = 0;
return s;
}

View File

@ -35,10 +35,14 @@ char* itoa (int val, char *s, int radix);
char* ltoa (long val, char *s, int radix);
char* lltoa (long long val, char* s, int radix);
char* utoa (unsigned int val, char *s, int radix);
char* ultoa (unsigned long val, char *s, int radix);
char* ulltoa (unsigned long long val, char* s, int radix);
char* dtostrf (double val, signed int width, unsigned int prec, char *s);
#ifdef __cplusplus

View File

@ -71,48 +71,70 @@ Installing using PlatformIO
:width: 200
:figclass: align-center
PlatformIO is one of most popular embedded development tool. Currently, it supports Arduino ESP32 and ESP-IDF from Espressif (other platforms are also supported).
PlatformIO is a professional collaborative platform for embedded development. It has out-of-the-box support for ESP32 SoCs and allows working with Arduino ESP32 as well as ESP-IDF from Espressif without changing your development environment. PlatformIO includes lots of instruments for the most common development tasks such as debugging, unit testing, and static code analysis.
To install PIO, you can follow this Getting Started, provided by PIO at `docs.platformio.org`_.
A detailed overview of the PlatformIO ecosystem and its philosophy can be found in `the official documentation <https://docs.platformio.org/en/latest/core/index.html>`_.
To test the latest Arduino ESP32, you need to change your project *platform.ini* accordingly.
PlatformIO can be used in two flavors:
- Start a new project and select one of the available board. You can change after by changing the *platform.ini* file.
- `PlatformIO IDE <https://platformio.org/platformio-ide>`_ is a toolset for embedded C/C++ development available on Windows, macOS and Linux platforms
- `PlatformIO Core (CLI) <https://docs.platformio.org/en/latest/core/index.html>`_ is a command-line tool that consists of a multi-platform build system, platform and library managers and other integration components. It can be used with a variety of code development environments and allows integration with cloud platforms and web services
To install PlatformIO, you can follow this Getting Started, provided at `docs.platformio.org`_.
Using the stable code
*********************
.. note::
A detailed overview of supported development boards, examples and frameworks can be found on `the official Espressif32 dev-platform page <https://registry.platformio.org/platforms/platformio/espressif32>`_ in the PlatformIO Registry.
The most reliable and easiest way to get started is to use the latest stable version of the ESP32 development platform that passed all tests/verifications and can be used in production.
Create a new project and select one of the available boards. You can change after by changing the `platformio.ini <https://docs.platformio.org/en/latest/projectconf/index.html>`_ file.
- For ESP32
.. code-block:: bash
[env:arduino-esp32]
platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
platform_packages =
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32#master
- For ESP32-S2 (ESP32-S2-Saola-1 board)
.. code-block:: bash
[env:arduino-esp32s2]
platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream
[env:esp32-s2-saola-1]
platform = espressif32
board = esp32-s2-saola-1
framework = arduino
platform_packages =
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32#master
- For ESP32-C3 (ESP32-S3-DevKitM-1 board)
- For ESP32-C3 (ESP32-C3-DevKitM-1 board)
.. code-block:: bash
[env:arduino-esp32c3]
platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream
[env:esp32-c3-devkitm-1]
platform = espressif32
board = esp32-c3-devkitm-1
framework = arduino
How to update to the latest code
********************************
To test the latest Arduino ESP32, you need to change your project *platformio.ini* accordingly.
The following configuration uses the upstream version of the Espressif development platform and the latest Arduino core directly from the Espressif GitHub repository:
.. code-block:: bash
[env:esp32-c3-devkitm-1]
platform = https://github.com/platformio/platform-espressif32.git
board = esp32-c3-devkitm-1
framework = arduino
platform_packages =
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32#master
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32#master
Now you're able to use the latest Arduino ESP32 support directly from Espressif GitHub repository.
To get more information about PlatformIO, see the following links:

View File

@ -0,0 +1,188 @@
###############
Partition Table
###############
Introduction
------------
Partition table is used to define the flash memory organization and the different kind of data will be stored on each partition.
You can use one of the available partition table scheme or create your own. You can see all the different schemes on the `tools/partitions <https://github.com/espressif/arduino-esp32/tree/master/tools/partitions>`_ folder or by the Arduino IDE tools menu `Tools -> Partition Scheme`.
The partition table is created by a .CSV (Comma-separeted Values) file with the following structure:
.. code-block::
# ESP-IDF Partition Table
# Name, Type, SubType, Offset, Size, Flags
Where:
1. **Name**
Is the partition name and must be a unique name. This name is not relevant for the system and the size must be at maximum of 16-chars (no special chars).
2. **Type**
This is the type of the partition. This value can be ``data`` or ``app``.
* ``app`` type is used to define the partition that will store the application.
* ``data`` type can be used to define the partition that stores general data, not the application.
3. **SubType**
The SubType defines the usage of the ``app`` and ``data`` partitions.
**data**
``ota``
The ota subtype is used to store the OTA information. This partition is used only when the OTA is used to select the initialization partition, otherwise no need to add it to your custom partition table.
The size of this partition should be a fixed size of 8kB (0x2000 bytes).
``nvs``
The nvs partition subtype is used to define the partition to store general data, like the WiFi data, device PHY calibration data and any other data to be stored on the non-volatile memory.
This kind of partition is suitable for small custom configuration data, cloud certificates, etc. Another usage for the NVS is to store sensitive data, since the NVS supports encryption.
It is highly recommended to add at least one nvs partition, labeled with the name nvs, in your custom partition tables with size of at least 12kB (0x3000 bytes). If needed, you can increase the size of the nvs partition.
The recommended size for this partition is from 12kb to 64kb. Although larger NVS partitions can be defined, we recommend using FAT or SPIFFS filesystem for storage of larger amounts of data.
``coredump``
The coredump partition subtype is used to store the core dump on the flash. The core dump is used to analyze critical errors like crash and panic.
This function must be enabled in the project configuration menu and set the data destination to flash.
The recommended size for this partition is 64kB (0x10000).
``nvs_keys``
The nvs_keys partition subtype is used to store the keys when the NVS encryption is used.
The size for this partition is 4kB (0x1000).
``fat``
The fat partition subtype defines the FAT filesystem usage, and it is suitable for larger data and if this data is often updated and changed. The FAT FS can be used with wear leveling feature to increase the erase/modification cycles per memory sector and encryption for sensitive data storage, like cloud certificates or any other data that may be protected.
To use FAT FS with wear leveling see the example.
``spiffs``
The spiffs partition subtype defines the SPI flash filesystem usage, and it is also suitable for larger files and it also performs the wear leveling and file system consistency check.
The SPIFFS do not support flash encryption.
**app**
``factory``
The factory partition subtype is the default application. The bootloader will set this partition as the default application initialization if no OTA partition is found, or the OTA partitions are empty.
If the OTA partition is used, the ota_0 can be used as the default application and the factory can be removed from the partition table to save memory space.
``ota_0`` to ``ota_15``
The ota_x partition subtype is used for the Over-the air update. The OTA feature requires at least two ota_x partition (usually ota_0 and ota_1) and it also requires the ota partition to keep the OTA information data.
Up to 16 OTA partitions can be defined but only two are needed for basic OTA feature.
``test``
The test partition subtype is used for factory test procedures.
4. **Offset**
The offset defines the partition start address. The offset is defined by the sum of the offset and the size of the earlier partition.
.. note::
Offset must be multiple of 4kB (0x1000) and for app partitions it must be aligned by 64kB (0x10000).
If left blank, the offset will be automatically calculated based on the end of the previous partition, including any necessary alignment, however, the offset for the first partition must be always set as **0x9000** and for the first application partition **0x10000**.
5. **Size**
Size defines the amount of memory to be allocated on the partition. The size can be formatted as decimal, hex numbers (0x prefix), or using unit prefix K (kilo) or M (mega) i.e: 4096 = 4K = 0x1000.
6. **Flags**
The last column in the CSV file is the flags and it is currently used to define if the partition will be encrypted by the flash encryption feature.
For example, **the most common partition** is the ``default_8MB.csv`` (see `tools/partitions <https://github.com/espressif/arduino-esp32/tree/master/tools/partitions>`_ folder for some examples):
.. code-block::
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x330000,
app1, app, ota_1, 0x340000,0x330000,
spiffs, data, spiffs, 0x670000,0x190000,
Using a Custom Partition Scheme
-------------------------------
To create your own partition table, you can create the ``partitions.csv`` file **in the same folder you created your sketch**. The build system will automatically pick the partition table file and use it instead of the predefined ones.
Here is an example you can use for a custom partition table:
.. code-block::
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 36K, 20K,
otadata, data, ota, 56K, 8K,
app0, app, ota_0, 64K, 2M,
app1, app, ota_1, , 2M,
spiffs, data, spiffs, , 8M,
This partition will use about 12MB of the 16MB flash. The offset will be automatically calculated after the first application partition and the units are in K and M.
A alternative is to create the new partition table as a new file in the `tools/partitions <https://github.com/espressif/arduino-esp32/tree/master/tools/partitions>`_ folder and edit the `boards.txt <https://github.com/espressif/arduino-esp32/tree/master/boards.txt>`_ file to add your custom partition table.
Examples
--------
**2MB no OTA**
.. code-block::
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 36K, 20K,
factory, app, factory, 64K, 1900K,
**4MB no OTA**
.. code-block::
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 36K, 20K,
factory, app, factory, 64K, 4000K,
**4MB with OTA**
.. code-block::
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 36K, 20K,
otadata, data, ota, 56K, 8K,
app0, app, ota_0, 64K, 1900K,
app1, app, ota_1, , 1900K,
**8MB no OTA with Storage**
.. code-block::
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 36K, 20K,
factory, app, factory, 64K, 2M,
spiffs, data, spiffs, , 5M,
**8MB with OTA and Storage**
.. code-block::
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 36K, 20K,
otadata, data, ota, 56K, 8K,
app0, app, ota_0, 64K, 2M,
app1, app, ota_1, , 2M,
spiffs, data, spiffs, , 3M,
Reference
---------
This documentation was based on the `How to use custom partition tables on ESP32 <https://medium.com/p/69c0f3fa89c8>`_ article.

View File

@ -7,7 +7,6 @@
#include "Stream.h"
#include <functional>
extern "C" {
#include "lwip/ip_addr.h"
#include "esp_netif.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"

View File

@ -71,7 +71,7 @@ bool BLEAddress::operator!=(const BLEAddress& otherAddress) const {
}
bool BLEAddress::operator<(const BLEAddress& otherAddress) const {
return memcmp(otherAddress.m_address, m_address, ESP_BD_ADDR_LEN) < 0;
return memcmp(m_address, otherAddress.m_address, ESP_BD_ADDR_LEN) < 0;
}
bool BLEAddress::operator<=(const BLEAddress& otherAddress) const {
@ -83,7 +83,7 @@ bool BLEAddress::operator>=(const BLEAddress& otherAddress) const {
}
bool BLEAddress::operator>(const BLEAddress& otherAddress) const {
return memcmp(otherAddress.m_address, m_address, ESP_BD_ADDR_LEN) > 0;
return memcmp(m_address, otherAddress.m_address, ESP_BD_ADDR_LEN) > 0;
}
/**

View File

@ -0,0 +1,114 @@
/**
* Bluetooth Classic Example
* Scan for devices - asyncronously, print device as soon as found
* query devices for SPP - SDP profile
* connect to first device offering a SPP connection
*
* Example python server:
* source: https://gist.github.com/ukBaz/217875c83c2535d22a16ba38fc8f2a91
*
* Tested with Raspberry Pi onboard Wifi/BT, USB BT 4.0 dongles, USB BT 1.1 dongles,
* 202202: does NOT work with USB BT 2.0 dongles when esp32 aduino lib is compiled with SSP support!
* see https://github.com/espressif/esp-idf/issues/8394
*
* use ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE in connect() if remote side requests 'RequireAuthentication': dbus.Boolean(True),
* use ESP_SPP_SEC_NONE or ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE in connect() if remote side has Authentication: False
*/
#include <map>
#include <BluetoothSerial.h>
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif
#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#endif
BluetoothSerial SerialBT;
#define BT_DISCOVER_TIME 10000
esp_spp_sec_t sec_mask=ESP_SPP_SEC_NONE; // or ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE to request pincode confirmation
esp_spp_role_t role=ESP_SPP_ROLE_SLAVE; // or ESP_SPP_ROLE_MASTER
// std::map<BTAddress, BTAdvertisedDeviceSet> btDeviceList;
void setup() {
Serial.begin(115200);
if(! SerialBT.begin("ESP32test", true) ) {
Serial.println("========== serialBT failed!");
abort();
}
// SerialBT.setPin("1234"); // doesn't seem to change anything
// SerialBT.enableSSP(); // doesn't seem to change anything
Serial.println("Starting discoverAsync...");
BTScanResults* btDeviceList = SerialBT.getScanResults(); // maybe accessing from different threads!
if (SerialBT.discoverAsync([](BTAdvertisedDevice* pDevice) {
// BTAdvertisedDeviceSet*set = reinterpret_cast<BTAdvertisedDeviceSet*>(pDevice);
// btDeviceList[pDevice->getAddress()] = * set;
Serial.printf(">>>>>>>>>>>Found a new device asynchronously: %s\n", pDevice->toString().c_str());
} )
) {
delay(BT_DISCOVER_TIME);
Serial.print("Stopping discoverAsync... ");
SerialBT.discoverAsyncStop();
Serial.println("discoverAsync stopped");
delay(5000);
if(btDeviceList->getCount() > 0) {
BTAddress addr;
int channel=0;
Serial.println("Found devices:");
for (int i=0; i < btDeviceList->getCount(); i++) {
BTAdvertisedDevice *device=btDeviceList->getDevice(i);
Serial.printf(" ----- %s %s %d\n", device->getAddress().toString().c_str(), device->getName().c_str(), device->getRSSI());
std::map<int,std::string> channels=SerialBT.getChannels(device->getAddress());
Serial.printf("scanned for services, found %d\n", channels.size());
for(auto const &entry : channels) {
Serial.printf(" channel %d (%s)\n", entry.first, entry.second.c_str());
}
if(channels.size() > 0) {
addr = device->getAddress();
channel=channels.begin()->first;
}
}
if(addr) {
Serial.printf("connecting to %s - %d\n", addr.toString().c_str(), channel);
SerialBT.connect(addr, channel, sec_mask, role);
}
} else {
Serial.println("Didn't find any devices");
}
} else {
Serial.println("Error on discoverAsync f.e. not workin after a \"connect\"");
}
}
String sendData="Hi from esp32!\n";
void loop() {
if(! SerialBT.isClosed() && SerialBT.connected()) {
if( SerialBT.write((const uint8_t*) sendData.c_str(),sendData.length()) != sendData.length()) {
Serial.println("tx: error");
} else {
Serial.printf("tx: %s",sendData.c_str());
}
if(SerialBT.available()) {
Serial.print("rx: ");
while(SerialBT.available()) {
int c=SerialBT.read();
if(c >= 0) {
Serial.print((char) c);
}
}
Serial.println();
}
} else {
Serial.println("not connected");
}
delay(1000);
}

View File

@ -29,6 +29,9 @@ BTAddress::BTAddress(esp_bd_addr_t address) {
memcpy(m_address, address, ESP_BD_ADDR_LEN);
} // BTAddress
BTAddress::BTAddress() {
bzero(m_address, ESP_BD_ADDR_LEN);
} // BTAddress
/**
* @brief Create an address from a hex string
@ -64,13 +67,20 @@ bool BTAddress::equals(BTAddress otherAddress) {
return memcmp(otherAddress.getNative(), m_address, 6) == 0;
} // equals
BTAddress::operator bool () const {
for(int i = 0; i < ESP_BD_ADDR_LEN; i++){
if(this->m_address[i])
return true;
}
return false;
} // operator ()
/**
* @brief Return the native representation of the address.
* @return The native representation of the address.
*/
esp_bd_addr_t *BTAddress::getNative() {
return &m_address;
esp_bd_addr_t *BTAddress::getNative() const {
return const_cast<esp_bd_addr_t *>(&m_address);
} // getNative
@ -85,7 +95,7 @@ esp_bd_addr_t *BTAddress::getNative() {
*
* @return The string representation of the address.
*/
std::string BTAddress::toString() {
std::string BTAddress::toString() const {
auto size = 18;
char *res = (char*)malloc(size);
snprintf(res, size, "%02x:%02x:%02x:%02x:%02x:%02x", m_address[0], m_address[1], m_address[2], m_address[3], m_address[4], m_address[5]);

View File

@ -22,11 +22,14 @@
*/
class BTAddress {
public:
BTAddress();
BTAddress(esp_bd_addr_t address);
BTAddress(std::string stringAddress);
bool equals(BTAddress otherAddress);
esp_bd_addr_t* getNative();
std::string toString();
operator bool () const;
esp_bd_addr_t* getNative() const;
std::string toString() const;
private:
esp_bd_addr_t m_address;

View File

@ -16,14 +16,14 @@ public:
virtual ~BTAdvertisedDevice() = default;
virtual BTAddress getAddress();
virtual uint32_t getCOD();
virtual std::string getName();
virtual int8_t getRSSI();
virtual uint32_t getCOD() const;
virtual std::string getName() const;
virtual int8_t getRSSI() const;
virtual bool haveCOD();
virtual bool haveName();
virtual bool haveRSSI();
virtual bool haveCOD() const;
virtual bool haveName() const;
virtual bool haveRSSI() const;
virtual std::string toString();
};
@ -35,14 +35,14 @@ public:
BTAddress getAddress();
uint32_t getCOD();
std::string getName();
int8_t getRSSI();
uint32_t getCOD() const;
std::string getName() const;
int8_t getRSSI() const;
bool haveCOD();
bool haveName();
bool haveRSSI();
bool haveCOD() const;
bool haveName() const;
bool haveRSSI() const;
std::string toString();
@ -62,4 +62,4 @@ public:
int8_t m_rssi;
};
#endif
#endif

View File

@ -25,14 +25,14 @@ BTAdvertisedDeviceSet::BTAdvertisedDeviceSet() {
} // BTAdvertisedDeviceSet
BTAddress BTAdvertisedDeviceSet::getAddress() { return m_address; }
uint32_t BTAdvertisedDeviceSet::getCOD() { return m_cod; }
std::string BTAdvertisedDeviceSet::getName() { return m_name; }
int8_t BTAdvertisedDeviceSet::getRSSI() { return m_rssi; }
uint32_t BTAdvertisedDeviceSet::getCOD() const { return m_cod; }
std::string BTAdvertisedDeviceSet::getName() const { return m_name; }
int8_t BTAdvertisedDeviceSet::getRSSI() const { return m_rssi; }
bool BTAdvertisedDeviceSet::haveCOD() { return m_haveCOD; }
bool BTAdvertisedDeviceSet::haveName() { return m_haveName; }
bool BTAdvertisedDeviceSet::haveRSSI() { return m_haveRSSI; }
bool BTAdvertisedDeviceSet::haveCOD() const { return m_haveCOD; }
bool BTAdvertisedDeviceSet::haveName() const { return m_haveName; }
bool BTAdvertisedDeviceSet::haveRSSI() const { return m_haveRSSI; }
/**
* @brief Create a string representation of this device.

View File

@ -72,18 +72,30 @@ static esp_bt_pin_code_t _pin_code;
static int _pin_len;
static bool _isPinSet;
static bool _enableSSP;
static esp_spp_sec_t _sec_mask;
static esp_spp_role_t _role;
// start connect on ESP_SPP_DISCOVERY_COMP_EVT or save entry for getChannels
static bool _doConnect;
static std::map <int, std::string> sdpRecords;
static BTScanResultsSet scanResults;
static BTAdvertisedDeviceCb advertisedDeviceCb = nullptr;
// _spp_event_group
#define SPP_RUNNING 0x01
#define SPP_CONNECTED 0x02
#define SPP_CONGESTED 0x04
// true until OPEN successful, changes to false on CLOSE
#define SPP_DISCONNECTED 0x08
// true until connect(), changes to true on CLOSE
#define SPP_CLOSED 0x10
// _bt_event_group
#define BT_DISCOVERY_RUNNING 0x01
#define BT_DISCOVERY_COMPLETED 0x02
#define BT_SDP_RUNNING 0x04
#define BT_SDP_COMPLETED 0x08
typedef struct {
size_t len;
@ -98,7 +110,7 @@ static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
}
uint8_t *p = bda;
sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x",
p[0], p[1], p[2], p[3], p[4], p[5]);
return str;
}
@ -280,13 +292,15 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
case ESP_SPP_CLOSE_EVT://Client connection closed
if ((param->close.async == false && param->close.status == ESP_SPP_SUCCESS) || param->close.async) {
log_i("ESP_SPP_CLOSE_EVT: %u", secondConnectionAttempt);
log_i("ESP_SPP_CLOSE_EVT status:%d handle:%d close_by_remote:%d attempt %u", param->close.status,
param->close.handle, param->close.async, secondConnectionAttempt);
if(secondConnectionAttempt) {
secondConnectionAttempt = false;
} else {
_spp_client = 0;
xEventGroupSetBits(_spp_event_group, SPP_DISCONNECTED);
xEventGroupSetBits(_spp_event_group, SPP_CONGESTED);
xEventGroupSetBits(_spp_event_group, SPP_CLOSED);
}
xEventGroupClearBits(_spp_event_group, SPP_CONNECTED);
} else {
@ -333,13 +347,37 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
break;
case ESP_SPP_DISCOVERY_COMP_EVT://discovery complete
log_i("ESP_SPP_DISCOVERY_COMP_EVT");
log_i("ESP_SPP_DISCOVERY_COMP_EVT num=%d", param->disc_comp.scn_num);
if (param->disc_comp.status == ESP_SPP_SUCCESS) {
log_i("ESP_SPP_DISCOVERY_COMP_EVT: spp connect to remote");
esp_spp_connect(ESP_SPP_SEC_AUTHENTICATE, ESP_SPP_ROLE_MASTER, param->disc_comp.scn[0], _peer_bd_addr);
for(int i=0; i < param->disc_comp.scn_num; i++) {
log_d("ESP_SPP_DISCOVERY_COMP_EVT: spp [%d] channel: %d service name:%s", i, param->disc_comp.scn[i], param->disc_comp.service_name[0]);
}
if(_doConnect) {
if(param->disc_comp.scn_num > 0) {
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)
char bda_str[18];
log_i("ESP_SPP_DISCOVERY_COMP_EVT: spp connect to remote %s channel %d",
bda2str(_peer_bd_addr, bda_str, sizeof(bda_str)),
param->disc_comp.scn[0]);
#endif
xEventGroupClearBits(_spp_event_group, SPP_CLOSED);
if(esp_spp_connect(_sec_mask, _role, param->disc_comp.scn[0], _peer_bd_addr) != ESP_OK) {
log_e("ESP_SPP_DISCOVERY_COMP_EVT connect failed");
xEventGroupSetBits(_spp_event_group, SPP_CLOSED);
}
} else {
log_e("ESP_SPP_DISCOVERY_COMP_EVT remote doesn't offer an SPP channel");
xEventGroupSetBits(_spp_event_group, SPP_CLOSED);
}
} else {
for(int i=0; i < param->disc_comp.scn_num; i++) {
sdpRecords[param->disc_comp.scn[i]] = param->disc_comp.service_name[0];
}
}
} else {
log_e("ESP_SPP_DISCOVERY_COMP_EVT failed!, status:%d", param->disc_comp.status);
}
xEventGroupSetBits(_bt_event_group, BT_SDP_COMPLETED);
break;
case ESP_SPP_OPEN_EVT://Client connection open
@ -360,10 +398,15 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
break;
case ESP_SPP_CL_INIT_EVT://client initiated a connection
log_i("ESP_SPP_CL_INIT_EVT");
if (param->cl_init.status == ESP_SPP_SUCCESS) {
log_i("ESP_SPP_CL_INIT_EVT handle:%d sec_id:%d", param->cl_init.handle, param->cl_init.sec_id);
} else {
log_i("ESP_SPP_CL_INIT_EVT status:%d", param->cl_init.status);
}
break;
default:
log_i("ESP_SPP_* event unhandled %d", event);
break;
}
if(custom_spp_callback)(*custom_spp_callback)(event, param);
@ -377,7 +420,7 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
{
switch(event){
case ESP_BT_GAP_DISC_RES_EVT: {
log_i("ESP_BT_GAP_DISC_RES_EVT");
log_i("ESP_BT_GAP_DISC_RES_EVT properties=%d", param->disc_res.num_prop);
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)
char bda_str[18];
log_i("Scanned device: %s", bda2str(param->disc_res.bda, bda_str, 18));
@ -417,28 +460,29 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
break;
case ESP_BT_GAP_DEV_PROP_COD:
log_d("ESP_BT_GAP_DEV_PROP_COD");
if (param->disc_res.prop[i].len <= sizeof(int)) {
uint32_t cod = 0;
memcpy(&cod, param->disc_res.prop[i].val, param->disc_res.prop[i].len);
advertisedDevice.setCOD(cod);
log_d("ESP_BT_GAP_DEV_PROP_COD 0x%x", cod);
} else {
log_d("Value size larger than integer");
log_d("ESP_BT_GAP_DEV_PROP_COD invalid COD: Value size larger than integer");
}
break;
case ESP_BT_GAP_DEV_PROP_RSSI:
log_d("ESP_BT_GAP_DEV_PROP_RSSI");
if (param->disc_res.prop[i].len <= sizeof(int)) {
uint8_t rssi = 0;
memcpy(&rssi, param->disc_res.prop[i].val, param->disc_res.prop[i].len);
log_d("ESP_BT_GAP_DEV_PROP_RSSI %d", rssi);
advertisedDevice.setRSSI(rssi);
} else {
log_d("Value size larger than integer");
log_d("ESP_BT_GAP_DEV_PROP_RSSI invalid RSSI: Value size larger than integer");
}
break;
default:
log_i("ESP_BT_GAP_DISC_RES_EVT unknown property [%d]:type:%d", i, param->disc_res.prop[i].type);
break;
}
if (_isRemoteAddressSet)
@ -455,11 +499,12 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
break;
case ESP_BT_GAP_DISC_STATE_CHANGED_EVT:
log_i("ESP_BT_GAP_DISC_STATE_CHANGED_EVT");
if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED) {
log_i("ESP_BT_GAP_DISC_STATE_CHANGED_EVT stopped");
xEventGroupClearBits(_bt_event_group, BT_DISCOVERY_RUNNING);
xEventGroupSetBits(_bt_event_group, BT_DISCOVERY_COMPLETED);
} else { // ESP_BT_GAP_DISCOVERY_STARTED
log_i("ESP_BT_GAP_DISC_STATE_CHANGED_EVT started");
xEventGroupClearBits(_bt_event_group, BT_DISCOVERY_COMPLETED);
xEventGroupSetBits(_bt_event_group, BT_DISCOVERY_RUNNING);
}
@ -522,7 +567,24 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
log_i("ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
break;
case ESP_BT_GAP_CONFIG_EIR_DATA_EVT:
log_i("ESP_BT_GAP_CONFIG_EIR_DATA_EVT: stat:%d num:%d", param->config_eir_data.stat, param->config_eir_data.eir_type_num);
break;
case ESP_BT_GAP_READ_REMOTE_NAME_EVT:
if (param->read_rmt_name.stat == ESP_BT_STATUS_SUCCESS ) {
log_i("ESP_BT_GAP_READ_REMOTE_NAME_EVT: %s", param->read_rmt_name.rmt_name);
} else {
log_i("ESP_BT_GAP_READ_REMOTE_NAME_EVT: no success stat:%d", param->read_rmt_name.stat);
}
break;
case ESP_BT_GAP_MODE_CHG_EVT:
log_i("ESP_BT_GAP_MODE_CHG_EVT: mode: %d", param->mode_chg.mode);
break;
default:
log_i("ESP-BT_GAP_* unknown message: %d", event);
break;
}
}
@ -546,6 +608,7 @@ static bool _init_bt(const char *deviceName)
xEventGroupClearBits(_spp_event_group, 0xFFFFFF);
xEventGroupSetBits(_spp_event_group, SPP_CONGESTED);
xEventGroupSetBits(_spp_event_group, SPP_DISCONNECTED);
xEventGroupSetBits(_spp_event_group, SPP_CLOSED);
}
if (_spp_rx_queue == NULL){
_spp_rx_queue = xQueueCreate(RX_QUEUE_SIZE, sizeof(uint8_t)); //initialize the queue
@ -623,6 +686,7 @@ static bool _init_bt(const char *deviceName)
esp_bt_dev_set_device_name(deviceName);
if (_isPinSet) {
log_i("pin set");
btSetPin();
}
@ -690,7 +754,16 @@ static bool _stop_bt()
static bool waitForConnect(int timeout) {
TickType_t xTicksToWait = timeout / portTICK_PERIOD_MS;
return (xEventGroupWaitBits(_spp_event_group, SPP_CONNECTED, pdFALSE, pdTRUE, xTicksToWait) & SPP_CONNECTED) != 0;
// wait for connected or closed
EventBits_t rc = xEventGroupWaitBits(_spp_event_group, SPP_CONNECTED | SPP_CLOSED, pdFALSE, pdFALSE, xTicksToWait);
if((rc & SPP_CONNECTED) != 0)
return true;
else if((rc & SPP_CLOSED) != 0) {
log_d("connection closed!");
return false;
}
log_d("timeout");
return false;
}
static bool waitForDiscovered(int timeout) {
@ -698,6 +771,11 @@ static bool waitForDiscovered(int timeout) {
return (xEventGroupWaitBits(_spp_event_group, BT_DISCOVERY_COMPLETED, pdFALSE, pdTRUE, xTicksToWait) & BT_DISCOVERY_COMPLETED) != 0;
}
static bool waitForSDPRecord(int timeout) {
TickType_t xTicksToWait = timeout / portTICK_PERIOD_MS;
return (xEventGroupWaitBits(_bt_event_group, BT_SDP_COMPLETED, pdFALSE, pdTRUE, xTicksToWait) & BT_SDP_COMPLETED) != 0;
}
/*
* Serial Bluetooth Arduino
*
@ -713,6 +791,9 @@ BluetoothSerial::~BluetoothSerial(void)
_stop_bt();
}
/**
* @Param isMaster set to true if you want to connect to an other device
*/
bool BluetoothSerial::begin(String localName, bool isMaster)
{
_isMaster = isMaster;
@ -733,7 +814,7 @@ int BluetoothSerial::available(void)
int BluetoothSerial::peek(void)
{
uint8_t c;
if (_spp_rx_queue && xQueuePeek(_spp_rx_queue, &c, 0)){
if (_spp_rx_queue && xQueuePeek(_spp_rx_queue, &c, this->timeoutTicks)){
return c;
}
return -1;
@ -744,16 +825,24 @@ bool BluetoothSerial::hasClient(void)
return _spp_client > 0;
}
int BluetoothSerial::read(void)
int BluetoothSerial::read()
{
uint8_t c = 0;
if (_spp_rx_queue && xQueueReceive(_spp_rx_queue, &c, 0)){
if (_spp_rx_queue && xQueueReceive(_spp_rx_queue, &c, this->timeoutTicks)){
return c;
}
return -1;
}
/**
* Set timeout for read / peek
*/
void BluetoothSerial::setTimeout(int timeoutMS)
{
this->timeoutTicks=timeoutMS / portTICK_PERIOD_MS;
}
size_t BluetoothSerial::write(uint8_t c)
{
return write(&c, 1);
@ -812,6 +901,7 @@ void BluetoothSerial::enableSSP() {
* Use fixed pin code
*/
bool BluetoothSerial::setPin(const char *pin) {
log_i("pin: %s", pin);
bool isEmpty = !(pin && *pin);
if (isEmpty && !_isPinSet) {
return true; // nothing to do
@ -831,13 +921,18 @@ bool BluetoothSerial::setPin(const char *pin) {
bool BluetoothSerial::connect(String remoteName)
{
bool retval = false;
if (!isReady(true, READY_TIMEOUT)) return false;
if (remoteName && remoteName.length() < 1) {
log_e("No remote name is provided");
return false;
}
disconnect();
_doConnect = true;
_isRemoteAddressSet = false;
_sec_mask = ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE;
_role = ESP_SPP_ROLE_MASTER;
strncpy(_remote_name, remoteName.c_str(), ESP_BT_GAP_MAX_BDNAME_LEN);
_remote_name[ESP_BT_GAP_MAX_BDNAME_LEN] = 0;
log_i("master : remoteName");
@ -847,33 +942,78 @@ bool BluetoothSerial::connect(String remoteName)
#else
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
#endif
xEventGroupClearBits(_spp_event_group, SPP_CLOSED);
if (esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, INQ_LEN, INQ_NUM_RSPS) == ESP_OK) {
return waitForConnect(SCAN_TIMEOUT);
retval = waitForConnect(SCAN_TIMEOUT);
}
return false;
if (retval == false) {
_isRemoteAddressSet = false;
}
return retval;
}
bool BluetoothSerial::connect(uint8_t remoteAddress[])
/**
* @Param channel: specify channel or 0 for auto-detect
* @Param sec_mask:
* ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE
* ESP_SPP_SEC_NONE
* @Param role:
* ESP_SPP_ROLE_MASTER master can handle up to 7 connections to slaves
* ESP_SPP_ROLE_SLAVE can only have one connection to a master
*/
bool BluetoothSerial::connect(uint8_t remoteAddress[], int channel, esp_spp_sec_t sec_mask, esp_spp_role_t role)
{
bool retval = false;
if (!isReady(true, READY_TIMEOUT)) return false;
if (!remoteAddress) {
log_e("No remote address is provided");
return false;
}
disconnect();
_doConnect = true;
_remote_name[0] = 0;
_isRemoteAddressSet = true;
_sec_mask = sec_mask;
_role = role;
memcpy(_peer_bd_addr, remoteAddress, ESP_BD_ADDR_LEN);
log_i("master : remoteAddress");
if (esp_spp_start_discovery(_peer_bd_addr) == ESP_OK) {
return waitForConnect(READY_TIMEOUT);
xEventGroupClearBits(_spp_event_group, SPP_CLOSED);
if (channel > 0) {
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)
char bda_str[18];
log_i("spp connect to remote %s channel %d",
bda2str(_peer_bd_addr, bda_str, sizeof(bda_str)),
channel);
#endif
if(esp_spp_connect(sec_mask, role, channel, _peer_bd_addr) != ESP_OK ) {
log_e("spp connect failed");
retval = false;
} else {
retval = waitForConnect(READY_TIMEOUT);
if(retval) {
log_i("connected");
} else {
if(this->isClosed()) {
log_e("connect failed");
} else {
log_e("connect timed out after %dms", READY_TIMEOUT);
}
}
}
return false;
} else if (esp_spp_start_discovery(_peer_bd_addr) == ESP_OK) {
retval = waitForConnect(READY_TIMEOUT);
}
if (!retval) {
_isRemoteAddressSet = false;
}
return retval;
}
bool BluetoothSerial::connect()
{
if (!isReady(true, READY_TIMEOUT)) return false;
_doConnect = true;
if (_isRemoteAddressSet){
disconnect();
// use resolved or set address first
@ -924,6 +1064,13 @@ bool BluetoothSerial::connected(int timeout) {
return waitForConnect(timeout);
}
/**
* true if a connection terminated or a connection attempt failed
*/
bool BluetoothSerial::isClosed() {
return xEventGroupGetBits(_spp_event_group) & SPP_CLOSED;
}
bool BluetoothSerial::isReady(bool checkMaster, int timeout) {
if (checkMaster && !_isMaster) {
log_e("Master mode is not active. Call begin(localName, true) to enable Master mode");
@ -956,6 +1103,7 @@ BTScanResults* BluetoothSerial::discover(int timeoutMs) {
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
if (esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, timeout, 0) == ESP_OK) {
waitForDiscovered(timeoutMs);
log_i("gap_cancel_discovery()");
esp_bt_gap_cancel_discovery();
}
return &scanResults;
@ -1008,4 +1156,31 @@ BluetoothSerial::operator bool() const
{
return true;
}
/**
* SDP scan address
* esp_spp_start_discovery doesn't tell us the btAddress in the callback, so we have to wait until it's finished
*/
std::map<int, std::string> BluetoothSerial::getChannels(const BTAddress &remoteAddress) {
if(xEventGroupGetBits(_bt_event_group) & BT_SDP_RUNNING) {
log_e("getChannels failed - already running");
}
xEventGroupSetBits(_bt_event_group, BT_SDP_RUNNING);
xEventGroupClearBits(_bt_event_group, BT_SDP_COMPLETED);
_doConnect = false;
sdpRecords.clear();
log_d("esp_spp_start_discovery");
if (esp_spp_start_discovery(*remoteAddress.getNative()) != ESP_OK) {
log_e("esp_spp_start_discovery failed");
} else {
if(! waitForSDPRecord(READY_TIMEOUT)) {
log_e("getChannels failed timeout");
}
log_d("esp_spp_start_discovery wait for BT_SDP_COMPLETED done (%dms)", READY_TIMEOUT);
}
log_d("esp_spp_start_discovery done, found %d services", sdpRecords.size());
xEventGroupClearBits(_bt_event_group, BT_SDP_RUNNING);
return sdpRecords;
}
#endif

View File

@ -24,6 +24,7 @@
#include <esp_gap_bt_api.h>
#include <esp_spp_api.h>
#include <functional>
#include <map>
#include "BTScan.h"
typedef std::function<void(const uint8_t *buffer, size_t size)> BluetoothSerialDataCb;
@ -50,6 +51,7 @@ class BluetoothSerial: public Stream
size_t write(const uint8_t *buffer, size_t size);
void flush();
void end(void);
void setTimeout(int timeoutMS);
void onData(BluetoothSerialDataCb cb);
esp_err_t register_callback(esp_spp_cb_t * callback);
@ -60,9 +62,12 @@ class BluetoothSerial: public Stream
void enableSSP();
bool setPin(const char *pin);
bool connect(String remoteName);
bool connect(uint8_t remoteAddress[]);
bool connect(uint8_t remoteAddress[], int channel=0, esp_spp_sec_t sec_mask=(ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE), esp_spp_role_t role=ESP_SPP_ROLE_MASTER);
bool connect(const BTAddress &remoteAddress, int channel=0, esp_spp_sec_t sec_mask=(ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE), esp_spp_role_t role=ESP_SPP_ROLE_MASTER) {
return connect(*remoteAddress.getNative(), channel, sec_mask); };
bool connect();
bool connected(int timeout=0);
bool isClosed();
bool isReady(bool checkMaster=false, int timeout=0);
bool disconnect();
bool unpairDevice(uint8_t remoteAddress[]);
@ -73,6 +78,8 @@ class BluetoothSerial: public Stream
void discoverClear();
BTScanResults* getScanResults();
std::map<int, std::string> getChannels(const BTAddress &remoteAddress);
const int INQ_TIME = 1280; // Inquire Time unit 1280 ms
const int MIN_INQ_TIME = (ESP_BT_GAP_MIN_INQ_LEN * INQ_TIME);
const int MAX_INQ_TIME = (ESP_BT_GAP_MAX_INQ_LEN * INQ_TIME);
@ -80,7 +87,7 @@ class BluetoothSerial: public Stream
operator bool() const;
private:
String local_name;
int timeoutTicks=0;
};
#endif

View File

@ -20,6 +20,22 @@ DNSServer::DNSServer()
_port = 0;
}
DNSServer::~DNSServer()
{
if (_dnsHeader) {
free(_dnsHeader);
_dnsHeader = NULL;
}
if (_dnsQuestion) {
free(_dnsQuestion);
_dnsQuestion = NULL;
}
if (_buffer) {
free(_buffer);
_buffer = NULL;
}
}
bool DNSServer::start(const uint16_t &port, const String &domainName,
const IPAddress &resolvedIP)
{

View File

@ -76,6 +76,7 @@ class DNSServer
{
public:
DNSServer();
~DNSServer();
void processNextRequest();
void setErrorReplyCode(const DNSReplyCode &replyCode);
void setTTL(const uint32_t &ttl);

View File

@ -6,22 +6,35 @@
// Ensure ESP32 Wrover Module or other board with PSRAM is selected
// Partial images will be transmitted if image exceeds buffer size
//
// You must select partition scheme from the board menu that has at least 3MB APP space.
// Face Recognition is DISABLED for ESP32 and ESP32-S2, because it takes up from 15
// seconds to process single frame. Face Detection is ENABLED if PSRAM is enabled as well
// ===================
// Select camera model
#define CAMERA_MODEL_WROVER_KIT // Has PSRAM
// ===================
//#define CAMERA_MODEL_WROVER_KIT // Has PSRAM
//#define CAMERA_MODEL_ESP_EYE // Has PSRAM
//#define CAMERA_MODEL_ESP32S3_EYE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM
//#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM
//#define CAMERA_MODEL_M5STACK_UNITCAM // No PSRAM
//#define CAMERA_MODEL_AI_THINKER // Has PSRAM
#define CAMERA_MODEL_AI_THINKER // Has PSRAM
//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM
// ** Espressif Internal Boards **
//#define CAMERA_MODEL_ESP32_CAM_BOARD
//#define CAMERA_MODEL_ESP32S2_CAM_BOARD
//#define CAMERA_MODEL_ESP32S3_CAM_LCD
#include "camera_pins.h"
const char* ssid = "*********";
const char* password = "*********";
// ===========================
// Enter your WiFi credentials
// ===========================
const char* ssid = "**********";
const char* password = "**********";
void startCameraServer();
@ -50,19 +63,32 @@ void setup() {
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
config.frame_size = FRAMESIZE_UXGA;
config.pixel_format = PIXFORMAT_JPEG; // for streaming
//config.pixel_format = PIXFORMAT_RGB565; // for face detection/recognition
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.jpeg_quality = 12;
config.fb_count = 1;
// if PSRAM IC present, init with UXGA resolution and higher JPEG quality
// for larger pre-allocated frame buffer.
if(psramFound()){
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
if(config.pixel_format == PIXFORMAT_JPEG){
if(psramFound()){
config.jpeg_quality = 10;
config.fb_count = 2;
config.grab_mode = CAMERA_GRAB_LATEST;
} else {
// Limit the frame size when PSRAM is not available
config.frame_size = FRAMESIZE_SVGA;
config.fb_location = CAMERA_FB_IN_DRAM;
}
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
config.fb_location = CAMERA_FB_IN_DRAM;
// Best option for face detection/recognition
config.frame_size = FRAMESIZE_240X240;
#if CONFIG_IDF_TARGET_ESP32S3
config.fb_count = 2;
#endif
}
#if defined(CAMERA_MODEL_ESP_EYE)
@ -85,14 +111,21 @@ void setup() {
s->set_saturation(s, -2); // lower the saturation
}
// drop down frame size for higher initial frame rate
s->set_framesize(s, FRAMESIZE_QVGA);
if(config.pixel_format == PIXFORMAT_JPEG){
s->set_framesize(s, FRAMESIZE_QVGA);
}
#if defined(CAMERA_MODEL_M5STACK_WIDE) || defined(CAMERA_MODEL_M5STACK_ESP32CAM)
s->set_vflip(s, 1);
s->set_hmirror(s, 1);
#endif
#if defined(CAMERA_MODEL_ESP32S3_EYE)
s->set_vflip(s, 1);
#endif
WiFi.begin(ssid, password);
WiFi.setSleep(false);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
@ -109,6 +142,6 @@ void setup() {
}
void loop() {
// put your main code here, to run repeatedly:
// Do nothing. Everything is done in another task by the web server
delay(10000);
}

View File

@ -28,14 +28,37 @@
static const char *TAG = "camera_httpd";
#endif
// Face Detection will not work on boards without (or with disabled) PSRAM
#ifdef BOARD_HAS_PSRAM
#define CONFIG_ESP_FACE_DETECT_ENABLED 1
// Face Recognition takes upward from 15 seconds per frame on chips other than ESP32S3
// Makes no sense to have it enabled for them
#if CONFIG_IDF_TARGET_ESP32S3
#define CONFIG_ESP_FACE_RECOGNITION_ENABLED 1
#else
#define CONFIG_ESP_FACE_RECOGNITION_ENABLED 0
#endif
#else
#define CONFIG_ESP_FACE_DETECT_ENABLED 0
#define CONFIG_ESP_FACE_RECOGNITION_ENABLED 0
#endif
#if CONFIG_ESP_FACE_DETECT_ENABLED
#include "fd_forward.h"
#include <vector>
#include "human_face_detect_msr01.hpp"
#include "human_face_detect_mnp01.hpp"
#define TWO_STAGE 1 /*<! 1: detect by two-stage which is more accurate but slower(with keypoints). */
/*<! 0: detect by one-stage which is less accurate but faster(without keypoints). */
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
#include "fr_forward.h"
#include "face_recognition_tool.hpp"
#include "face_recognition_112_v1_s16.hpp"
#include "face_recognition_112_v1_s8.hpp"
#define QUANT_TYPE 0 //if set to 1 => very large firmware, very slow, reboots when streaming...
#define ENROLL_CONFIRM_TIMES 5
#define FACE_ID_SAVE_NUMBER 7
#endif
@ -77,12 +100,24 @@ httpd_handle_t camera_httpd = NULL;
static int8_t detection_enabled = 0;
static mtmn_config_t mtmn_config = {0};
// #if TWO_STAGE
// static HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F);
// static HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5);
// #else
// static HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F);
// #endif
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
static int8_t recognition_enabled = 0;
static int8_t is_enrolling = 0;
static face_id_list id_list = {0};
#if QUANT_TYPE
// S16 model
FaceRecognition112V1S16 recognizer;
#else
// S8 model
FaceRecognition112V1S8 recognizer;
#endif
#endif
#endif
@ -113,6 +148,7 @@ static ra_filter_t *ra_filter_init(ra_filter_t *filter, size_t sample_size)
return filter;
}
/* unused function triggers error
static int ra_filter_run(ra_filter_t *filter, int value)
{
if (!filter->values)
@ -130,21 +166,16 @@ static int ra_filter_run(ra_filter_t *filter, int value)
}
return filter->sum / filter->count;
}
*/
#if CONFIG_ESP_FACE_DETECT_ENABLED
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
static void rgb_print(dl_matrix3du_t *image_matrix, uint32_t color, const char *str)
static void rgb_print(fb_data_t *fb, uint32_t color, const char *str)
{
fb_data_t fb;
fb.width = image_matrix->w;
fb.height = image_matrix->h;
fb.data = image_matrix->item;
fb.bytes_per_pixel = 3;
fb.format = FB_BGR888;
fb_gfx_print(&fb, (fb.width - (strlen(str) * 14)) / 2, 10, color, str);
fb_gfx_print(fb, (fb->width - (strlen(str) * 14)) / 2, 10, color, str);
}
static int rgb_printf(dl_matrix3du_t *image_matrix, uint32_t color, const char *format, ...)
static int rgb_printf(fb_data_t *fb, uint32_t color, const char *format, ...)
{
char loc_buf[64];
char *temp = loc_buf;
@ -165,7 +196,7 @@ static int rgb_printf(dl_matrix3du_t *image_matrix, uint32_t color, const char *
}
vsnprintf(temp, len + 1, format, arg);
va_end(arg);
rgb_print(image_matrix, color, temp);
rgb_print(fb, color, temp);
if (len > 64)
{
free(temp);
@ -173,9 +204,9 @@ static int rgb_printf(dl_matrix3du_t *image_matrix, uint32_t color, const char *
return len;
}
#endif
static void draw_face_boxes(dl_matrix3du_t *image_matrix, box_array_t *boxes, int face_id)
static void draw_face_boxes(fb_data_t *fb, std::list<dl::detect::result_t> *results, int face_id)
{
int x, y, w, h, i;
int x, y, w, h;
uint32_t color = FACE_COLOR_YELLOW;
if (face_id < 0)
{
@ -185,89 +216,64 @@ static void draw_face_boxes(dl_matrix3du_t *image_matrix, box_array_t *boxes, in
{
color = FACE_COLOR_GREEN;
}
fb_data_t fb;
fb.width = image_matrix->w;
fb.height = image_matrix->h;
fb.data = image_matrix->item;
fb.bytes_per_pixel = 3;
fb.format = FB_BGR888;
for (i = 0; i < boxes->len; i++)
if(fb->bytes_per_pixel == 2){
//color = ((color >> 8) & 0xF800) | ((color >> 3) & 0x07E0) | (color & 0x001F);
color = ((color >> 16) & 0x001F) | ((color >> 3) & 0x07E0) | ((color << 8) & 0xF800);
}
int i = 0;
for (std::list<dl::detect::result_t>::iterator prediction = results->begin(); prediction != results->end(); prediction++, i++)
{
// rectangle box
x = (int)boxes->box[i].box_p[0];
y = (int)boxes->box[i].box_p[1];
w = (int)boxes->box[i].box_p[2] - x + 1;
h = (int)boxes->box[i].box_p[3] - y + 1;
fb_gfx_drawFastHLine(&fb, x, y, w, color);
fb_gfx_drawFastHLine(&fb, x, y + h - 1, w, color);
fb_gfx_drawFastVLine(&fb, x, y, h, color);
fb_gfx_drawFastVLine(&fb, x + w - 1, y, h, color);
#if 0
// landmark
x = (int)prediction->box[0];
y = (int)prediction->box[1];
w = (int)prediction->box[2] - x + 1;
h = (int)prediction->box[3] - y + 1;
if((x + w) > fb->width){
w = fb->width - x;
}
if((y + h) > fb->height){
h = fb->height - y;
}
fb_gfx_drawFastHLine(fb, x, y, w, color);
fb_gfx_drawFastHLine(fb, x, y + h - 1, w, color);
fb_gfx_drawFastVLine(fb, x, y, h, color);
fb_gfx_drawFastVLine(fb, x + w - 1, y, h, color);
#if TWO_STAGE
// landmarks (left eye, mouth left, nose, right eye, mouth right)
int x0, y0, j;
for (j = 0; j < 10; j+=2) {
x0 = (int)boxes->landmark[i].landmark_p[j];
y0 = (int)boxes->landmark[i].landmark_p[j+1];
fb_gfx_fillRect(&fb, x0, y0, 3, 3, color);
x0 = (int)prediction->keypoint[j];
y0 = (int)prediction->keypoint[j+1];
fb_gfx_fillRect(fb, x0, y0, 3, 3, color);
}
#endif
}
}
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
static int run_face_recognition(dl_matrix3du_t *image_matrix, box_array_t *net_boxes)
static int run_face_recognition(fb_data_t *fb, std::list<dl::detect::result_t> *results)
{
dl_matrix3du_t *aligned_face = NULL;
int matched_id = 0;
std::vector<int> landmarks = results->front().keypoint;
int id = -1;
aligned_face = dl_matrix3du_alloc(1, FACE_WIDTH, FACE_HEIGHT, 3);
if (!aligned_face)
{
ESP_LOGE(TAG, "Could not allocate face recognition buffer");
return matched_id;
}
if (align_face(net_boxes, image_matrix, aligned_face) == ESP_OK)
{
if (is_enrolling == 1)
{
int8_t left_sample_face = enroll_face(&id_list, aligned_face);
Tensor<uint8_t> tensor;
tensor.set_element((uint8_t *)fb->data).set_shape({fb->height, fb->width, 3}).set_auto_free(false);
if (left_sample_face == (ENROLL_CONFIRM_TIMES - 1))
{
ESP_LOGD(TAG, "Enrolling Face ID: %d", id_list.tail);
}
ESP_LOGD(TAG, "Enrolling Face ID: %d sample %d", id_list.tail, ENROLL_CONFIRM_TIMES - left_sample_face);
rgb_printf(image_matrix, FACE_COLOR_CYAN, "ID[%u] Sample[%u]", id_list.tail, ENROLL_CONFIRM_TIMES - left_sample_face);
if (left_sample_face == 0)
{
is_enrolling = 0;
ESP_LOGD(TAG, "Enrolled Face ID: %d", id_list.tail);
}
}
else
{
matched_id = recognize_face(&id_list, aligned_face);
if (matched_id >= 0)
{
ESP_LOGW(TAG, "Match Face ID: %u", matched_id);
rgb_printf(image_matrix, FACE_COLOR_GREEN, "Hello Subject %u", matched_id);
}
else
{
ESP_LOGW(TAG, "No Match Found");
rgb_print(image_matrix, FACE_COLOR_RED, "Intruder Alert!");
matched_id = -1;
}
}
}
else
{
ESP_LOGW(TAG, "Face Not Aligned");
//rgb_print(image_matrix, FACE_COLOR_YELLOW, "Human Detected");
int enrolled_count = recognizer.get_enrolled_id_num();
if (enrolled_count < FACE_ID_SAVE_NUMBER && is_enrolling){
id = recognizer.enroll_id(tensor, landmarks, "", true);
ESP_LOGI(TAG, "Enrolled ID: %d", id);
rgb_printf(fb, FACE_COLOR_CYAN, "ID[%u]", id);
}
dl_matrix3du_free(aligned_face);
return matched_id;
face_info_t recognize = recognizer.recognize(tensor, landmarks);
if(recognize.id >= 0){
rgb_printf(fb, FACE_COLOR_GREEN, "ID[%u]: %.2f", recognize.id, recognize.similarity);
} else {
rgb_print(fb, FACE_COLOR_RED, "Intruder Alert!");
}
return recognize.id;
}
#endif
#endif
@ -290,7 +296,9 @@ static esp_err_t bmp_handler(httpd_req_t *req)
{
camera_fb_t *fb = NULL;
esp_err_t res = ESP_OK;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
uint64_t fr_start = esp_timer_get_time();
#endif
fb = esp_camera_fb_get();
if (!fb)
{
@ -319,7 +327,9 @@ static esp_err_t bmp_handler(httpd_req_t *req)
}
res = httpd_resp_send(req, (const char *)buf, buf_len);
free(buf);
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
uint64_t fr_end = esp_timer_get_time();
#endif
ESP_LOGI(TAG, "BMP: %llums, %uB", (uint64_t)((fr_end - fr_start) / 1000), buf_len);
return res;
}
@ -343,7 +353,9 @@ static esp_err_t capture_handler(httpd_req_t *req)
{
camera_fb_t *fb = NULL;
esp_err_t res = ESP_OK;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
int64_t fr_start = esp_timer_get_time();
#endif
#ifdef CONFIG_LED_ILLUMINATOR_ENABLED
enable_led(true);
@ -373,15 +385,21 @@ static esp_err_t capture_handler(httpd_req_t *req)
size_t out_len, out_width, out_height;
uint8_t *out_buf;
bool s;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
bool detected = false;
#endif
int face_id = 0;
if (!detection_enabled || fb->width > 400)
{
#endif
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
size_t fb_len = 0;
#endif
if (fb->format == PIXFORMAT_JPEG)
{
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
fb_len = fb->len;
#endif
res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
}
else
@ -389,68 +407,110 @@ static esp_err_t capture_handler(httpd_req_t *req)
jpg_chunking_t jchunk = {req, 0};
res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk) ? ESP_OK : ESP_FAIL;
httpd_resp_send_chunk(req, NULL, 0);
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
fb_len = jchunk.len;
#endif
}
esp_camera_fb_return(fb);
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
int64_t fr_end = esp_timer_get_time();
#endif
ESP_LOGI(TAG, "JPG: %uB %ums", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start) / 1000));
return res;
#if CONFIG_ESP_FACE_DETECT_ENABLED
}
dl_matrix3du_t *image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3);
if (!image_matrix)
{
esp_camera_fb_return(fb);
ESP_LOGE(TAG, "dl_matrix3du_alloc failed");
httpd_resp_send_500(req);
return ESP_FAIL;
}
out_buf = image_matrix->item;
out_len = fb->width * fb->height * 3;
out_width = fb->width;
out_height = fb->height;
s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf);
esp_camera_fb_return(fb);
if (!s)
{
dl_matrix3du_free(image_matrix);
ESP_LOGE(TAG, "to rgb888 failed");
httpd_resp_send_500(req);
return ESP_FAIL;
}
box_array_t *net_boxes = face_detect(image_matrix, &mtmn_config);
if (net_boxes)
{
detected = true;
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
if (recognition_enabled)
{
face_id = run_face_recognition(image_matrix, net_boxes);
}
#endif
draw_face_boxes(image_matrix, net_boxes, face_id);
dl_lib_free(net_boxes->score);
dl_lib_free(net_boxes->box);
if (net_boxes->landmark != NULL)
dl_lib_free(net_boxes->landmark);
dl_lib_free(net_boxes);
}
jpg_chunking_t jchunk = {req, 0};
s = fmt2jpg_cb(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, jpg_encode_stream, &jchunk);
dl_matrix3du_free(image_matrix);
if (!s)
if (fb->format == PIXFORMAT_RGB565
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
&& !recognition_enabled
#endif
){
#if TWO_STAGE
HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F);
HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5);
std::list<dl::detect::result_t> &candidates = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3});
std::list<dl::detect::result_t> &results = s2.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}, candidates);
#else
HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F);
std::list<dl::detect::result_t> &results = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3});
#endif
if (results.size() > 0) {
fb_data_t rfb;
rfb.width = fb->width;
rfb.height = fb->height;
rfb.data = fb->buf;
rfb.bytes_per_pixel = 2;
rfb.format = FB_RGB565;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
detected = true;
#endif
draw_face_boxes(&rfb, &results, face_id);
}
s = fmt2jpg_cb(fb->buf, fb->len, fb->width, fb->height, PIXFORMAT_RGB565, 90, jpg_encode_stream, &jchunk);
esp_camera_fb_return(fb);
} else
{
ESP_LOGE(TAG, "JPEG compression failed");
return ESP_FAIL;
out_len = fb->width * fb->height * 3;
out_width = fb->width;
out_height = fb->height;
out_buf = (uint8_t*)malloc(out_len);
if (!out_buf) {
ESP_LOGE(TAG, "out_buf malloc failed");
httpd_resp_send_500(req);
return ESP_FAIL;
}
s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf);
esp_camera_fb_return(fb);
if (!s) {
free(out_buf);
ESP_LOGE(TAG, "to rgb888 failed");
httpd_resp_send_500(req);
return ESP_FAIL;
}
fb_data_t rfb;
rfb.width = out_width;
rfb.height = out_height;
rfb.data = out_buf;
rfb.bytes_per_pixel = 3;
rfb.format = FB_BGR888;
#if TWO_STAGE
HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F);
HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5);
std::list<dl::detect::result_t> &candidates = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3});
std::list<dl::detect::result_t> &results = s2.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}, candidates);
#else
HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F);
std::list<dl::detect::result_t> &results = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3});
#endif
if (results.size() > 0) {
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
detected = true;
#endif
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
if (recognition_enabled) {
face_id = run_face_recognition(&rfb, &results);
}
#endif
draw_face_boxes(&rfb, &results, face_id);
}
s = fmt2jpg_cb(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, jpg_encode_stream, &jchunk);
free(out_buf);
}
if (!s) {
ESP_LOGE(TAG, "JPEG compression failed");
httpd_resp_send_500(req);
return ESP_FAIL;
}
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
int64_t fr_end = esp_timer_get_time();
#endif
ESP_LOGI(TAG, "FACE: %uB %ums %s%d", (uint32_t)(jchunk.len), (uint32_t)((fr_end - fr_start) / 1000), detected ? "DETECTED " : "", face_id);
return res;
#endif
@ -465,14 +525,24 @@ static esp_err_t stream_handler(httpd_req_t *req)
uint8_t *_jpg_buf = NULL;
char *part_buf[128];
#if CONFIG_ESP_FACE_DETECT_ENABLED
dl_matrix3du_t *image_matrix = NULL;
bool detected = false;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
bool detected = false;
int64_t fr_ready = 0;
int64_t fr_recognize = 0;
int64_t fr_encode = 0;
int64_t fr_face = 0;
int64_t fr_start = 0;
#endif
int face_id = 0;
int64_t fr_start = 0;
int64_t fr_ready = 0;
int64_t fr_face = 0;
int64_t fr_recognize = 0;
int64_t fr_encode = 0;
size_t out_len = 0, out_width = 0, out_height = 0;
uint8_t *out_buf = NULL;
bool s = false;
#if TWO_STAGE
HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F);
HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5);
#else
HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F);
#endif
#endif
static int64_t last_frame = 0;
@ -498,7 +568,9 @@ static esp_err_t stream_handler(httpd_req_t *req)
while (true)
{
#if CONFIG_ESP_FACE_DETECT_ENABLED
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
detected = false;
#endif
face_id = 0;
#endif
@ -513,11 +585,13 @@ static esp_err_t stream_handler(httpd_req_t *req)
_timestamp.tv_sec = fb->timestamp.tv_sec;
_timestamp.tv_usec = fb->timestamp.tv_usec;
#if CONFIG_ESP_FACE_DETECT_ENABLED
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
fr_start = esp_timer_get_time();
fr_ready = fr_start;
fr_face = fr_start;
fr_encode = fr_start;
fr_recognize = fr_start;
fr_face = fr_start;
#endif
if (!detection_enabled || fb->width > 400)
{
#endif
@ -541,65 +615,112 @@ static esp_err_t stream_handler(httpd_req_t *req)
}
else
{
image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3);
if (!image_matrix)
{
ESP_LOGE(TAG, "dl_matrix3du_alloc failed");
res = ESP_FAIL;
}
else
{
if (!fmt2rgb888(fb->buf, fb->len, fb->format, image_matrix->item))
{
ESP_LOGE(TAG, "fmt2rgb888 failed");
if (fb->format == PIXFORMAT_RGB565
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
&& !recognition_enabled
#endif
){
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
fr_ready = esp_timer_get_time();
#endif
#if TWO_STAGE
std::list<dl::detect::result_t> &candidates = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3});
std::list<dl::detect::result_t> &results = s2.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}, candidates);
#else
std::list<dl::detect::result_t> &results = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3});
#endif
#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
fr_face = esp_timer_get_time();
fr_recognize = fr_face;
#endif
if (results.size() > 0) {
fb_data_t rfb;
rfb.width = fb->width;
rfb.height = fb->height;
rfb.data = fb->buf;
rfb.bytes_per_pixel = 2;
rfb.format = FB_RGB565;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
detected = true;
#endif
draw_face_boxes(&rfb, &results, face_id);
}
s = fmt2jpg(fb->buf, fb->len, fb->width, fb->height, PIXFORMAT_RGB565, 80, &_jpg_buf, &_jpg_buf_len);
esp_camera_fb_return(fb);
fb = NULL;
if (!s) {
ESP_LOGE(TAG, "fmt2jpg failed");
res = ESP_FAIL;
}
else
{
fr_ready = esp_timer_get_time();
box_array_t *net_boxes = NULL;
if (detection_enabled)
{
net_boxes = face_detect(image_matrix, &mtmn_config);
}
fr_face = esp_timer_get_time();
fr_recognize = fr_face;
if (net_boxes || fb->format != PIXFORMAT_JPEG)
{
if (net_boxes)
{
detected = true;
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
if (recognition_enabled)
{
face_id = run_face_recognition(image_matrix, net_boxes);
}
fr_recognize = esp_timer_get_time();
#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
fr_encode = esp_timer_get_time();
#endif
draw_face_boxes(image_matrix, net_boxes, face_id);
dl_lib_free(net_boxes->score);
dl_lib_free(net_boxes->box);
if (net_boxes->landmark != NULL)
dl_lib_free(net_boxes->landmark);
dl_lib_free(net_boxes);
} else
{
out_len = fb->width * fb->height * 3;
out_width = fb->width;
out_height = fb->height;
out_buf = (uint8_t*)malloc(out_len);
if (!out_buf) {
ESP_LOGE(TAG, "out_buf malloc failed");
res = ESP_FAIL;
} else {
s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf);
esp_camera_fb_return(fb);
fb = NULL;
if (!s) {
free(out_buf);
ESP_LOGE(TAG, "to rgb888 failed");
res = ESP_FAIL;
} else {
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
fr_ready = esp_timer_get_time();
#endif
fb_data_t rfb;
rfb.width = out_width;
rfb.height = out_height;
rfb.data = out_buf;
rfb.bytes_per_pixel = 3;
rfb.format = FB_BGR888;
#if TWO_STAGE
std::list<dl::detect::result_t> &candidates = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3});
std::list<dl::detect::result_t> &results = s2.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}, candidates);
#else
std::list<dl::detect::result_t> &results = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3});
#endif
#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
fr_face = esp_timer_get_time();
fr_recognize = fr_face;
#endif
if (results.size() > 0) {
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
detected = true;
#endif
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
if (recognition_enabled) {
face_id = run_face_recognition(&rfb, &results);
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
fr_recognize = esp_timer_get_time();
#endif
}
#endif
draw_face_boxes(&rfb, &results, face_id);
}
if (!fmt2jpg(image_matrix->item, fb->width * fb->height * 3, fb->width, fb->height, PIXFORMAT_RGB888, 90, &_jpg_buf, &_jpg_buf_len))
{
s = fmt2jpg(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, &_jpg_buf, &_jpg_buf_len);
free(out_buf);
if (!s) {
ESP_LOGE(TAG, "fmt2jpg failed");
res = ESP_FAIL;
}
esp_camera_fb_return(fb);
fb = NULL;
#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
fr_encode = esp_timer_get_time();
#endif
}
else
{
_jpg_buf = fb->buf;
_jpg_buf_len = fb->len;
}
fr_encode = esp_timer_get_time();
}
dl_matrix3du_free(image_matrix);
}
}
#endif
@ -630,11 +751,12 @@ static esp_err_t stream_handler(httpd_req_t *req)
}
if (res != ESP_OK)
{
ESP_LOGE(TAG, "send frame failed failed");
break;
}
int64_t fr_end = esp_timer_get_time();
#if CONFIG_ESP_FACE_DETECT_ENABLED
#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
int64_t ready_time = (fr_ready - fr_start) / 1000;
int64_t face_time = (fr_face - fr_ready) / 1000;
int64_t recognize_time = (fr_recognize - fr_face) / 1000;
@ -643,9 +765,10 @@ static esp_err_t stream_handler(httpd_req_t *req)
#endif
int64_t frame_time = fr_end - last_frame;
last_frame = fr_end;
frame_time /= 1000;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
uint32_t avg_frame_time = ra_filter_run(&ra_filter, frame_time);
#endif
ESP_LOGI(TAG, "MJPG: %uB %ums (%.1ffps), AVG: %ums (%.1ffps)"
#if CONFIG_ESP_FACE_DETECT_ENABLED
", %u+%u+%u+%u=%u %s%d"
@ -667,7 +790,6 @@ static esp_err_t stream_handler(httpd_req_t *req)
enable_led(false);
#endif
last_frame = 0;
return res;
}
@ -784,8 +906,10 @@ static esp_err_t cmd_handler(httpd_req_t *req)
#endif
}
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
else if (!strcmp(variable, "face_enroll"))
is_enrolling = val;
else if (!strcmp(variable, "face_enroll")){
is_enrolling = !is_enrolling;
ESP_LOGI(TAG, "Enrolling: %s", is_enrolling?"true":"false");
}
else if (!strcmp(variable, "face_recognize")) {
recognition_enabled = val;
if (recognition_enabled) {
@ -1150,26 +1274,11 @@ void startCameraServer()
ra_filter_init(&ra_filter, 20);
#if CONFIG_ESP_FACE_DETECT_ENABLED
mtmn_config.type = FAST;
mtmn_config.min_face = 80;
mtmn_config.pyramid = 0.707;
mtmn_config.pyramid_times = 4;
mtmn_config.p_threshold.score = 0.6;
mtmn_config.p_threshold.nms = 0.7;
mtmn_config.p_threshold.candidate_number = 20;
mtmn_config.r_threshold.score = 0.7;
mtmn_config.r_threshold.nms = 0.7;
mtmn_config.r_threshold.candidate_number = 10;
mtmn_config.o_threshold.score = 0.7;
mtmn_config.o_threshold.nms = 0.7;
mtmn_config.o_threshold.candidate_number = 1;
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
face_id_init(&id_list, FACE_ID_SAVE_NUMBER, ENROLL_CONFIRM_TIMES);
#endif
recognizer.set_partition(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "fr");
// load ids from flash partition
recognizer.set_ids_from_flash();
#endif
ESP_LOGI(TAG, "Starting web server on port: '%d'", config.server_port);
if (httpd_start(&camera_httpd, &config) == ESP_OK)

View File

@ -170,6 +170,104 @@
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#elif defined(CAMERA_MODEL_ESP32_CAM_BOARD)
// The 18 pin header on the board has Y5 and Y3 swapped
#define USE_BOARD_HEADER 0
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM 33
#define XCLK_GPIO_NUM 4
#define SIOD_GPIO_NUM 18
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 36
#define Y8_GPIO_NUM 19
#define Y7_GPIO_NUM 21
#define Y6_GPIO_NUM 39
#if USE_BOARD_HEADER
#define Y5_GPIO_NUM 13
#else
#define Y5_GPIO_NUM 35
#endif
#define Y4_GPIO_NUM 14
#if USE_BOARD_HEADER
#define Y3_GPIO_NUM 35
#else
#define Y3_GPIO_NUM 13
#endif
#define Y2_GPIO_NUM 34
#define VSYNC_GPIO_NUM 5
#define HREF_GPIO_NUM 27
#define PCLK_GPIO_NUM 25
#elif defined(CAMERA_MODEL_ESP32S3_CAM_LCD)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 40
#define SIOD_GPIO_NUM 17
#define SIOC_GPIO_NUM 18
#define Y9_GPIO_NUM 39
#define Y8_GPIO_NUM 41
#define Y7_GPIO_NUM 42
#define Y6_GPIO_NUM 12
#define Y5_GPIO_NUM 3
#define Y4_GPIO_NUM 14
#define Y3_GPIO_NUM 47
#define Y2_GPIO_NUM 13
#define VSYNC_GPIO_NUM 21
#define HREF_GPIO_NUM 38
#define PCLK_GPIO_NUM 11
#elif defined(CAMERA_MODEL_ESP32S2_CAM_BOARD)
// The 18 pin header on the board has Y5 and Y3 swapped
#define USE_BOARD_HEADER 0
#define PWDN_GPIO_NUM 1
#define RESET_GPIO_NUM 2
#define XCLK_GPIO_NUM 42
#define SIOD_GPIO_NUM 41
#define SIOC_GPIO_NUM 18
#define Y9_GPIO_NUM 16
#define Y8_GPIO_NUM 39
#define Y7_GPIO_NUM 40
#define Y6_GPIO_NUM 15
#if USE_BOARD_HEADER
#define Y5_GPIO_NUM 12
#else
#define Y5_GPIO_NUM 13
#endif
#define Y4_GPIO_NUM 5
#if USE_BOARD_HEADER
#define Y3_GPIO_NUM 13
#else
#define Y3_GPIO_NUM 12
#endif
#define Y2_GPIO_NUM 14
#define VSYNC_GPIO_NUM 38
#define HREF_GPIO_NUM 4
#define PCLK_GPIO_NUM 3
#elif defined(CAMERA_MODEL_ESP32S3_EYE)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 15
#define SIOD_GPIO_NUM 4
#define SIOC_GPIO_NUM 5
#define Y2_GPIO_NUM 11
#define Y3_GPIO_NUM 9
#define Y4_GPIO_NUM 8
#define Y5_GPIO_NUM 10
#define Y6_GPIO_NUM 12
#define Y7_GPIO_NUM 18
#define Y8_GPIO_NUM 17
#define Y9_GPIO_NUM 16
#define VSYNC_GPIO_NUM 6
#define HREF_GPIO_NUM 7
#define PCLK_GPIO_NUM 13
#else
#error "Camera model not selected"
#endif

View File

@ -0,0 +1,5 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x3d0000,
fr, data, , 0x3e0000, 0x20000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x3d0000
5 fr data 0x3e0000 0x20000

View File

@ -30,7 +30,7 @@
#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
void print_reset_reason(RESET_REASON reason)
void print_reset_reason(int reason)
{
switch ( reason)
{
@ -53,7 +53,7 @@ void print_reset_reason(RESET_REASON reason)
}
}
void verbose_print_reset_reason(RESET_REASON reason)
void verbose_print_reset_reason(int reason)
{
switch ( reason)
{

View File

@ -30,8 +30,6 @@ void setup() {
}
void loop() {
static uint32_t count = 0;
if (touch1detected) {
touch1detected = false;
if (touchInterruptGetLastStatus(T1)) {

View File

@ -57,24 +57,25 @@ extern void tcpipInit();
static eth_clock_mode_t eth_clock_mode = ETH_CLK_MODE;
#if CONFIG_ETH_RMII_CLK_INPUT
/*
static void emac_config_apll_clock(void)
{
/* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) */
// apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2)
rtc_xtal_freq_t rtc_xtal_freq = rtc_clk_xtal_freq_get();
switch (rtc_xtal_freq) {
case RTC_XTAL_FREQ_40M: // Recommended
/* 50 MHz = 40MHz * (4 + 6) / (2 * (2 + 2) = 50.000 */
/* sdm0 = 0, sdm1 = 0, sdm2 = 6, o_div = 2 */
// 50 MHz = 40MHz * (4 + 6) / (2 * (2 + 2) = 50.000
// sdm0 = 0, sdm1 = 0, sdm2 = 6, o_div = 2
rtc_clk_apll_enable(true, 0, 0, 6, 2);
break;
case RTC_XTAL_FREQ_26M:
/* 50 MHz = 26MHz * (4 + 15 + 118 / 256 + 39/65536) / ((3 + 2) * 2) = 49.999992 */
/* sdm0 = 39, sdm1 = 118, sdm2 = 15, o_div = 3 */
// 50 MHz = 26MHz * (4 + 15 + 118 / 256 + 39/65536) / ((3 + 2) * 2) = 49.999992
// sdm0 = 39, sdm1 = 118, sdm2 = 15, o_div = 3
rtc_clk_apll_enable(true, 39, 118, 15, 3);
break;
case RTC_XTAL_FREQ_24M:
/* 50 MHz = 24MHz * (4 + 12 + 255 / 256 + 255/65536) / ((2 + 2) * 2) = 49.499977 */
/* sdm0 = 255, sdm1 = 255, sdm2 = 12, o_div = 2 */
// 50 MHz = 24MHz * (4 + 12 + 255 / 256 + 255/65536) / ((2 + 2) * 2) = 49.499977
// sdm0 = 255, sdm1 = 255, sdm2 = 12, o_div = 2
rtc_clk_apll_enable(true, 255, 255, 12, 2);
break;
default: // Assume we have a 40M xtal
@ -82,8 +83,10 @@ static void emac_config_apll_clock(void)
break;
}
}
*/
#endif
/*
static esp_err_t on_lowlevel_init_done(esp_eth_handle_t eth_handle){
#if CONFIG_IDF_TARGET_ESP32
if(eth_clock_mode > ETH_CLOCK_GPIO17_OUT){
@ -123,7 +126,7 @@ static esp_err_t on_lowlevel_init_done(esp_eth_handle_t eth_handle){
//gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_EMAC_TX_CLK);
//PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[0]);
pinMode(0, INPUT);
pinMode(0, FUNCTION_6);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[0], 5);
EMAC_EXT.ex_clk_ctrl.ext_en = 1;
EMAC_EXT.ex_clk_ctrl.int_en = 0;
EMAC_EXT.ex_oscclk_conf.clk_sel = 1;
@ -135,7 +138,7 @@ static esp_err_t on_lowlevel_init_done(esp_eth_handle_t eth_handle){
//gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
//PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[0]);
pinMode(0, OUTPUT);
pinMode(0, FUNCTION_2);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[0], 1);
// Choose the APLL clock to output on GPIO
REG_WRITE(PIN_CTRL, 6);
#endif
@ -145,7 +148,7 @@ static esp_err_t on_lowlevel_init_done(esp_eth_handle_t eth_handle){
//gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_EMAC_CLK_OUT);
//PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[16]);
pinMode(16, OUTPUT);
pinMode(16, FUNCTION_6);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[16], 5);
#endif
} else if(eth_clock_mode == ETH_CLOCK_GPIO17_OUT){
#if CONFIG_ETH_RMII_CLK_OUT_GPIO != 17
@ -153,7 +156,7 @@ static esp_err_t on_lowlevel_init_done(esp_eth_handle_t eth_handle){
//gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO17_U, FUNC_GPIO17_EMAC_CLK_OUT_180);
//PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[17]);
pinMode(17, OUTPUT);
pinMode(17, FUNCTION_6);
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[17], 5);
#endif
}
#if CONFIG_ETH_RMII_CLK_INPUT
@ -168,7 +171,7 @@ static esp_err_t on_lowlevel_init_done(esp_eth_handle_t eth_handle){
#endif
return ESP_OK;
}
*/
/**
@ -404,7 +407,7 @@ bool ETHClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, I
esp_err_t err = ESP_OK;
tcpip_adapter_ip_info_t info;
if(local_ip != (uint32_t)0x00000000 && local_ip != INADDR_NONE){
if(static_cast<uint32_t>(local_ip) != 0){
info.ip.addr = static_cast<uint32_t>(local_ip);
info.gw.addr = static_cast<uint32_t>(gateway);
info.netmask.addr = static_cast<uint32_t>(subnet);
@ -440,13 +443,13 @@ bool ETHClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, I
ip_addr_t d;
d.type = IPADDR_TYPE_V4;
if(dns1 != (uint32_t)0x00000000 && dns1 != INADDR_NONE) {
if(static_cast<uint32_t>(dns1) != 0) {
// Set DNS1-Server
d.u_addr.ip4.addr = static_cast<uint32_t>(dns1);
dns_setserver(0, &d);
}
if(dns2 != (uint32_t)0x00000000 && dns2 != INADDR_NONE) {
if(static_cast<uint32_t>(dns2) != 0) {
// Set DNS2-Server
d.u_addr.ip4.addr = static_cast<uint32_t>(dns2);
dns_setserver(1, &d);

View File

@ -130,6 +130,15 @@ size_t File::size() const
return _p->size();
}
bool File::setBufferSize(size_t size)
{
if (!*this) {
return 0;
}
return _p->setBufferSize(size);
}
void File::close()
{
if (_p) {

View File

@ -70,6 +70,7 @@ public:
}
size_t position() const;
size_t size() const;
bool setBufferSize(size_t size);
void close();
operator bool() const;
time_t getLastWrite();

View File

@ -36,6 +36,7 @@ public:
virtual bool seek(uint32_t pos, SeekMode mode) = 0;
virtual size_t position() const = 0;
virtual size_t size() const = 0;
virtual bool setBufferSize(size_t size) = 0;
virtual void close() = 0;
virtual time_t getLastWrite() = 0;
virtual const char* path() const = 0;

View File

@ -13,11 +13,10 @@
// limitations under the License.
#include "vfs_api.h"
#include <stdio_ext.h>
using namespace fs;
#define READ_SIZE_SWITCH 128 //swithc to read func when read size > 128bytes
#define DEFAULT_FILE_BUFFER_SIZE 4096
FileImplPtr VFSImpl::open(const char* fpath, const char* mode, const bool create)
{
@ -283,6 +282,10 @@ VFSFileImpl::VFSFileImpl(VFSImpl* fs, const char* fpath, const char* mode)
if(!_f) {
log_e("fopen(%s) failed", temp);
}
if(_f && (_stat.st_blksize == 0))
{
setvbuf(_f,NULL,_IOFBF,DEFAULT_FILE_BUFFER_SIZE);
}
} else if(S_ISDIR(_stat.st_mode)) {
_isDirectory = true;
_d = opendir(temp);
@ -310,6 +313,10 @@ VFSFileImpl::VFSFileImpl(VFSImpl* fs, const char* fpath, const char* mode)
if(!_f) {
log_e("fopen(%s) failed", temp);
}
if(_f && (_stat.st_blksize == 0))
{
setvbuf(_f,NULL,_IOFBF,DEFAULT_FILE_BUFFER_SIZE);
}
}
}
free(temp);
@ -377,28 +384,7 @@ size_t VFSFileImpl::read(uint8_t* buf, size_t size)
return 0;
}
//ERASE BYTEBUFFER and use read when size > READ_SIZE_SWITCH always
if(size > READ_SIZE_SWITCH)
{
//check some data in buffer exists > clear buffer and move pointer to deleted data
size_t bytesinbuf = __fpending(_f);
if (bytesinbuf && (bytesinbuf != 128)) //buffer lenght is 128 bytes
{
fpurge(_f);
lseek(fileno(_f),(-128+bytesinbuf),SEEK_CUR);
}
int res = ::read(fileno(_f), buf, size);
if (res < 0) {
// an error occurred
return 0;
}
return res;
}
else
{
return fread(buf, 1, size, _f);
}
return fread(buf, 1, size, _f);
}
void VFSFileImpl::flush()
@ -439,6 +425,19 @@ size_t VFSFileImpl::size() const
return _stat.st_size;
}
/*
* Change size of files internal buffer used for read / write operations.
* Need to be called right after opening file before any other operation!
*/
bool VFSFileImpl::setBufferSize(size_t size)
{
if(_isDirectory || !_f) {
return 0;
}
int res = setvbuf(_f,NULL,_IOFBF,size);
return res == 0;
}
const char* VFSFileImpl::path() const
{
return (const char*) _path;

View File

@ -65,10 +65,11 @@ public:
bool seek(uint32_t pos, SeekMode mode) override;
size_t position() const override;
size_t size() const override;
bool setBufferSize(size_t size);
void close() override;
const char* path() const override;
const char* name() const override;
time_t getLastWrite() override;
time_t getLastWrite() override;
boolean isDirectory(void) override;
FileImplPtr openNextFile(const char* mode) override;
void rewindDirectory(void) override;

View File

@ -276,7 +276,7 @@ protected:
/// request handling
String _host;
uint16_t _port = 0;
int32_t _connectTimeout = -1;
int32_t _connectTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
bool _reuse = true;
uint16_t _tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
bool _useHTTP10 = false;

View File

@ -988,7 +988,6 @@ void I2SClass::_post_read_data_fix(void *input, size_t *size){
// bytes_written - number of bytes used from original buffer
// actual_bytes_written - number of bytes written by i2s_write after fix
void I2SClass::_fix_and_write(void *output, size_t size, size_t *bytes_written, size_t *actual_bytes_written){
long start = millis();
ulong src_ptr = 0;
uint8_t* buff = NULL;
size_t buff_size = size;

View File

@ -1,2 +1,2 @@
Import("env")
env.Replace( MKSPIFFSTOOL=env.get("PROJECT_DIR") + '/mklittlefs' )
env.Replace( MKSPIFFSTOOL=env.get("PROJECT_DIR") + '/mklittlefs' ) # PlatformIO now believes it has actually created a SPIFFS

View File

@ -16,17 +16,6 @@ framework = arduino
[env:esp32]
platform = espressif32
;platform = https://github.com/platformio/platform-espressif32.git
;board_build.mcu = esp32
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git
build_flags =
${env.build_flags}
-D=${PIOENV}
;-D CONFIG_LITTLEFS_FOR_IDF_3_2
lib_deps = https://github.com/lorol/LITTLEFS.git
board = esp32dev
;board_build.partitions = partitions_custom.csv
monitor_filters = esp32_exception_decoder

View File

@ -1,10 +1,13 @@
# ESP RainMaker Examples
While building any examples for ESP RainMaker, take care of the following:
1. Change partition scheme in Arduino IDE to RainMaker (Tools -> Partition Scheme -> RainMaker).
2. Once ESP RainMaker gets started, compulsorily call `WiFi.beginProvision()` which is responsible for user-node mapping.
3. Use appropriate provisioning scheme as per the board.
3. Use the appropriate provisioning scheme as per the board.
- ESP32 Board: BLE Provisioning
- ESP32S2 Board: SoftAP Provisioning
4. Set debug level to Info (Tools -> Core Debug Level -> Info). This is recommended, but not mandatory.
- ESP32-C3 Board: BLE Provisioning
- ESP32-S3 Board: BLE Provisioning
- ESP32-S2 Board: SoftAP Provisioning
4. Set debug level to Info (Tools -> Core Debug Level -> Info). This is recommended debug level but not mandatory to run RainMaker.

View File

@ -9,10 +9,15 @@ const char *service_name = "PROV_1234";
const char *pop = "abcd1234";
//GPIO for push button
static int gpio_0 = 0;
#if CONFIG_IDF_TARGET_ESP32C3
static int gpio_0 = 9;
static int gpio_dimmer = 7;
#else
//GPIO for virtual device
static int gpio_0 = 0;
static int gpio_dimmer = 16;
/* Variable for reading pin status*/
#endif
bool dimmer_state = true;
// The framework provides some standard device types like switch, lightbulb, fan, temperature sensor.
@ -23,14 +28,15 @@ void sysProvEvent(arduino_event_t *sys_event)
{
switch (sys_event->event_id) {
case ARDUINO_EVENT_PROV_START:
#if CONFIG_IDF_TARGET_ESP32
Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", service_name, pop);
printQR(service_name, pop, "ble");
#else
#if CONFIG_IDF_TARGET_ESP32S2
Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on SoftAP\n", service_name, pop);
printQR(service_name, pop, "softap");
#else
Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", service_name, pop);
printQR(service_name, pop, "ble");
#endif
break;
default:;
}
}
@ -89,10 +95,10 @@ void setup()
RMaker.start();
WiFi.onEvent(sysProvEvent);
#if CONFIG_IDF_TARGET_ESP32
WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name);
#else
#if CONFIG_IDF_TARGET_ESP32S2
WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name);
#else
WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name);
#endif
}

View File

@ -50,6 +50,7 @@ void sysProvEvent(arduino_event_t *sys_event)
Serial.printf("\nConnected to Wi-Fi!\n");
digitalWrite(gpio_led, true);
break;
default:;
}
}

View File

@ -8,9 +8,15 @@ const char *service_name = "PROV_1234";
const char *pop = "abcd1234";
//GPIO for push button
static int gpio_0 = 0;
#if CONFIG_IDF_TARGET_ESP32C3
static int gpio_0 = 9;
static int gpio_switch = 7;
#else
//GPIO for virtual device
static int gpio_0 = 0;
static int gpio_switch = 16;
#endif
/* Variable for reading pin status*/
bool switch_state = true;
@ -21,14 +27,15 @@ void sysProvEvent(arduino_event_t *sys_event)
{
switch (sys_event->event_id) {
case ARDUINO_EVENT_PROV_START:
#if CONFIG_IDF_TARGET_ESP32
Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", service_name, pop);
printQR(service_name, pop, "ble");
#else
#if CONFIG_IDF_TARGET_ESP32S2
Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on SoftAP\n", service_name, pop);
printQR(service_name, pop, "softap");
#endif
#else
Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", service_name, pop);
printQR(service_name, pop, "ble");
#endif
break;
default:;
}
}
@ -74,10 +81,10 @@ void setup()
RMaker.start();
WiFi.onEvent(sysProvEvent);
#if CONFIG_IDF_TARGET_ESP32
WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name);
#else
#if CONFIG_IDF_TARGET_ESP32S2
WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name);
#else
WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name);
#endif
}

View File

@ -0,0 +1,21 @@
#include "RMakerQR.h"
#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK
void printQR(const char *name, const char *pop, const char *transport)
{
if (!name || !pop || !transport) {
log_w("Cannot generate QR code payload. Data missing.");
return;
}
char payload[150];
snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
",\"pop\":\"%s\",\"transport\":\"%s\"}",
PROV_QR_VERSION, name, pop, transport);
if(Serial){
Serial.printf("Scan this QR code from the ESP RainMaker phone app.\n");
}
qrcode_display(payload);
if(Serial){
Serial.printf("If QR code is not visible, copy paste the below URL in a browser.\n%s?data=%s\n", QRCODE_BASE_URL, payload);
}
}
#endif

View File

@ -14,24 +14,12 @@
#pragma once
#include "sdkconfig.h"
#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK
#include "RMaker.h"
#include "esp_system.h"
#include <qrcode.h>
#define PROV_QR_VERSION "v1"
#define QRCODE_BASE_URL "https://rainmaker.espressif.com/qrcode.html"
static void printQR(const char *name, const char *pop, const char *transport)
{
if (!name || !pop || !transport) {
log_w("Cannot generate QR code payload. Data missing.");
return;
}
char payload[150];
snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
",\"pop\":\"%s\",\"transport\":\"%s\"}",
PROV_QR_VERSION, name, pop, transport);
Serial.printf("Scan this QR code from the ESP RainMaker phone app.\n");
qrcode_display(payload);
Serial.printf("If QR code is not visible, copy paste the below URL in a browser.\n%s?data=%s\n", QRCODE_BASE_URL, payload);
}
void printQR(const char *name, const char *pop, const char *transport);
#endif

View File

@ -0,0 +1,12 @@
#include "RMakerUtils.h"
#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK
void RMakerFactoryReset(int seconds)
{
esp_rmaker_factory_reset(0, seconds);
}
void RMakerWiFiReset(int seconds)
{
esp_rmaker_wifi_reset(0, seconds);
}
#endif

View File

@ -14,16 +14,10 @@
#pragma once
#include "sdkconfig.h"
#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK
#include "RMaker.h"
#include "esp_system.h"
#include <esp_rmaker_utils.h>
static void RMakerFactoryReset(int seconds)
{
esp_rmaker_factory_reset(0, seconds);
}
static void RMakerWiFiReset(int seconds)
{
esp_rmaker_wifi_reset(0, seconds);
}
void RMakerFactoryReset(int seconds);
void RMakerWiFiReset(int seconds);
#endif

View File

@ -801,8 +801,13 @@ bool sdcard_mount(uint8_t pdrv, const char* path, uint8_t max_files, bool format
if (res != FR_OK) {
log_e("f_mount failed: %s", fferr2str[res]);
if(res == 13 && format_if_empty){
BYTE work[FF_MAX_SS];
BYTE* work = (BYTE*) malloc(sizeof(BYTE) * FF_MAX_SS);
if (!work) {
log_e("alloc for f_mkfs failed");
return false;
}
res = f_mkfs(drv, FM_ANY, 0, work, sizeof(work));
free(work);
if (res != FR_OK) {
log_e("f_mkfs failed: %s", fferr2str[res]);
esp_vfs_fat_unregister_path(path);

View File

@ -20,6 +20,15 @@
*/
#include "SPI.h"
#include "esp32-hal-log.h"
#if !CONFIG_DISABLE_HAL_LOCKS
#define SPI_PARAM_LOCK() do {} while (xSemaphoreTake(paramLock, portMAX_DELAY) != pdPASS)
#define SPI_PARAM_UNLOCK() xSemaphoreGive(paramLock)
#else
#define SPI_PARAM_LOCK()
#define SPI_PARAM_UNLOCK()
#endif
SPIClass::SPIClass(uint8_t spi_bus)
:_spi_num(spi_bus)
@ -32,7 +41,31 @@ SPIClass::SPIClass(uint8_t spi_bus)
,_div(0)
,_freq(1000000)
,_inTransaction(false)
#if !CONFIG_DISABLE_HAL_LOCKS
,paramLock(NULL)
{
if(paramLock==NULL){
paramLock = xSemaphoreCreateMutex();
if(paramLock==NULL){
log_e("xSemaphoreCreateMutex failed");
return;
}
}
}
#else
{}
#endif
SPIClass::~SPIClass()
{
end();
#if !CONFIG_DISABLE_HAL_LOCKS
if(paramLock!=NULL){
vSemaphoreDelete(paramLock);
paramLock = NULL;
}
#endif
}
void SPIClass::begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
{
@ -106,6 +139,7 @@ void SPIClass::setHwCs(bool use)
void SPIClass::setFrequency(uint32_t freq)
{
SPI_PARAM_LOCK();
//check if last freq changed
uint32_t cdiv = spiGetClockDiv(_spi);
if(_freq != freq || _div != cdiv) {
@ -113,12 +147,15 @@ void SPIClass::setFrequency(uint32_t freq)
_div = spiFrequencyToClockDiv(_freq);
spiSetClockDiv(_spi, _div);
}
SPI_PARAM_UNLOCK();
}
void SPIClass::setClockDivider(uint32_t clockDiv)
{
SPI_PARAM_LOCK();
_div = clockDiv;
spiSetClockDiv(_spi, _div);
SPI_PARAM_UNLOCK();
}
uint32_t SPIClass::getClockDivider()
@ -138,6 +175,7 @@ void SPIClass::setBitOrder(uint8_t bitOrder)
void SPIClass::beginTransaction(SPISettings settings)
{
SPI_PARAM_LOCK();
//check if last freq changed
uint32_t cdiv = spiGetClockDiv(_spi);
if(_freq != settings._clock || _div != cdiv) {
@ -153,6 +191,7 @@ void SPIClass::endTransaction()
if(_inTransaction){
_inTransaction = false;
spiEndTransaction(_spi);
SPI_PARAM_UNLOCK(); // <-- Im not sure should it be here or right after spiTransaction()
}
}
@ -226,9 +265,9 @@ void SPIClass::writeBytes(const uint8_t * data, uint32_t size)
spiEndTransaction(_spi);
}
void SPIClass::transfer(uint8_t * data, uint32_t size)
void SPIClass::transfer(void * data, uint32_t size)
{
transferBytes(data, data, size);
transferBytes((const uint8_t *)data, (uint8_t *)data, size);
}
/**

View File

@ -24,6 +24,8 @@
#include <stdlib.h>
#include "pins_arduino.h"
#include "esp32-hal-spi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#define SPI_HAS_TRANSACTION
@ -50,10 +52,14 @@ private:
uint32_t _div;
uint32_t _freq;
bool _inTransaction;
#if !CONFIG_DISABLE_HAL_LOCKS
SemaphoreHandle_t paramLock=NULL;
#endif
void writePattern_(const uint8_t * data, uint8_t size, uint8_t repeat);
public:
SPIClass(uint8_t spi_bus=HSPI);
~SPIClass();
void begin(int8_t sck=-1, int8_t miso=-1, int8_t mosi=-1, int8_t ss=-1);
void end();
@ -67,7 +73,7 @@ public:
void beginTransaction(SPISettings settings);
void endTransaction(void);
void transfer(uint8_t * data, uint32_t size);
void transfer(void * data, uint32_t size);
uint8_t transfer(uint8_t data);
uint16_t transfer16(uint16_t data);
uint32_t transfer32(uint32_t data);

View File

@ -58,5 +58,6 @@ void Ticker::detach() {
}
bool Ticker::active() {
if (!_timer) return false;
return esp_timer_is_active(_timer);
}

View File

@ -20,7 +20,7 @@ static void vendorEventCallback(void* arg, esp_event_base_t event_base, int32_t
case ARDUINO_USB_HID_VENDOR_SET_FEATURE_EVENT:
Serial.printf("HID VENDOR SET FEATURE: len:%u\n", data->len);
for(uint16_t i=0; i<data->len; i++){
Serial.printf("0x%02X ",data->buffer);
Serial.printf("0x%02X ",*(data->buffer));
}
Serial.println();
break;

View File

@ -42,7 +42,9 @@ static bool tinyusb_hid_is_initialized = false;
static uint8_t tinyusb_loaded_hid_devices_num = 0;
static uint16_t tinyusb_hid_device_descriptor_len = 0;
static uint8_t * tinyusb_hid_device_descriptor = NULL;
static const char * tinyusb_hid_device_report_types[4] = {"INVALID", "INPUT", "OUTPUT", "FEATURE"};
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
static const char * tinyusb_hid_device_report_types[4] = {"INVALID", "INPUT", "OUTPUT", "FEATURE"};
#endif
static bool tinyusb_enable_hid_device(uint16_t descriptor_len, USBHIDDevice * device){
if(tinyusb_hid_is_initialized){

View File

@ -274,7 +274,6 @@ size_t USBHIDKeyboard::releaseRaw(uint8_t k)
// call release(), releaseAll(), or otherwise clear the report and resend.
size_t USBHIDKeyboard::press(uint8_t k)
{
uint8_t i;
if (k >= 0x88) { // it's a non-printing key (not a modifier)
k = k - 0x88;
} else if (k >= 0x80) { // it's a modifier key
@ -298,7 +297,6 @@ size_t USBHIDKeyboard::press(uint8_t k)
// it shouldn't be repeated any more.
size_t USBHIDKeyboard::release(uint8_t k)
{
uint8_t i;
if (k >= 0x88) { // it's a non-printing key (not a modifier)
k = k - 0x88;
} else if (k >= 0x80) { // it's a modifier key

View File

@ -1,3 +1,5 @@
#ifndef HTPSPOTUADATE_H
#define HTPSPOTUADATE_H
#include "esp_http_client.h"
#define HttpEvent_t esp_http_client_event_t
@ -19,3 +21,4 @@ class HttpsOTAUpdateClass {
};
extern HttpsOTAUpdateClass HttpsOTA;
#endif

View File

@ -375,7 +375,7 @@
function createTreeLeaf(path, name, size){
var leaf = document.createElement("li");
leaf.id = (((path == "/")?"":path)+"/"+name).toLowerCase();
leaf.id = name.toLowerCase();
var label = document.createElement("span");
label.textContent = name.toLowerCase();
leaf.appendChild(label);
@ -398,7 +398,7 @@
var leaf = document.createElement("li");
var check = document.createElement("input");
check.type = "checkbox";
check.id = (((path == "/")?"":path)+"/"+name).toLowerCase();
check.id = name.toLowerCase();
if(typeof disabled !== "undefined" && disabled) check.disabled = "disabled";
leaf.appendChild(check);
var label = document.createElement("label");

View File

@ -430,12 +430,32 @@ void WebServer::send(int code, const char* content_type, const String& content)
// Can we asume the following?
//if(code == 200 && content.length() == 0 && _contentLength == CONTENT_LENGTH_NOT_SET)
// _contentLength = CONTENT_LENGTH_UNKNOWN;
if (content.length() == 0) {
log_w("content length is zero");
}
_prepareHeader(header, code, content_type, content.length());
_currentClientWrite(header.c_str(), header.length());
if(content.length())
sendContent(content);
}
void WebServer::send(int code, char* content_type, const String& content) {
send(code, (const char*)content_type, content);
}
void WebServer::send(int code, const String& content_type, const String& content) {
send(code, (const char*)content_type.c_str(), content);
}
void WebServer::send(int code, const char* content_type, const char* content)
{
const String passStr = (String)content;
if (strlen(content) != passStr.length()) {
log_e("String cast failed. Use send_P for long arrays");
}
send(code, content_type, passStr);
}
void WebServer::send_P(int code, PGM_P content_type, PGM_P content) {
size_t contentLength = 0;
@ -460,14 +480,6 @@ void WebServer::send_P(int code, PGM_P content_type, PGM_P content, size_t conte
sendContent_P(content, contentLength);
}
void WebServer::send(int code, char* content_type, const String& content) {
send(code, (const char*)content_type, content);
}
void WebServer::send(int code, const String& content_type, const String& content) {
send(code, (const char*)content_type.c_str(), content);
}
void WebServer::sendContent(const String& content) {
sendContent(content.c_str(), content.length());
}

View File

@ -120,6 +120,8 @@ public:
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, const char* content_type, const char* content);
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);

View File

@ -18,7 +18,7 @@
void setup()
{
bool err = ESP_FAIL;
bool err = false;
Serial.begin(115200);
// Set WiFi to station mode and disconnect from an AP if it was previously connected
@ -36,7 +36,7 @@ void setup()
* https://docs.espressif.com/projects/arduino-esp32/en/latest/api/wifi.html
*/
if(err == ESP_FAIL) {
if(err == false) {
Serial.println("Dual Antenna configuration failed!");
} else {
Serial.println("Dual Antenna configuration successfuly done!");

View File

@ -3,7 +3,7 @@ version=2.0.0
author=Hristo Gochkov
maintainer=Hristo Gochkov <hristo@espressif.com>
sentence=Enables network connection (local and Internet) using the ESP32 built-in WiFi.
paragraph=With this library you can instantiate Servers, Clients and send/receive UDP packets through WiFi. The shield can connect either to open or encrypted networks (WEP, WPA). The IP address can be assigned statically or through a DHCP. The library can also manage DNS.
paragraph=With this library you can instantiate Servers, Clients and send/receive UDP packets through WiFi. The shield can connect either to open or encrypted networks. The IP address can be assigned statically or through a DHCP. The library can also manage DNS.
category=Communication
url=
architectures=esp32

View File

@ -47,7 +47,7 @@ extern "C" {
// -----------------------------------------------------------------------------------------------------------------------
esp_netif_t* get_esp_interface_netif(esp_interface_t interface);
esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPAddress(), IPAddress gateway=IPAddress(), IPAddress subnet=IPAddress());
esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=INADDR_NONE, IPAddress gateway=INADDR_NONE, IPAddress subnet=INADDR_NONE, IPAddress dhcp_lease_start=INADDR_NONE);
static bool softap_config_equal(const wifi_config_t& lhs, const wifi_config_t& rhs);
static size_t _wifi_strncpy(char * dst, const char * src, size_t dst_len){
@ -195,7 +195,7 @@ String WiFiAPClass::softAPSSID() const
* @param gateway gateway IP
* @param subnet subnet mask
*/
bool WiFiAPClass::softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet)
bool WiFiAPClass::softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dhcp_lease_start)
{
esp_err_t err = ESP_OK;
@ -204,7 +204,7 @@ bool WiFiAPClass::softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress
return false;
}
err = set_esp_interface_ip(ESP_IF_WIFI_AP, local_ip, gateway, subnet);
err = set_esp_interface_ip(ESP_IF_WIFI_AP, local_ip, gateway, subnet, dhcp_lease_start);
return err == ESP_OK;
}

View File

@ -38,7 +38,7 @@ class WiFiAPClass
public:
bool softAP(const char* ssid, const char* passphrase = NULL, int channel = 1, int ssid_hidden = 0, int max_connection = 4, bool ftm_responder = false);
bool softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet);
bool softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dhcp_lease_start = INADDR_NONE);
bool softAPdisconnect(bool wifioff = false);
uint8_t softAPgetStationNum();

View File

@ -175,11 +175,11 @@ public:
}
};
WiFiClient::WiFiClient():_connected(false),next(NULL)
WiFiClient::WiFiClient():_connected(false),_timeout(WIFI_CLIENT_DEF_CONN_TIMEOUT_MS),next(NULL)
{
}
WiFiClient::WiFiClient(int fd):_connected(true),next(NULL)
WiFiClient::WiFiClient(int fd):_connected(true),_timeout(WIFI_CLIENT_DEF_CONN_TIMEOUT_MS),next(NULL)
{
clientSocketHandle.reset(new WiFiClientSocketHandle(fd));
_rxBuffer.reset(new WiFiClientRxBuffer(fd));
@ -208,10 +208,11 @@ void WiFiClient::stop()
int WiFiClient::connect(IPAddress ip, uint16_t port)
{
return connect(ip,port,WIFI_CLIENT_DEF_CONN_TIMEOUT_MS);
}
int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout )
return connect(ip,port,_timeout);
}
int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout)
{
_timeout = timeout;
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
log_e("socket: %d", errno);
@ -229,8 +230,8 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
struct timeval tv;
FD_ZERO(&fdset);
FD_SET(sockfd, &fdset);
tv.tv_sec = 0;
tv.tv_usec = timeout * 1000;
tv.tv_sec = _timeout / 1000;
tv.tv_usec = 0;
#ifdef ESP_IDF_VERSION_MAJOR
int res = lwip_connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
@ -243,13 +244,13 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
return 0;
}
res = select(sockfd + 1, nullptr, &fdset, nullptr, timeout<0 ? nullptr : &tv);
res = select(sockfd + 1, nullptr, &fdset, nullptr, _timeout<0 ? nullptr : &tv);
if (res < 0) {
log_e("select on fd %d, errno: %d, \"%s\"", sockfd, errno, strerror(errno));
close(sockfd);
return 0;
} else if (res == 0) {
log_i("select returned due to timeout %d ms for fd %d", timeout, sockfd);
log_i("select returned due to timeout %d ms for fd %d", _timeout, sockfd);
close(sockfd);
return 0;
} else {
@ -270,18 +271,28 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
}
}
#define ROE_WIFICLIENT(x,msg) { if (((x)<0)) { log_e("Setsockopt '" msg "'' on fd %d failed. errno: %d, \"%s\"", sockfd, errno, strerror(errno)); return 0; }}
ROE_WIFICLIENT(setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)),"SO_SNDTIMEO");
ROE_WIFICLIENT(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)),"SO_RCVTIMEO");
// These are also set in WiFiClientSecure, should be set here too?
//ROE_WIFICLIENT(setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)),"TCP_NODELAY");
//ROE_WIFICLIENT (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)),"SO_KEEPALIVE");
fcntl( sockfd, F_SETFL, fcntl( sockfd, F_GETFL, 0 ) & (~O_NONBLOCK) );
clientSocketHandle.reset(new WiFiClientSocketHandle(sockfd));
_rxBuffer.reset(new WiFiClientRxBuffer(sockfd));
_connected = true;
return 1;
}
int WiFiClient::connect(const char *host, uint16_t port)
{
return connect(host,port,WIFI_CLIENT_DEF_CONN_TIMEOUT_MS);
}
int WiFiClient::connect(const char *host, uint16_t port, int32_t timeout )
return connect(host,port,_timeout);
}
int WiFiClient::connect(const char *host, uint16_t port, int32_t timeout)
{
IPAddress srv((uint32_t)0);
if(!WiFiGenericClass::hostByName(host, srv)){
@ -301,14 +312,20 @@ int WiFiClient::setSocketOption(int option, char* value, size_t len)
int WiFiClient::setTimeout(uint32_t seconds)
{
Client::setTimeout(seconds * 1000);
struct timeval tv;
tv.tv_sec = seconds;
tv.tv_usec = 0;
if(setSocketOption(SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)) < 0) {
return -1;
Client::setTimeout(seconds * 1000); // This should be here?
_timeout = seconds * 1000;
if(fd() >= 0) {
struct timeval tv;
tv.tv_sec = seconds;
tv.tv_usec = 0;
if(setSocketOption(SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)) < 0) {
return -1;
}
return setSocketOption(SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval));
}
else {
return 0;
}
return setSocketOption(SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval));
}
int WiFiClient::setOption(int option, int *value)

View File

@ -42,6 +42,7 @@ protected:
std::shared_ptr<WiFiClientSocketHandle> clientSocketHandle;
std::shared_ptr<WiFiClientRxBuffer> _rxBuffer;
bool _connected;
int _timeout;
public:
WiFiClient *next;

View File

@ -48,6 +48,7 @@ extern "C" {
#include <vector>
#include "sdkconfig.h"
#define _byte_swap32(num) (((num>>24)&0xff) | ((num<<8)&0xff0000) | ((num>>8)&0xff00) | ((num<<24)&0xff000000))
ESP_EVENT_DEFINE_BASE(ARDUINO_EVENTS);
/*
* Private (exposable) methods
@ -82,7 +83,7 @@ esp_err_t set_esp_interface_hostname(esp_interface_t interface, const char * hos
return ESP_FAIL;
}
esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPAddress(), IPAddress gateway=IPAddress(), IPAddress subnet=IPAddress()){
esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPAddress(), IPAddress gateway=IPAddress(), IPAddress subnet=IPAddress(), IPAddress dhcp_lease_start=INADDR_NONE){
esp_netif_t *esp_netif = esp_netifs[interface];
esp_netif_dhcp_status_t status = ESP_NETIF_DHCP_INIT;
esp_netif_ip_info_t info;
@ -138,20 +139,64 @@ esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPA
dhcps_lease_t lease;
lease.enable = true;
uint32_t dhcp_ipaddr = static_cast<uint32_t>(local_ip);
// prevents DHCP lease range to overflow subnet/24 range
// there will be 11 addresses for DHCP to lease
uint8_t leaseStart = (uint8_t)(~subnet[3] - 12);
if ((local_ip[3]) < leaseStart) {
lease.start_ip.addr = dhcp_ipaddr + (1 << 24);
lease.end_ip.addr = dhcp_ipaddr + (11 << 24);
} else {
// make range stay in the begining of the netmask range
dhcp_ipaddr = (dhcp_ipaddr & 0x00FFFFFF);
lease.start_ip.addr = dhcp_ipaddr + (1 << 24);
lease.end_ip.addr = dhcp_ipaddr + (11 << 24);
uint8_t CIDR = WiFiGenericClass::calculateSubnetCIDR(subnet);
log_v("SoftAP: %s | Gateway: %s | DHCP Start: %s | Netmask: %s", local_ip.toString().c_str(), gateway.toString().c_str(), dhcp_lease_start.toString().c_str(), subnet.toString().c_str());
// netmask must have room for at least 12 IP addresses (AP + GW + 10 DHCP Leasing addresses)
// netmask also must be limited to the last 8 bits of IPv4, otherwise this function won't work
// IDF NETIF checks netmask for the 3rd byte: https://github.com/espressif/esp-idf/blob/master/components/esp_netif/lwip/esp_netif_lwip.c#L1857-L1862
if (CIDR > 28 || CIDR < 24) {
log_e("Bad netmask. It must be from /24 to /28 (255.255.255. 0<->240)");
return ESP_FAIL; // ESP_FAIL if initializing failed
}
// The code below is ready for any netmask, not limited to 255.255.255.0
uint32_t netmask = _byte_swap32(info.netmask.addr);
uint32_t ap_ipaddr = _byte_swap32(info.ip.addr);
uint32_t dhcp_ipaddr = _byte_swap32(static_cast<uint32_t>(dhcp_lease_start));
dhcp_ipaddr = dhcp_ipaddr == 0 ? ap_ipaddr + 1 : dhcp_ipaddr;
uint32_t leaseStartMax = ~netmask - 10;
// there will be 10 addresses for DHCP to lease
lease.start_ip.addr = dhcp_ipaddr;
lease.end_ip.addr = lease.start_ip.addr + 10;
// Check if local_ip is in the same subnet as the dhcp leasing range initial address
if ((ap_ipaddr & netmask) != (dhcp_ipaddr & netmask)) {
log_e("The AP IP address (%s) and the DHCP start address (%s) must be in the same subnet",
local_ip.toString().c_str(), IPAddress(_byte_swap32(dhcp_ipaddr)).toString().c_str());
return ESP_FAIL; // ESP_FAIL if initializing failed
}
// prevents DHCP lease range to overflow subnet range
if ((dhcp_ipaddr & ~netmask) >= leaseStartMax) {
// make first DHCP lease addr stay in the begining of the netmask range
lease.start_ip.addr = (dhcp_ipaddr & netmask) + 1;
lease.end_ip.addr = lease.start_ip.addr + 10;
log_w("DHCP Lease out of range - Changing DHCP leasing start to %s", IPAddress(_byte_swap32(lease.start_ip.addr)).toString().c_str());
}
// Check if local_ip is within DHCP range
if (ap_ipaddr >= lease.start_ip.addr && ap_ipaddr <= lease.end_ip.addr) {
log_e("The AP IP address (%s) can't be within the DHCP range (%s -- %s)",
local_ip.toString().c_str(), IPAddress(_byte_swap32(lease.start_ip.addr)).toString().c_str(), IPAddress(_byte_swap32(lease.end_ip.addr)).toString().c_str());
return ESP_FAIL; // ESP_FAIL if initializing failed
}
// Check if gateway is within DHCP range
uint32_t gw_ipaddr = _byte_swap32(info.gw.addr);
bool gw_in_same_subnet = (gw_ipaddr & netmask) == (ap_ipaddr & netmask);
if (gw_in_same_subnet && gw_ipaddr >= lease.start_ip.addr && gw_ipaddr <= lease.end_ip.addr) {
log_e("The GatewayP address (%s) can't be within the DHCP range (%s -- %s)",
gateway.toString().c_str(), IPAddress(_byte_swap32(lease.start_ip.addr)).toString().c_str(), IPAddress(_byte_swap32(lease.end_ip.addr)).toString().c_str());
return ESP_FAIL; // ESP_FAIL if initializing failed
}
// all done, just revert back byte order of DHCP lease range
lease.start_ip.addr = _byte_swap32(lease.start_ip.addr);
lease.end_ip.addr = _byte_swap32(lease.end_ip.addr);
log_v("DHCP Server Range: %s to %s", IPAddress(lease.start_ip.addr).toString().c_str(), IPAddress(lease.end_ip.addr).toString().c_str());
err = tcpip_adapter_dhcps_option(
(tcpip_adapter_dhcp_option_mode_t)TCPIP_ADAPTER_OP_SET,
(tcpip_adapter_dhcp_option_id_t)ESP_NETIF_SUBNET_MASK,
(void*)&info.netmask.addr, sizeof(info.netmask.addr)
);
if(err){
log_e("DHCPS Set Netmask Failed! 0x%04x", err);
return err;
}
log_v("DHCP Server Range: %s to %s", IPAddress(lease.start_ip.addr).toString(), IPAddress(lease.end_ip.addr).toString());
err = tcpip_adapter_dhcps_option(
(tcpip_adapter_dhcp_option_mode_t)TCPIP_ADAPTER_OP_SET,
(tcpip_adapter_dhcp_option_id_t)REQUESTED_IP_ADDRESS,
@ -161,7 +206,6 @@ esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPA
log_e("DHCPS Set Lease Failed! 0x%04x", err);
return err;
}
err = esp_netif_dhcps_start(esp_netif);
if(err){
log_e("DHCPS Start Failed! 0x%04x", err);
@ -195,6 +239,7 @@ esp_err_t set_esp_interface_dns(esp_interface_t interface, IPAddress main_dns=IP
return ESP_OK;
}
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
static const char * auth_mode_str(int authmode)
{
switch (authmode) {
@ -216,11 +261,21 @@ static const char * auth_mode_str(int authmode)
case WIFI_AUTH_WPA2_ENTERPRISE:
return ("WPA2_ENTERPRISE");
break;
case WIFI_AUTH_WPA3_PSK:
return ("WPA3_PSK");
break;
case WIFI_AUTH_WPA2_WPA3_PSK:
return ("WPA2_WPA3_PSK");
break;
case WIFI_AUTH_WAPI_PSK:
return ("WPAPI_PSK");
break;
default:
break;
}
return ("UNKNOWN");
}
#endif
static char default_hostname[32] = {0,};
static const char * get_esp_netif_hostname(){
@ -286,24 +341,32 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
log_v("STA Stopped");
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_STOP;
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_AUTHMODE_CHANGE) {
wifi_event_sta_authmode_change_t * event = (wifi_event_sta_authmode_change_t*)event_data;
log_v("STA Auth Mode Changed: From: %s, To: %s", auth_mode_str(event->old_mode), auth_mode_str(event->new_mode));
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
wifi_event_sta_authmode_change_t * event = (wifi_event_sta_authmode_change_t*)event_data;
log_v("STA Auth Mode Changed: From: %s, To: %s", auth_mode_str(event->old_mode), auth_mode_str(event->new_mode));
#endif
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE;
memcpy(&arduino_event.event_info.wifi_sta_authmode_change, event_data, sizeof(wifi_event_sta_authmode_change_t));
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED) {
wifi_event_sta_connected_t * event = (wifi_event_sta_connected_t*)event_data;
log_v("STA Connected: SSID: %s, BSSID: " MACSTR ", Channel: %u, Auth: %s", event->ssid, MAC2STR(event->bssid), event->channel, auth_mode_str(event->authmode));
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
wifi_event_sta_connected_t * event = (wifi_event_sta_connected_t*)event_data;
log_v("STA Connected: SSID: %s, BSSID: " MACSTR ", Channel: %u, Auth: %s", event->ssid, MAC2STR(event->bssid), event->channel, auth_mode_str(event->authmode));
#endif
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_CONNECTED;
memcpy(&arduino_event.event_info.wifi_sta_connected, event_data, sizeof(wifi_event_sta_connected_t));
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
wifi_event_sta_disconnected_t * event = (wifi_event_sta_disconnected_t*)event_data;
log_v("STA Disconnected: SSID: %s, BSSID: " MACSTR ", Reason: %u", event->ssid, MAC2STR(event->bssid), event->reason);
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
wifi_event_sta_disconnected_t * event = (wifi_event_sta_disconnected_t*)event_data;
log_v("STA Disconnected: SSID: %s, BSSID: " MACSTR ", Reason: %u", event->ssid, MAC2STR(event->bssid), event->reason);
#endif
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_DISCONNECTED;
memcpy(&arduino_event.event_info.wifi_sta_disconnected, event_data, sizeof(wifi_event_sta_disconnected_t));
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
log_v("STA Got %sIP:" IPSTR, event->ip_changed?"New ":"Same ", IP2STR(&event->ip_info.ip));
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_GOT_IP;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
log_v("STA Got %sIP:" IPSTR, event->ip_changed?"New ":"Same ", IP2STR(&event->ip_info.ip));
#endif
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_GOT_IP;
memcpy(&arduino_event.event_info.got_ip, event_data, sizeof(ip_event_got_ip_t));
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_LOST_IP) {
log_v("STA IP Lost");
@ -313,8 +376,10 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
* SCAN
* */
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_SCAN_DONE) {
wifi_event_sta_scan_done_t * event = (wifi_event_sta_scan_done_t*)event_data;
log_v("SCAN Done: ID: %u, Status: %u, Results: %u", event->scan_id, event->status, event->number);
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
wifi_event_sta_scan_done_t * event = (wifi_event_sta_scan_done_t*)event_data;
log_v("SCAN Done: ID: %u, Status: %u, Results: %u", event->scan_id, event->status, event->number);
#endif
arduino_event.event_id = ARDUINO_EVENT_WIFI_SCAN_DONE;
memcpy(&arduino_event.event_info.wifi_scan_done, event_data, sizeof(wifi_event_sta_scan_done_t));
@ -328,24 +393,32 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
log_v("AP Stopped");
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_STOP;
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_PROBEREQRECVED) {
wifi_event_ap_probe_req_rx_t * event = (wifi_event_ap_probe_req_rx_t*)event_data;
log_v("AP Probe Request: RSSI: %d, MAC: " MACSTR, event->rssi, MAC2STR(event->mac));
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
wifi_event_ap_probe_req_rx_t * event = (wifi_event_ap_probe_req_rx_t*)event_data;
log_v("AP Probe Request: RSSI: %d, MAC: " MACSTR, event->rssi, MAC2STR(event->mac));
#endif
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED;
memcpy(&arduino_event.event_info.wifi_ap_probereqrecved, event_data, sizeof(wifi_event_ap_probe_req_rx_t));
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STACONNECTED) {
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
log_v("AP Station Connected: MAC: " MACSTR ", AID: %d", MAC2STR(event->mac), event->aid);
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_STACONNECTED;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
log_v("AP Station Connected: MAC: " MACSTR ", AID: %d", MAC2STR(event->mac), event->aid);
#endif
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_STACONNECTED;
memcpy(&arduino_event.event_info.wifi_ap_staconnected, event_data, sizeof(wifi_event_ap_staconnected_t));
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STADISCONNECTED) {
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
log_v("AP Station Disconnected: MAC: " MACSTR ", AID: %d", MAC2STR(event->mac), event->aid);
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
log_v("AP Station Disconnected: MAC: " MACSTR ", AID: %d", MAC2STR(event->mac), event->aid);
#endif
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_STADISCONNECTED;
memcpy(&arduino_event.event_info.wifi_ap_stadisconnected, event_data, sizeof(wifi_event_ap_stadisconnected_t));
} else if (event_base == IP_EVENT && event_id == IP_EVENT_AP_STAIPASSIGNED) {
ip_event_ap_staipassigned_t * event = (ip_event_ap_staipassigned_t*)event_data;
log_v("AP Station IP Assigned:" IPSTR, IP2STR(&event->ip));
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
ip_event_ap_staipassigned_t * event = (ip_event_ap_staipassigned_t*)event_data;
log_v("AP Station IP Assigned:" IPSTR, IP2STR(&event->ip));
#endif
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED;
memcpy(&arduino_event.event_info.wifi_ap_staipassigned, event_data, sizeof(ip_event_ap_staipassigned_t));
/*
@ -353,7 +426,6 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
* */
} else if (event_base == ETH_EVENT && event_id == ETHERNET_EVENT_CONNECTED) {
log_v("Ethernet Link Up");
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
arduino_event.event_id = ARDUINO_EVENT_ETH_CONNECTED;
memcpy(&arduino_event.event_info.eth_connected, event_data, sizeof(esp_eth_handle_t));
} else if (event_base == ETH_EVENT && event_id == ETHERNET_EVENT_DISCONNECTED) {
@ -366,9 +438,11 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
log_v("Ethernet Stopped");
arduino_event.event_id = ARDUINO_EVENT_ETH_STOP;
} else if (event_base == IP_EVENT && event_id == IP_EVENT_ETH_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
log_v("Ethernet got %sip:" IPSTR, event->ip_changed?"new":"", IP2STR(&event->ip_info.ip));
arduino_event.event_id = ARDUINO_EVENT_ETH_GOT_IP;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
log_v("Ethernet got %sip:" IPSTR, event->ip_changed?"new":"", IP2STR(&event->ip_info.ip));
#endif
arduino_event.event_id = ARDUINO_EVENT_ETH_GOT_IP;
memcpy(&arduino_event.event_info.got_ip, event_data, sizeof(ip_event_got_ip_t));
/*
@ -393,13 +467,11 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_WPS_ER_SUCCESS) {
arduino_event.event_id = ARDUINO_EVENT_WPS_ER_SUCCESS;
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_WPS_ER_FAILED) {
wifi_event_sta_wps_fail_reason_t * event = (wifi_event_sta_wps_fail_reason_t*)event_data;
arduino_event.event_id = ARDUINO_EVENT_WPS_ER_FAILED;
memcpy(&arduino_event.event_info.wps_fail_reason, event_data, sizeof(wifi_event_sta_wps_fail_reason_t));
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_WPS_ER_TIMEOUT) {
arduino_event.event_id = ARDUINO_EVENT_WPS_ER_TIMEOUT;
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_WPS_ER_PIN) {
wifi_event_sta_wps_er_pin_t * event = (wifi_event_sta_wps_er_pin_t*)event_data;
arduino_event.event_id = ARDUINO_EVENT_WPS_ER_PIN;
memcpy(&arduino_event.event_info.wps_er_pin, event_data, sizeof(wifi_event_sta_wps_er_pin_t));
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_WPS_ER_PBC_OVERLAP) {
@ -409,7 +481,6 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
* FTM
* */
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_FTM_REPORT) {
wifi_event_ftm_report_t * event = (wifi_event_ftm_report_t*)event_data;
arduino_event.event_id = ARDUINO_EVENT_WIFI_FTM_REPORT;
memcpy(&arduino_event.event_info.wifi_ftm_report, event_data, sizeof(wifi_event_ftm_report_t));
@ -424,8 +495,10 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
log_v("SC Found Channel");
arduino_event.event_id = ARDUINO_EVENT_SC_FOUND_CHANNEL;
} else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) {
smartconfig_event_got_ssid_pswd_t *event = (smartconfig_event_got_ssid_pswd_t *)event_data;
log_v("SC: SSID: %s, Password: %s", (const char *)event->ssid, (const char *)event->password);
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
smartconfig_event_got_ssid_pswd_t *event = (smartconfig_event_got_ssid_pswd_t *)event_data;
log_v("SC: SSID: %s, Password: %s", (const char *)event->ssid, (const char *)event->password);
#endif
arduino_event.event_id = ARDUINO_EVENT_SC_GOT_SSID_PSWD;
memcpy(&arduino_event.event_info.sc_got_ssid_pswd, event_data, sizeof(smartconfig_event_got_ssid_pswd_t));
@ -450,13 +523,17 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
wifi_prov_mgr_deinit();
arduino_event.event_id = ARDUINO_EVENT_PROV_END;
} else if (event_base == WIFI_PROV_EVENT && event_id == WIFI_PROV_CRED_RECV) {
wifi_sta_config_t *event = (wifi_sta_config_t *)event_data;
log_v("Provisioned Credentials: SSID: %s, Password: %s", (const char *) event->ssid, (const char *) event->password);
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
wifi_sta_config_t *event = (wifi_sta_config_t *)event_data;
log_v("Provisioned Credentials: SSID: %s, Password: %s", (const char *) event->ssid, (const char *) event->password);
#endif
arduino_event.event_id = ARDUINO_EVENT_PROV_CRED_RECV;
memcpy(&arduino_event.event_info.prov_cred_recv, event_data, sizeof(wifi_sta_config_t));
} else if (event_base == WIFI_PROV_EVENT && event_id == WIFI_PROV_CRED_FAIL) {
wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data;
log_e("Provisioning Failed: Reason : %s", (*reason == WIFI_PROV_STA_AUTH_ERROR)?"Authentication Failed":"AP Not Found");
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data;
log_e("Provisioning Failed: Reason : %s", (*reason == WIFI_PROV_STA_AUTH_ERROR)?"Authentication Failed":"AP Not Found");
#endif
arduino_event.event_id = ARDUINO_EVENT_PROV_CRED_FAIL;
memcpy(&arduino_event.event_info.prov_fail_reason, event_data, sizeof(wifi_prov_sta_fail_reason_t));
} else if (event_base == WIFI_PROV_EVENT && event_id == WIFI_PROV_CRED_SUCCESS) {
@ -1259,6 +1336,7 @@ bool WiFiGenericClass::setDualAntennaConfig(uint8_t gpio_ant1, uint8_t gpio_ant2
// Set antenna default configuration
wifi_ant_config_t ant_config = {
.rx_ant_mode = WIFI_ANT_MODE_AUTO,
.rx_ant_default = WIFI_ANT_MAX, // Ignored in AUTO mode
.tx_ant_mode = WIFI_ANT_MODE_AUTO,
.enabled_ant0 = 0,
.enabled_ant1 = 1,

View File

@ -51,7 +51,7 @@ extern "C" {
esp_netif_t* get_esp_interface_netif(esp_interface_t interface);
esp_err_t set_esp_interface_dns(esp_interface_t interface, IPAddress main_dns=IPAddress(), IPAddress backup_dns=IPAddress(), IPAddress fallback_dns=IPAddress());
esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPAddress(), IPAddress gateway=IPAddress(), IPAddress subnet=IPAddress());
esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=INADDR_NONE, IPAddress gateway=INADDR_NONE, IPAddress subnet=INADDR_NONE, IPAddress dhcp_lease_start=INADDR_NONE);
static bool sta_config_equal(const wifi_config_t& lhs, const wifi_config_t& rhs);
static size_t _wifi_strncpy(char * dst, const char * src, size_t dst_len){
@ -83,7 +83,7 @@ static bool sta_config_equal(const wifi_config_t& lhs, const wifi_config_t& rhs)
return true;
}
static void wifi_sta_config(wifi_config_t * wifi_config, const char * ssid=NULL, const char * password=NULL, const uint8_t * bssid=NULL, uint8_t channel=0, wifi_scan_method_t scan_method=WIFI_ALL_CHANNEL_SCAN, wifi_sort_method_t sort_method=WIFI_CONNECT_AP_BY_SIGNAL, uint16_t listen_interval=0, bool pmf_required=false){
static void wifi_sta_config(wifi_config_t * wifi_config, const char * ssid=NULL, const char * password=NULL, const uint8_t * bssid=NULL, uint8_t channel=0, wifi_auth_mode_t min_security=WIFI_AUTH_WPA2_PSK, wifi_scan_method_t scan_method=WIFI_ALL_CHANNEL_SCAN, wifi_sort_method_t sort_method=WIFI_CONNECT_AP_BY_SIGNAL, uint16_t listen_interval=0, bool pmf_required=false){
wifi_config->sta.channel = channel;
wifi_config->sta.listen_interval = listen_interval;
wifi_config->sta.scan_method = scan_method;//WIFI_ALL_CHANNEL_SCAN or WIFI_FAST_SCAN
@ -99,7 +99,7 @@ static void wifi_sta_config(wifi_config_t * wifi_config, const char * ssid=NULL,
if(ssid != NULL && ssid[0] != 0){
_wifi_strncpy((char*)wifi_config->sta.ssid, ssid, 32);
if(password != NULL && password[0] != 0){
wifi_config->sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
wifi_config->sta.threshold.authmode = min_security;
_wifi_strncpy((char*)wifi_config->sta.password, password, 64);
}
if(bssid != NULL){
@ -115,6 +115,9 @@ static void wifi_sta_config(wifi_config_t * wifi_config, const char * ssid=NULL,
bool WiFiSTAClass::_autoReconnect = true;
bool WiFiSTAClass::_useStaticIp = false;
wifi_auth_mode_t WiFiSTAClass::_minSecurity = WIFI_AUTH_WPA2_PSK;
wifi_scan_method_t WiFiSTAClass::_scanMethod = WIFI_FAST_SCAN;
wifi_sort_method_t WiFiSTAClass::_sortMethod = WIFI_CONNECT_AP_BY_SIGNAL;
static wl_status_t _sta_status = WL_NO_SHIELD;
static EventGroupHandle_t _sta_status_group = NULL;
@ -243,12 +246,7 @@ wl_status_t WiFiSTAClass::begin(const char* ssid, const char *passphrase, int32_
_wifi_strncpy(reinterpret_cast<char*>(conf.sta.password), passphrase, 64);
}
if(channel == 0) {
// If no specific channel specified, then do an slower WIFI_ALL_CHANNEL_SCAN
wifi_sta_config(&conf, ssid, passphrase, bssid, channel, WIFI_ALL_CHANNEL_SCAN);
}
else
wifi_sta_config(&conf, ssid, passphrase, bssid, channel, WIFI_FAST_SCAN);
wifi_sta_config(&conf, ssid, passphrase, bssid, channel, _minSecurity, _scanMethod, _sortMethod);
wifi_config_t current_conf;
if(esp_wifi_get_config((wifi_interface_t)ESP_IF_WIFI_STA, &current_conf) != ESP_OK){
@ -404,6 +402,37 @@ bool WiFiSTAClass::isConnected()
return (status() == WL_CONNECTED);
}
/**
* Set the minimum security for AP to be considered connectable
* Must be called before WiFi.begin()
* @param minSecurity wifi_auth_mode_t
*/
void WiFiSTAClass::setMinSecurity(wifi_auth_mode_t minSecurity)
{
_minSecurity = minSecurity;
}
/**
* Set the way that AP is chosen.
* First SSID match[WIFI_FAST_SCAN] or Sorted[WIFI_ALL_CHANNEL_SCAN] (RSSI or Security)
* Must be called before WiFi.begin()
* @param scanMethod wifi_scan_method_t
*/
void WiFiSTAClass::setScanMethod(wifi_scan_method_t scanMethod)
{
_scanMethod = scanMethod;
}
/**
* Set the way that AP is sorted. (requires scanMethod WIFI_ALL_CHANNEL_SCAN)
* By SSID[WIFI_CONNECT_AP_BY_SIGNAL] or Security[WIFI_CONNECT_AP_BY_SECURITY]
* Must be called before WiFi.begin()
* @param sortMethod wifi_sort_method_t
*/
void WiFiSTAClass::setSortMethod(wifi_sort_method_t sortMethod)
{
_sortMethod = sortMethod;
}
/**
* Setting the ESP32 station to connect to the AP (which is recorded)

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