Compare commits

...

101 Commits

Author SHA1 Message Date
7df50a97d1 Update IDF to ebdcbe8c6 (#2539)
- ESP-Face to 2937054
- ESP32-Camera to 113629b
2019-03-03 17:19:11 +01:00
566f659e90 Frog Board ESP32 definition (#2515)
* Added board definition

Signed-off-by: Roman Hosek <roman.hosek@iotbakery.com>

* fix typo

* variant + pin definition
2019-03-03 15:53:49 +01:00
cb0a939a6f Adding debug flag to PIO build script (#2510)
Adding the -g3 flag that was omitted in the PIO build script but is present in Arduino IDE build scripts. This flag restores the ability to get line numbers from stack traces for elf files generated in PlatformIO IDE.
2019-03-03 15:51:59 +01:00
cebd8704c8 Default pin remap for wESP32 (#2508)
* Add default pin mapping for Serial1 and Serial2

* Default pin remap on wESP32

Improved default pin mapping for I2C0 and UART1 to avoid issues
with programming.
SDA0 was on IO2 but IO2 needs to be pulled low on reset to enable
serial programming, which conflicts with I2C pull-ups.
RX1 was on IO12, idle UART level is high which conflicts with
IO12 needing to be low on reset to select correct 3.3V flash
voltage.
New mappings:
SDA0 on IO15
RX1 on IO13
TX1 on IO12
2019-03-03 15:51:43 +01:00
ff85f3e90e connect only to provided creds (#2491) 2019-03-03 15:49:59 +01:00
dffda0bd6e log no networks found when scanResult is 0 (#2484) 2019-03-03 15:49:16 +01:00
2ceab7c279 return macaddress (#2477)
* WiFi.macaddress() returns mac address

* change description

* return macaddress when WiFi mode is WIFI_MODE_NULL
2019-03-03 15:48:30 +01:00
84e458a9e1 Add Heltec boards defintion and update board menu chooices (#2475) 2019-03-03 15:47:47 +01:00
f3c1a91f8e adding uartRxActive to expose the RX state machine status as a boolean value (#2457) 2019-03-03 15:47:24 +01:00
5af0336177 Changed the description of file (#2476) 2019-02-20 00:50:20 +02:00
628b8f0c29 Fix Olimex board definition 2019-02-18 12:56:59 +02:00
2bb32bd4b0 Unbiased random (#2468)
* An example to read high frequency analog data using i2s_adc

* Changed random() to use Lemire's method for bounding
2019-02-18 12:18:49 +02:00
89d6b895d1 Fixed missing null terminator in EEPROM.readString(address, value, maxLen) (#2439) 2019-02-14 19:31:37 +01:00
010a7c60f7 Update IDF to abea9e4c0 (#2458)
* Update IDF to abea9e4c0

* Update esptool

* Enable PSRAM for PICO D4

* Enable APP_ROLLBACK_ENABLE
2019-02-14 16:49:30 +01:00
c0345eafbf fix missing the first bit in HC589 shift in (#2448) 2019-02-14 13:11:08 +01:00
71ec3c3e31 Correct millis() error causes by micros() overflow every about 72 minutes (#2438) 2019-02-14 13:09:51 +01:00
8ec76405b9 Fix compile warning, esp32-hal-i2c.c (#2434)
@tread-Qualitrol discovered this error.
2019-02-14 13:09:05 +01:00
8806acfbf9 Added partition menu for OROCA EduBot board. (#2429) 2019-02-14 13:08:28 +01:00
2e9cb5945d default FORMAT_FILESYSTEM to false in FSBrowser.ino (#2425) 2019-02-14 13:06:21 +01:00
c001996eef Add default pin mapping for Serial1 and Serial2 for wESP32 (#2409) 2019-02-14 13:05:23 +01:00
c1344ae094 New version of the ESP32-EVB/Gateway/PoE boards (#2397)
In Board.txt file added board revision submenu to distinguish the different revisions of the same board. By selecting different revision in the Arduino menu different value of the predefined macro will be applied which is used inside the pins_arduino.h file to make different defines and values for the specific revision.
In addition to this esp32-poe pin definitions is added ethernet power enable pin and also defined macro: BOARD_HAS_1BIT_SDMMC
2019-02-14 13:03:34 +01:00
f6b9e9c2ab Clarified comments and debug messages in WiFiClient Example (#2389)
* Clarified comments and debug messages

Made debug messages and comments easier to understand/grammatical fixes

* few more fixes
2019-02-14 12:59:55 +01:00
fc737e08c6 Add connect timeout to WiFiClient (#2383)
* Add timeout to WiFiClient.connect()

* Changed default handling
2019-02-14 12:55:50 +01:00
e302a6848a Board T-Beam: Update pins_arduino.h (#2380)
* Board T-Beam: Update pins_arduino.h

DAC2 is not wired, only DAC1 is -> corrected
LORA pins 27 + 19 are only wired on pcb, but not connected to header -> deleted

* Update pins_arduino.h

Button and LED added
2019-02-14 12:53:45 +01:00
aa2393b573 remove useless condition in if statement (#2371)
* fix log error code format

* remove useless condition in if statement
2019-02-14 12:52:52 +01:00
755cd938f7 add missing EEPROM lib to CMakeLists.txt, moved the EEPROM files to proper dir (#2333)
* add missing EEPROM lib to CMakeLists.txt, moved the EEPROM files to proper directory

* add missing EEPROM lib to CMakeLists.txt, moved the EEPROM files to proper directory
2019-02-14 12:49:34 +01:00
86fdb5b23d Fix compilation errors when used as IDF component 2019-01-26 21:37:03 +01:00
ffd15e4637 fix log error code format (#2366) 2019-01-23 15:33:41 +08:00
29d59876b4 Webserver library - fix logging (#2355) (#2359)
* Webserver fix logging (#1)

* Change logging to use esp32-hal-log.h

fixes #2355

* adjust log parameter output positions, reduce lines

The DEBUG_ESP method used less lines than I originally set `log_v` to use when displaying the details of the received params ("@" and "=" indexes, and File info on a single line)
2019-01-22 17:30:10 +08:00
8cbc60edbc fixed rmt receive data pointer position. (#2353) 2019-01-22 17:29:32 +08:00
00a546ee06 python2 get.py does not work behind proxy (#2349)
Executing python2 get.py behind proxy give error "IOError: [Errno socket error] [SSL: UNKNOWN_PROTOCOL] unknown protocol (_ssl.c:590)"
2019-01-22 17:28:27 +08:00
2ba1e66060 Fix SS pin for Adafruit Feather variant of the ESP32 board (#2344)
Pin 2 is not found on the [Adafruit docs](https://learn.adafruit.com/adafruit-huzzah32-esp32-feather) for this board and 33 was suggested in #1586 as a fix. I've tried this locally on my board and it is working correctly.
2019-01-22 17:27:42 +08:00
489feb8727 Fix BananaPi-BIT and T-Beam pin definitions (#2343)
* Fix BananaPi-BIT DAC definition

* Update t-beam too
2019-01-22 17:27:19 +08:00
3350476d1d I2C debugging and Log Dump Explaination (#2325)
* I2C debugging and Log Dump Explaination

Create a help file for I2C debugging and interpretation of log dumps

* Update i2c_debugging.md

version

* add formatting, file locations
2019-01-22 17:24:51 +08:00
fa6f75952d I2s adc (#2309)
* An example to read high frequency analog data using i2s_adc

* HiFreq_ADC.ino
2019-01-22 17:24:16 +08:00
6718da0350 Add ESP-EYE support to the camera demo 2019-01-22 14:38:24 +08:00
45fa0f8294 Fix issue with WiFi lib sending the wrong event ID when debug is on 2019-01-22 14:37:55 +08:00
6cf307dbd1 Fix copy/paste error in RMT
Fixes: https://github.com/espressif/arduino-esp32/issues/2316
2019-01-14 19:30:07 +08:00
81844f5360 Add API to feed the loop WDT (call from loop only) 2019-01-12 13:02:38 +01:00
f7cf583b87 Update README.md
Add download counter for releases
2019-01-11 10:17:45 +01:00
e8a2c16c8f Update issue templates 2019-01-11 02:21:32 +01:00
9a7946e685 I2C fix READ of zero bytes hardware hang (#2301)
The i2c peripheral will hang if a READ request is issued with a zero data length.  The peripheral
drops into a continuous timeout interrupt response.  The STOP command can not be set out to the I2C
bus. The SLAVE device correctly ACK'd the address byte, with READ bit set, it has control of the SDA
 pin.  The ESP32 send out the next SCL HIGH pulse but, since the SLAVE is in READ Mode, and the First
bit it is sending happened to be a ZERO, the ESP32 cannot send the STOP.  When it releases SDA during
the SCL HIGH, the pin does not change state.  The pin stays low because the SLAVE is outputing a LOW!
The ESP32 drops into a perminent WAIT state waiting for SDA to go HIGH (the STOP).

**esp32-hal-i2c.c**
* add databuff length checks to `i2cRead()` and `i2cWrite()`
2019-01-10 21:37:13 +01:00
566b69eda3 Test @PlatformIO with CameraWebServer example (#2300) 2019-01-10 15:54:12 +01:00
e544e67838 PlatformIO: Revert back default partition table to "default.csv" (#2299) 2019-01-10 15:53:51 +01:00
b0582e1ec8 Fix compilation failing on Windows because of liblib.a 2019-01-10 09:23:25 +01:00
a539257a38 An example to read high frequency analog data using i2s_adc (#2295) 2019-01-10 08:24:17 +01:00
70656aa129 fix leak in log_printf 2019-01-09 21:37:31 +01:00
fa61b3bffe Update IDF to e931fe9 and add esp-face (#2291)
* Update IDF to e931fe9 and add esp-face

* Fix PIO builds fail because of sketch size

* Fix example build failing for Arduino
2019-01-09 19:31:46 +01:00
452c27a74a Added ESP32 FM DevKit - Fixed unused pins definitions. (#2288)
* Added ESP32 FM DevKit

* Added ESP32 FM DevKit variant

Fixed pin definitions for unused pins.
2019-01-09 16:50:41 +01:00
2fd39b1aff Handle APB frequency change (#2250)
* Add APB change callbacks and move cpu code to own file

* Properly set esp_timer and FreeRTOS tick dividers

* Improve updated devisors

* No need to update REF_TICK yet

* Add initial handling for UART baud change

* fix uartWriteBuf and uartDetectBaudrate

* trigger callbacks even when APB did not change

* toggle UART ISR on CPU change

* add XTAL freq getter and add cpu freq validation

* Support CPU frequency changes in I2C (#2287)

**esp32-hal-i2c.c**
* add callback for cpu frequency changes
* adjust fifo thresholds based on cpu frequency and i2c bus frequency
* reduce i2c bus frequency if differential is too small
**Wire.h**
* version to 1.1.0

* Implement clock change for the other peripherals

* remove bad CPU clock values from the menu

* Add note to CPU freqs that support WiFi and BT
2019-01-09 10:07:54 +01:00
ff18a211e4 Add OROCA EduBot Board (#2264) 2019-01-06 21:47:55 +02:00
a6e3b29004 Added support for using TCPIP_ADAPTER_IF_MAX to join igmp groups on all (#2279)
interfaces
2019-01-06 21:29:38 +02:00
812d131663 Correct comment in SPI_Multiple_Buses.ino (#2272)
The default SPI bus is VSPI (see libraries/SPI/src/SPI.cpp). This change corrects a misleading comment in a code example which was stating wrongly that HSPI would be the default one.
2019-01-04 15:26:32 +02:00
00e69a28bc Redo PR #2259 because I messed up my local git (#2263) 2019-01-02 17:44:17 +02:00
229d9b7366 [WiFiClientSecure] Shows only free internal heap on logs (#2252)
* Shows only free internal heap on logs

Since Mbedtls is running only on internal heap, show internal + PSRAM available memory on logs can confuse the users

* Clarify logs
2018-12-31 11:44:57 +02:00
6dd8be3262 Use more agressive disconnect on wifi connect error 2018-12-28 21:23:17 +02:00
28ea39cf05 Add WDT API for Core 0 and disable it while SPIFFS is formatting 2018-12-28 21:14:46 +02:00
f49c854ff3 Update IDF to 97eecfa, enable reboot on WDT and add WDT API (#2248)
* Update IDF to 97eecfa and enable reboot on WDT

* Add API to enable/disable WDT for Core 1 and Arduino Loop
2018-12-28 20:37:33 +02:00
879388e170 Update esp32-hal-gpio.c
fix copy/paste error
2018-12-28 19:14:15 +02:00
1085e9a8f0 Fix bad multiplier calculation 2018-12-24 13:55:08 +02:00
bed9c96f41 update board files for LoPy, LoPy4, T-Beam (#2241)
changed LORA_IO0 -> LORA_IRQ
added LORA_RST
added SS
2018-12-24 13:08:12 +02:00
5af139bb74 HardwareSerial - add changeBaudRate method (#2223)
* Add updateBaudRate to hardware serial

* remove flush

* Fix tab
2018-12-23 21:15:06 +02:00
4f9a90fa0e fix #2232 and #2033 (#2233) 2018-12-23 19:06:43 +02:00
310e78e6fd Support CPU frequency changes (#2222)
The I2C hardware has limitations on min and max bus frequency directly related to CPU frequency, bus speed cannot be greater than 1/100 CPU clock, nor less than CPU clock / 8192.
2018-12-20 08:56:02 +01:00
c827bb4177 CPU and APB Frequency support (#2220)
* Add support to HAL for APB frequencies different than 80MHz

* Add support for CPU frequencies in the IDE board menu

* Switch to fast set_config

* Add method to uart so debug can be reassigned after apb frequency switch

* Return real APB frequency
2018-12-20 01:57:32 +01:00
1628f533a1 Add Camera WebServer Example 2018-12-20 00:41:48 +01:00
3e66aeff84 Handle better 160MHz cpu clock 2018-12-18 22:04:02 +01:00
66d33f792c Add support for CPU Frequency switching
Experimental!
2018-12-18 20:04:16 +01:00
0de0d3f79a move call to setTimeout() to after the client connects. (#2214)
This is necessary to avoid this log entry from being generated due to invalid usage of setTimeout:
[E][WiFiClient.cpp:236] setSocketOption(): 1006 : 9
2018-12-18 19:21:36 +01:00
512d0d088f Add Turta IoT Node Board (#2208) 2018-12-17 23:11:05 +01:00
77810471ce Move Example to proper folder 2018-12-16 19:24:02 +01:00
be081ac026 Add FreeRTOS multi-thread example (#2067)
* Add FreeRTOS exsample

* Update Code

* Change stack size

* Fix LED_BUILTIN not defined

Fix LED_BUILTIN not defined
2018-12-16 18:09:57 +01:00
4d3f6caa0d Add quotes around macro value (Issue #2193) (#2197)
* Replaced ARDUINO_VARIANT with const char

* Fixed missing return value

* Added quotes around defined value in macro (Issue #2193)
2018-12-16 17:10:56 +01:00
2db811f7f3 Update build tools (#2200) 2018-12-16 17:09:44 +01:00
39836f12df correct bounds checking in Print::printf to avoid corner case of len=64 (#2204) 2018-12-16 17:09:26 +01:00
25fd2d0f3b OTA success reporting fix (#2202) 2018-12-16 13:00:15 +01:00
278fa0d87a Fix read(), peek() and available() in WiFiClientSecure
closes: https://github.com/espressif/arduino-esp32/pull/2151
2018-12-15 18:14:38 +01:00
b37f4069e4 Increase _network_event_task priority (#2184)
Fixes https://github.com/espressif/arduino-esp32/issues/1595
2018-12-15 17:39:51 +01:00
e602145c2b fix #2105 (#2192) 2018-12-15 17:39:20 +01:00
6f6ee98188 Update ESP-IDF da2116f + esp32-camera f8f26ab + BLE b232e7f (#2194)
* ESP-IDF da2116f + esp32-camera f8f26ab +BLE b232e7f

* Fix fail compilation due to missing cpp guard
2018-12-15 17:38:34 +01:00
1289f4be4b Add MD5 computation to Esp and add request header with MD5 hash of the running sketch to HTTPUpdate (#2176) 2018-12-11 02:06:58 +01:00
70f000da71 Fix a compilation error if Bluetooth not enabled (#2172) 2018-12-10 10:11:37 +01:00
884e417a49 Fix HTTPUpdate flash size check and add SPIFFS size check (#2161)
* Fix error in PR #2048: if ::available() is called before ::connect() _rxBuffer is not initialised

* Fixed flash size check and added SPIFFS size check

* Rewriting ESP.getFreeSketchSpace(), moving code from HTTPUpdate.cpp
2018-12-06 20:39:52 +01:00
bb7dea1566 Fix missing SS define for D32 Pro
Fixes: https://github.com/espressif/arduino-esp32/issues/2153
2018-12-06 19:13:30 +01:00
bff9f0b6b1 Fix error in PR #2048: if ::available() is called before ::connect() _rxBuffer is not initialised (#2155) 2018-12-06 19:01:06 +01:00
72803703fd Updated table of tested locations of Eduroam network (#2157) 2018-12-06 18:56:48 +01:00
0596a2ac86 Abort update if http.begin() returns false. Fix a typo in httpUpdate.ino (#2156) 2018-12-06 18:50:53 +01:00
fe1fdd2790 #2147 available() shouldn't return 0 after disconnect if there is still data in the buffer. Otherwise, how would we know it was there? (#2148) 2018-12-04 18:23:34 +01:00
af7e489f01 WiFiClientSecure: add support for PSK (pre-shared key) ciphers (#2133)
* WiFiClientSecure: add support for PSK (pre-shared key) ciphers

* add example for WiFiClientSecure PSK

* WiFiClientSecure: added README
2018-12-03 16:17:55 +01:00
Luc
5cfff190e9 removing log (#2140)
* Use right function for BSSID

* removing log
2018-12-03 16:17:16 +01:00
7a332864ab I2C ReSTART returns Success (#2141)
* Don't Return I2C_ERROR_CONTINUE on ReSTART

ReSTART operations on the ESP32 have to be handled differently than on AVR chips, so ReSTART operations(`Wire.endTransmission(false), Wire.requestFrom(id,size,false);` are queued until a STOP is send (`Wire.endTransmission(TRUE), Wire.endTransmission(), Wire.requestFrom(id,size), Wire.requestFrom(id,size,TRUE)). To indicate the queuing I had used `I2C_ERROR_CONTINUE`, this caused compatibility issues with the existing Arduino I2C Code base. So, back to Lying to the public(for their own good of course) about success!  This update just returns `I2C_ERROR_OK` on ReSTART commands.

* add comments

add comments

* Change Return error for ReSTART operation to I2C_ERROR_OK

This change restores compatibility with pre-existing Arduino Libraries.  The ReSTART queuing operations are hidden behind the scenes.  Wire.endTransmission(id,len,FALSE); will know return I2C_ERROR_OK instead of I2C_ERROR_CONTINUE, Wire.lastError() will return the true condition of I2C_ERROR_CONTINUE.
2018-12-03 16:16:43 +01:00
8aa6e2e143 bugfix lopy/pins_arduino.h (#2135)
Correction of Pin A14 that was double defined.
2018-12-02 18:15:25 +01:00
b5f317010c Fixed Arduino SPI/Ethernet compile issue as described in issue #1623 (#2136)
* #1623, implementing suggested change

Splitted suggested fix issue #1623 in a header and source part. Dit not completely dive into the code.
Giving data twice as parameter feels wrong, but it compiles, and i can succesfully use the W5500 with SPI with this fix.
Doesn't compile without.

* #1623, implementing suggested change SPI.h/cpp

Splitted suggested fix issue #1623 in a header and source part. Dit not completely dive into the code.
Giving data twice as parameter feels wrong, but it compiles, and i can succesfully use the W5500 with SPI with this fix.
Doesn't compile without.
2018-12-02 18:15:01 +01:00
Luc
f644d9d157 Use right function for BSSID (#2132) 2018-12-01 10:20:13 +01:00
a15b7e9088 Update IDF to afe4c76 and BLE lib (#2130)
* Update BLE

* Update IDF to afe4c76

* Update CMakeLists.txt

* Update BLE to fix compilation issues

* Update BLE
2018-11-30 17:21:06 +01:00
Luc
ce340faf94 Clean warnings when all warning enabled (#2112)
* Clean warnings when all warning enabled

Not used variables / functions due to debug log

Dual define with different values :
cores\esp32/binary.h
#define B110 6
#define B1000000 64

tools/sdk/include/newlib/sys/termios.h
#define B110        3
#define B1000000   23

Local variable returned in WiFiclient Secure

* change due to deprecated function

* Update with proper variable and label

* Update esp32-hal-i2c.c

* Apply changes requested

* Fix warnings due to #define conflict thanks @atanisoft
2018-11-29 11:34:55 +01:00
b69b04cb2b Update build-release.sh
Reenable git log in release builds
2018-11-28 13:18:54 +01:00
0cbba8a71d * remove git clone --depth parameter (#2124) 2018-11-28 13:15:49 +01:00
9e1f8cc457 Update pins_arduino.h (#2120)
Bugfix: pin A14 was double defined; pin A15 was missing.
2018-11-28 11:47:11 +01:00
cfe7e01158 Remove F() macro's (#2121) 2018-11-28 11:45:25 +01:00
fcd734a13c Some fixes found by gcc 8 2018-11-28 00:35:43 +01:00
302 changed files with 10634 additions and 1995 deletions

54
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,54 @@
---
name: Bug report
about: Please fill in the bug report carefully
title: ''
labels: ''
assignees: ''
---
Make your question, not a Statement, inclusive. Include all pertinent information:
What you are trying to do?
Describe your system( Hardware, computer, O/S, core version, environment).
Describe what is failing.
Show the shortest possible code that will duplicate the error.
Show the EXACT error message(it doesn't work is not enough).
All of this work on your part shows us that you have worked to solve YOUR problem. The more complete your issue posting is, the more likely someone will volunteer their time to help you.
If you have a Guru Meditation Error or Backtrace, ***please decode it***:
https://github.com/me-no-dev/EspExceptionDecoder
----------------------------- Remove above -----------------------------
### Hardware:
Board: ?ESP32 Dev Module? ?node32? ?ttgo_lora?
Core Installation version: ?1.0.0? ?1.0.1-rc4? ?1.0.1? ?1.0.1-git?
IDE name: ?Arduino IDE? ?Platform.io? ?IDF component?
Flash Frequency: ?40Mhz?
PSRAM enabled: ?no? ?yes?
Upload Speed: ?115200?
Computer OS: ?Windows 10? ?Mac OSX? ?Ubuntu?
### Description:
Describe your problem here
### Sketch: (leave the backquotes for [code formatting](https://help.github.com/articles/creating-and-highlighting-code-blocks/))
```cpp
//Change the code below by your sketch
#include <Arduino.h>
void setup() {
}
void loop() {
}
```
### Debug Messages:
```
Enable Core debug level: Debug on tools menu of Arduino IDE, then put the serial output here
```

View File

@ -7,6 +7,9 @@ python:
os:
- linux
git:
depth: false
env:
global:
- secure: "l/4Dt+KQ/mACtGAHDUsPr66fUte840PZoQ4xpPikqWZI0uARu4l+Ym7+sHinnT6fBqrj8AJeBYGz4nFa8NK4LutZn9mSD40w+sxl0wSV4oHV8rzKe3Cd8+sMG3+o33yWoikMNjSvqa73Q0rm+SgrlInNdZbuAyixL+a2alaWSnGPm4F2xwUGj+S33TOy5P/Xp77CYtCV5S8vzyk/eEdNhoF0GYePJVdfuzCOUjXMyT5OWxORkzzQ7Hnn/Ka/RDfV8Si4HgujLQBrK5q6iPnNBFqBSqilYBepSMn4opnOBpIm0SCgePz7XQEFC83buA7GUcnCnfg38bf+dCwHaODf1d1PmqVRYt2QmfinexXtM4afAtL0iBUDtvrfnXHzwW9w82VeZhpbJSVh9DUQvB0IlsZeCz9J9PUBAi3N+SMX+9l+BomYwRUlPuKY+Ef2JKk9q6mxtUkky5R0daAlVxEhpVdQks1rT+T+NMoDMemxQ3SKEiqAHh6EgHecruszffmZ71uLX9MpERpew0qN+UFiafws+jkTjx+3yF9yut0Hf9sMbeAYzzkGzRqJTUEBJ6B29Cql8M0yRXCNN/8wuuTHhG8esstozga4ZQoIVrq7mEAgup376PTcNfr1+imbbWVQ7lJdYIuDe6OS5V3OX6np11vgK/DbhfyzvQv9Z1zAGnM="

View File

@ -3,6 +3,7 @@ set(CORE_SRCS
cores/esp32/cbuf.cpp
cores/esp32/esp32-hal-adc.c
cores/esp32/esp32-hal-bt.c
cores/esp32/esp32-hal-cpu.c
cores/esp32/esp32-hal-dac.c
cores/esp32/esp32-hal-gpio.c
cores/esp32/esp32-hal-i2c.c
@ -41,7 +42,7 @@ set(LIBRARY_SRCS
libraries/AsyncUDP/src/AsyncUDP.cpp
libraries/BluetoothSerial/src/BluetoothSerial.cpp
libraries/DNSServer/src/DNSServer.cpp
libraries/EEPROM/EEPROM.cpp
libraries/EEPROM/src/EEPROM.cpp
libraries/ESPmDNS/src/ESPmDNS.cpp
libraries/FFat/src/FFat.cpp
libraries/FS/src/FS.cpp
@ -150,6 +151,8 @@ set(BLE_SRCS
libraries/BLE/src/BLEDescriptor.cpp
libraries/BLE/src/BLEDescriptorMap.cpp
libraries/BLE/src/BLEDevice.cpp
libraries/BLE/src/BLEEddystoneTLM.cpp
libraries/BLE/src/BLEEddystoneURL.cpp
libraries/BLE/src/BLEExceptions.cpp
libraries/BLE/src/BLEHIDDevice.cpp
libraries/BLE/src/BLERemoteCharacteristic.cpp
@ -178,6 +181,7 @@ set(COMPONENT_ADD_INCLUDEDIRS
libraries/BLE/src
libraries/BluetoothSerial/src
libraries/DNSServer/src
libraries/EEPROM/src
libraries/ESP32/src
libraries/ESPmDNS/src
libraries/FFat/src

View File

@ -90,6 +90,8 @@ config ARDUHAL_PARTITION_SCHEME_MINIMAL
bool "Minimal (for 2MB FLASH)"
config ARDUHAL_PARTITION_SCHEME_NO_OTA
bool "No OTA (for large apps)"
config ARDUHAL_PARTITION_SCHEME_HUGE_APP
bool "Huge App (for very large apps)"
config ARDUHAL_PARTITION_SCHEME_MIN_SPIFFS
bool "Minimal SPIFFS (for large apps with OTA)"
endchoice
@ -99,6 +101,7 @@ config ARDUHAL_PARTITION_SCHEME
default "default" if ARDUHAL_PARTITION_SCHEME_DEFAULT
default "minimal" if ARDUHAL_PARTITION_SCHEME_MINIMAL
default "no_ota" if ARDUHAL_PARTITION_SCHEME_NO_OTA
default "huge_app" if ARDUHAL_PARTITION_SCHEME_HUGE_APP
default "min_spiffs" if ARDUHAL_PARTITION_SCHEME_MIN_SPIFFS

View File

@ -10,9 +10,9 @@
- [ESP32Dev Board PINMAP](#esp32dev-board-pinmap)
## Development Status
[Latest stable release ![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32.svg?style=plastic) ![Release Date](https://img.shields.io/github/release-date/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/)
[Latest stable release ![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32.svg?style=plastic) ![Release Date](https://img.shields.io/github/release-date/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/) ![Downloads](https://img.shields.io/github/downloads/espressif/arduino-esp32/latest/total.svg?style=plastic)
[Latest development release ![Development Version](https://img.shields.io/github/release/espressif/arduino-esp32/all.svg?style=plastic) ![Development Date](https://img.shields.io/github/release-date-pre/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/)
[Latest development release ![Development Version](https://img.shields.io/github/release/espressif/arduino-esp32/all.svg?style=plastic) ![Development Date](https://img.shields.io/github/release-date-pre/espressif/arduino-esp32.svg?style=plastic)](https://github.com/espressif/arduino-esp32/releases/latest/) ![Downloads](https://img.shields.io/github/downloads-pre/espressif/arduino-esp32/latest/total.svg?style=plastic)
Most of the framework is implemented. Most noticable is the missing analogWrite. While analogWrite is on it's way, there are a few other options that you can use:
- 16 channels [LEDC](cores/esp32/esp32-hal-ledc.h) which is PWM

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,36 @@
ARDUINO_LIBRARIES_LIST := $(patsubst $(COMPONENT_PATH)/libraries/%,%,$(wildcard $(COMPONENT_PATH)/libraries/*))
ARDUINO_SINGLE_LIBRARY_FILES = $(patsubst $(COMPONENT_PATH)/%,%,$(sort $(dir $(wildcard $(COMPONENT_PATH)/libraries/$(MODULE)/*/)) $(dir $(wildcard $(COMPONENT_PATH)/libraries/$(MODULE)/*/*/)) $(dir $(wildcard $(COMPONENT_PATH)/libraries/$(MODULE)/*/*/*/)) $(dir $(wildcard $(COMPONENT_PATH)/libraries/$(MODULE)/*/*/*/*/)) $(dir $(wildcard $(COMPONENT_PATH)/libraries/$(MODULE)/*/*/*/*/*/))))
ARDUINO_CORE_LIBS := $(foreach MODULE,$(ARDUINO_LIBRARIES_LIST),$(if $(CONFIG_ARDUINO_SELECTIVE_COMPILATION),$(if $(CONFIG_ARDUINO_SELECTIVE_$(MODULE)),$(ARDUINO_SINGLE_LIBRARY_FILES)),$(ARDUINO_SINGLE_LIBRARY_FILES)))
ARDUINO_ALL_LIBRARIES := $(patsubst $(COMPONENT_PATH)/libraries/%,%,$(wildcard $(COMPONENT_PATH)/libraries/*))
COMPONENT_ADD_INCLUDEDIRS := cores/esp32 variants/esp32 $(ARDUINO_CORE_LIBS)
# Macro returns non-empty if Arduino library $(1) should be included in the build
# (either because selective compilation is of, or this library is enabled
define ARDUINO_LIBRARY_ENABLED
$(if $(CONFIG_ARDUINO_SELECTIVE_COMPILATION),$(CONFIG_ARDUINO_SELECTIVE_$(1)),y)
endef
ARDUINO_ENABLED_LIBRARIES := $(foreach LIBRARY,$(sort $(ARDUINO_ALL_LIBRARIES)),$(if $(call ARDUINO_LIBRARY_ENABLED,$(LIBRARY)),$(LIBRARY)))
$(info Arduino libraries in build: $(ARDUINO_ENABLED_LIBRARIES))
# Expand all subdirs under $(1)
define EXPAND_SUBDIRS
$(sort $(dir $(wildcard $(1)/* $(1)/*/* $(1)/*/*/* $(1)/*/*/*/* $(1)/*/*/*/*/*)))
endef
# Macro returns SRCDIRS for library
define ARDUINO_LIBRARY_GET_SRCDIRS
$(if $(wildcard $(COMPONENT_PATH)/libraries/$(1)/src/.), \
$(call EXPAND_SUBDIRS,$(COMPONENT_PATH)/libraries/$(1)/src), \
$(filter-out $(call EXPAND_SUBDIRS,$(COMPONENT_PATH)/libraries/$(1)/examples), \
$(call EXPAND_SUBDIRS,$(COMPONENT_PATH)/libraries/$(1)) \
) \
)
endef
# Make a list of all srcdirs in enabled libraries
ARDUINO_LIBRARY_SRCDIRS := $(patsubst $(COMPONENT_PATH)/%,%,$(foreach LIBRARY,$(ARDUINO_ENABLED_LIBRARIES),$(call ARDUINO_LIBRARY_GET_SRCDIRS,$(LIBRARY))))
#$(info Arduino libraries src dirs: $(ARDUINO_LIBRARY_SRCDIRS))
COMPONENT_ADD_INCLUDEDIRS := cores/esp32 variants/esp32 $(ARDUINO_LIBRARY_SRCDIRS)
COMPONENT_PRIV_INCLUDEDIRS := cores/esp32/libb64
COMPONENT_SRCDIRS := cores/esp32/libb64 cores/esp32 variants/esp32 $(ARDUINO_CORE_LIBS)
COMPONENT_SRCDIRS := cores/esp32/libb64 cores/esp32 variants/esp32 $(ARDUINO_LIBRARY_SRCDIRS)
CXXFLAGS += -fno-rtti

View File

@ -26,10 +26,11 @@
#include <soc/soc.h>
#include <soc/efuse_reg.h>
#include <esp_partition.h>
#include <esp_ota_ops.h>
extern "C" {
#include <esp_image_format.h>
#include "esp_ota_ops.h"
#include "esp_image_format.h"
}
#include <MD5Builder.h>
/**
* User-defined Literals
@ -156,11 +157,11 @@ static uint32_t sketchSize(sketchSize_t response) {
.size = running->size,
};
data.start_addr = running_pos.offset;
esp_image_load(ESP_IMAGE_VERIFY, &running_pos, &data);
esp_image_verify(ESP_IMAGE_VERIFY, &running_pos, &data);
if (response) {
return running_pos.size - data.image_len;
return running_pos.size - data.image_len;
} else {
return data.image_len;
return data.image_len;
}
}
@ -168,8 +169,53 @@ uint32_t EspClass::getSketchSize () {
return sketchSize(SKETCH_SIZE_TOTAL);
}
String EspClass::getSketchMD5()
{
static String result;
if (result.length()) {
return result;
}
uint32_t lengthLeft = getSketchSize();
const esp_partition_t *running = esp_ota_get_running_partition();
if (!running) {
log_e("Partition could not be found");
return String();
}
const size_t bufSize = SPI_FLASH_SEC_SIZE;
std::unique_ptr<uint8_t[]> buf(new uint8_t[bufSize]);
uint32_t offset = 0;
if(!buf.get()) {
log_e("Not enough memory to allocate buffer");
return String();
}
MD5Builder md5;
md5.begin();
while( lengthLeft > 0) {
size_t readBytes = (lengthLeft < bufSize) ? lengthLeft : bufSize;
if (!ESP.flashRead(running->address + offset, reinterpret_cast<uint32_t*>(buf.get()), (readBytes + 3) & ~3)) {
log_e("Could not read buffer from flash");
return String();
}
md5.add(buf.get(), readBytes);
lengthLeft -= readBytes;
offset += readBytes;
}
md5.calculate();
result = md5.toString();
return result;
}
uint32_t EspClass::getFreeSketchSpace () {
return sketchSize(SKETCH_SIZE_FREE);
const esp_partition_t* _partition = esp_ota_get_next_update_partition(NULL);
if(!_partition){
return 0;
}
return _partition->size;
}
uint8_t EspClass::getChipRevision(void)

View File

@ -90,6 +90,7 @@ public:
FlashMode_t magicFlashChipMode(uint8_t byte);
uint32_t getSketchSize();
String getSketchMD5();
uint32_t getFreeSketchSpace();
bool flashEraseSector(uint32_t sector);

View File

@ -73,6 +73,11 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
}
}
void HardwareSerial::updateBaudRate(unsigned long baud)
{
uartSetBaudRate(_uart, baud);
}
void HardwareSerial::end()
{
if(uartGetDebug() == _uart_nr) {

View File

@ -57,6 +57,7 @@ public:
void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false, unsigned long timeout_ms = 20000UL);
void end();
void updateBaudRate(unsigned long baud);
int available(void);
int availableForWrite(void);
int peek(void);

View File

@ -63,7 +63,7 @@ size_t Print::printf(const char *format, ...)
len = vsnprintf(temp, len+1, format, arg);
write((uint8_t*)temp, len);
va_end(arg);
if(len > 64){
if(len >= sizeof(loc_buf)){
delete[] temp;
}
return len;

View File

@ -37,10 +37,23 @@ void randomSeed(unsigned long seed)
long random(long howbig)
{
if(howbig == 0) {
return 0;
uint32_t x = esp_random();
uint64_t m = uint64_t(x) * uint64_t(howbig);
uint32_t l = uint32_t(m);
if (l < howbig) {
uint32_t t = -howbig;
if (t >= howbig) {
t -= howbig;
if (t >= howbig)
t %= howbig;
}
while (l < t) {
x = esp_random();
m = uint64_t(x) * uint64_t(howbig);
l = uint32_t(m);
}
}
return esp_random() % howbig;
return m >> 32;
}
long random(long howsmall, long howbig)

209
cores/esp32/esp32-hal-cpu.c Normal file
View File

@ -0,0 +1,209 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "freertos/xtensa_timer.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "rom/rtc.h"
#include "soc/apb_ctrl_reg.h"
#include "esp32-hal.h"
#include "esp32-hal-cpu.h"
typedef struct apb_change_cb_s {
struct apb_change_cb_s * next;
void * arg;
apb_change_cb_t cb;
} apb_change_t;
const uint32_t MHZ = 1000000;
static apb_change_t * apb_change_callbacks = NULL;
static xSemaphoreHandle apb_change_lock = NULL;
static void initApbChangeCallback(){
static volatile bool initialized = false;
if(!initialized){
initialized = true;
apb_change_lock = xSemaphoreCreateMutex();
if(!apb_change_lock){
initialized = false;
}
}
}
static void triggerApbChangeCallback(apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
initApbChangeCallback();
xSemaphoreTake(apb_change_lock, portMAX_DELAY);
apb_change_t * r = apb_change_callbacks;
while(r != NULL){
r->cb(r->arg, ev_type, old_apb, new_apb);
r=r->next;
}
xSemaphoreGive(apb_change_lock);
}
bool addApbChangeCallback(void * arg, apb_change_cb_t cb){
initApbChangeCallback();
apb_change_t * c = (apb_change_t*)malloc(sizeof(apb_change_t));
if(!c){
log_e("Callback Object Malloc Failed");
return false;
}
c->next = NULL;
c->arg = arg;
c->cb = cb;
xSemaphoreTake(apb_change_lock, portMAX_DELAY);
if(apb_change_callbacks == NULL){
apb_change_callbacks = c;
} else {
apb_change_t * r = apb_change_callbacks;
if(r->cb != cb || r->arg != arg){
while(r->next){
r = r->next;
if(r->cb == cb && r->arg == arg){
free(c);
goto unlock_and_exit;
}
}
r->next = c;
}
}
unlock_and_exit:
xSemaphoreGive(apb_change_lock);
return true;
}
bool removeApbChangeCallback(void * arg, apb_change_cb_t cb){
initApbChangeCallback();
xSemaphoreTake(apb_change_lock, portMAX_DELAY);
apb_change_t * r = apb_change_callbacks;
if(r == NULL){
xSemaphoreGive(apb_change_lock);
return false;
}
if(r->cb == cb && r->arg == arg){
apb_change_callbacks = r->next;
free(r);
} else {
while(r->next && (r->next->cb != cb || r->next->arg != arg)){
r = r->next;
}
if(r->next == NULL || r->next->cb != cb || r->next->arg != arg){
xSemaphoreGive(apb_change_lock);
return false;
}
apb_change_t * c = r->next;
r->next = c->next;
free(c);
}
xSemaphoreGive(apb_change_lock);
return true;
}
static uint32_t calculateApb(rtc_cpu_freq_config_t * conf){
if(conf->freq_mhz >= 80){
return 80 * MHZ;
}
return (conf->source_freq_mhz * MHZ) / conf->div;
}
void esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us); //private in IDF
bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){
rtc_cpu_freq_config_t conf, cconf;
uint32_t capb, apb;
//Get XTAL Frequency and calculate min CPU MHz
rtc_xtal_freq_t xtal = rtc_clk_xtal_freq_get();
if(xtal > RTC_XTAL_FREQ_AUTO){
if(xtal < RTC_XTAL_FREQ_40M) {
if(cpu_freq_mhz <= xtal && cpu_freq_mhz != xtal && cpu_freq_mhz != (xtal/2)){
log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2);
return false;
}
} else if(cpu_freq_mhz <= xtal && cpu_freq_mhz != xtal && cpu_freq_mhz != (xtal/2) && cpu_freq_mhz != (xtal/4)){
log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2, xtal/4);
return false;
}
}
if(cpu_freq_mhz > xtal && cpu_freq_mhz != 240 && cpu_freq_mhz != 160 && cpu_freq_mhz != 80){
if(xtal >= RTC_XTAL_FREQ_40M){
log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2, xtal/4);
} else {
log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2);
}
return false;
}
//Get current CPU clock configuration
rtc_clk_cpu_freq_get_config(&cconf);
//return if frequency has not changed
if(cconf.freq_mhz == cpu_freq_mhz){
return true;
}
//Get configuration for the new CPU frequency
if(!rtc_clk_cpu_freq_mhz_to_config(cpu_freq_mhz, &conf)){
log_e("CPU clock could not be set to %u MHz", cpu_freq_mhz);
return false;
}
//Current APB
capb = calculateApb(&cconf);
//New APB
apb = calculateApb(&conf);
log_d("%s: %u / %u = %u Mhz, APB: %u Hz", (conf.source == RTC_CPU_FREQ_SRC_PLL)?"PLL":((conf.source == RTC_CPU_FREQ_SRC_APLL)?"APLL":((conf.source == RTC_CPU_FREQ_SRC_XTAL)?"XTAL":"8M")), conf.source_freq_mhz, conf.div, conf.freq_mhz, apb);
//Call peripheral functions before the APB change
if(apb_change_callbacks){
triggerApbChangeCallback(APB_BEFORE_CHANGE, capb, apb);
}
//Make the frequency change
rtc_clk_cpu_freq_set_config_fast(&conf);
if(capb != apb){
//Update REF_TICK (uncomment if REF_TICK is different than 1MHz)
//if(conf.freq_mhz < 80){
// ESP_REG(APB_CTRL_XTAL_TICK_CONF_REG) = conf.freq_mhz / (REF_CLK_FREQ / MHZ) - 1;
//}
//Update APB Freq REG
rtc_clk_apb_freq_update(apb);
//Update esp_timer divisor
esp_timer_impl_update_apb_freq(apb / MHZ);
}
//Update FreeRTOS Tick Divisor
uint32_t fcpu = (conf.freq_mhz >= 80)?(conf.freq_mhz * MHZ):(apb);
_xt_tick_divisor = fcpu / XT_TICK_PER_SEC;
//Call peripheral functions after the APB change
if(apb_change_callbacks){
triggerApbChangeCallback(APB_AFTER_CHANGE, capb, apb);
}
return true;
}
uint32_t getCpuFrequencyMhz(){
rtc_cpu_freq_config_t conf;
rtc_clk_cpu_freq_get_config(&conf);
return conf.freq_mhz;
}
uint32_t getXtalFrequencyMhz(){
return rtc_clk_xtal_freq_get();
}
uint32_t getApbFrequency(){
rtc_cpu_freq_config_t conf;
rtc_clk_cpu_freq_get_config(&conf);
return calculateApb(&conf);
}

View File

@ -0,0 +1,48 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESP32_HAL_CPU_H_
#define _ESP32_HAL_CPU_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
typedef enum { APB_BEFORE_CHANGE, APB_AFTER_CHANGE } apb_change_ev_t;
typedef void (* apb_change_cb_t)(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb);
bool addApbChangeCallback(void * arg, apb_change_cb_t cb);
bool removeApbChangeCallback(void * arg, apb_change_cb_t cb);
//function takes the following frequencies as valid values:
// 240, 160, 80 <<< For all XTAL types
// 40, 20, 10 <<< For 40MHz XTAL
// 26, 13 <<< For 26MHz XTAL
// 24, 12 <<< For 24MHz XTAL
bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz);
uint32_t getCpuFrequencyMhz(); // In MHz
uint32_t getXtalFrequencyMhz(); // In MHz
uint32_t getApbFrequency(); // In Hz
#ifdef __cplusplus
}
#endif
#endif /* _ESP32_HAL_CPU_H_ */

View File

@ -287,7 +287,7 @@ extern void __detachInterrupt(uint8_t pin)
}
__pinInterruptHandlers[pin].fn = NULL;
__pinInterruptHandlers[pin].arg = NULL;
__pinInterruptHandlers[pin].arg = false;
__pinInterruptHandlers[pin].functional = false;
GPIO.pin[pin].int_ena = 0;
GPIO.pin[pin].int_type = 0;

View File

@ -24,7 +24,7 @@
#include "soc/i2c_struct.h"
#include "soc/dport_reg.h"
#include "esp_attr.h"
#include "esp32-hal-cpu.h" // cpu clock change support 31DEC2018
//#define I2C_DEV(i) (volatile i2c_dev_t *)((i)?DR_REG_I2C1_EXT_BASE:DR_REG_I2C_EXT_BASE)
//#define I2C_DEV(i) ((i2c_dev_t *)(REG_I2C_BASE(i)))
#define I2C_SCL_IDX(p) ((p==0)?I2CEXT0_SCL_OUT_IDX:((p==1)?I2CEXT1_SCL_OUT_IDX:0))
@ -206,8 +206,8 @@ static i2c_t _i2c_bus_array[2] = {
{(volatile i2c_dev_t *)(DR_REG_I2C1_EXT_BASE_FIXED), 1, -1, -1,I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0,0,0}
};
#else
#define I2C_MUTEX_LOCK() do {} while (xSemaphoreTake(i2c->lock, portMAX_DELAY) != pdPASS)
#define I2C_MUTEX_UNLOCK() xSemaphoreGive(i2c->lock)
#define I2C_MUTEX_LOCK() do {} while (xSemaphoreTakeRecursive(i2c->lock, portMAX_DELAY) != pdPASS)
#define I2C_MUTEX_UNLOCK() xSemaphoreGiveRecursive(i2c->lock)
static i2c_t _i2c_bus_array[2] = {
{(volatile i2c_dev_t *)(DR_REG_I2C_EXT_BASE_FIXED), NULL, 0, -1, -1, I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0,0,0,0},
@ -248,9 +248,10 @@ static void IRAM_ATTR i2cDumpCmdQueue(i2c_t *i2c)
/* Stickbreaker ISR mode debug support
*/
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)
static void i2cDumpDqData(i2c_t * i2c)
{
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)&&(defined ENABLE_I2C_DEBUG_BUFFER)
#if defined (ENABLE_I2C_DEBUG_BUFFER)
uint16_t a=0;
char buff[140];
I2C_DATA_QUEUE_t *tdq;
@ -306,9 +307,12 @@ static void i2cDumpDqData(i2c_t * i2c)
}
a++;
}
#else
log_i("Debug Buffer not Enabled");
#endif
}
#endif
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
static void i2cDumpI2c(i2c_t * i2c)
{
log_e("i2c=%p",i2c);
@ -332,11 +336,12 @@ static void i2cDumpI2c(i2c_t * i2c)
i2cDumpDqData(i2c);
}
}
#endif
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)
static void i2cDumpInts(uint8_t num)
{
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) && (defined ENABLE_I2C_DEBUG_BUFFER)
#if defined (ENABLE_I2C_DEBUG_BUFFER)
uint32_t b;
log_i("%u row\tcount\tINTR\tTX\tRX\tTick ",num);
for(uint32_t a=1; a<=INTBUFFMAX; a++) {
@ -349,9 +354,10 @@ static void i2cDumpInts(uint8_t num)
log_i("Debug Buffer not Enabled");
#endif
}
#endif
static void IRAM_ATTR i2cDumpStatus(i2c_t * i2c){
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)&&(defined ENABLE_I2C_DEBUG_BUFFER)
static void IRAM_ATTR i2cDumpStatus(i2c_t * i2c){
typedef union {
struct {
uint32_t ack_rec: 1; /*This register stores the value of ACK bit.*/
@ -377,11 +383,11 @@ static void IRAM_ATTR i2cDumpStatus(i2c_t * i2c){
sr.val= i2c->dev->status_reg.val;
log_i("ack(%d) sl_rw(%d) to(%d) arb(%d) busy(%d) sl(%d) trans(%d) rx(%d) tx(%d) sclMain(%d) scl(%d)",sr.ack_rec,sr.slave_rw,sr.time_out,sr.arb_lost,sr.bus_busy,sr.slave_addressed,sr.byte_trans, sr.rx_fifo_cnt, sr.tx_fifo_cnt,sr.scl_main_state_last, sr.scl_state_last);
#endif
}
#endif
static void i2cDumpFifo(i2c_t * i2c){
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)&&(defined ENABLE_I2C_DEBUG_BUFFER)
static void i2cDumpFifo(i2c_t * i2c){
char buf[64];
uint16_t k = 0;
uint16_t i = fifoPos+1;
@ -422,8 +428,8 @@ if(i != fifoPos){// actual data
}
}while( i!= fifoPos);
}
#endif
}
#endif
static void IRAM_ATTR i2cTriggerDumps(i2c_t * i2c, uint8_t trigger, const char locus[]){
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)&&(defined ENABLE_I2C_DEBUG_BUFFER)
@ -439,6 +445,39 @@ static void IRAM_ATTR i2cTriggerDumps(i2c_t * i2c, uint8_t trigger, const char l
}
// end of debug support routines
/* Start of CPU Clock change Support
*/
static void i2cApbChangeCallback(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
i2c_t* i2c = (i2c_t*) arg; // recover data
if(i2c == NULL) { // point to peripheral control block does not exits
return;
}
uint32_t oldFreq=0;
switch(ev_type){
case APB_BEFORE_CHANGE :
if(new_apb < 3000000) {// too slow
log_e("apb speed %d too slow",new_apb);
break;
}
I2C_MUTEX_LOCK(); // lock will spin until current transaction is completed
break;
case APB_AFTER_CHANGE :
oldFreq = (i2c->dev->scl_low_period.period+i2c->dev->scl_high_period.period); //read old apbCycles
if(oldFreq>0) { // was configured with value
oldFreq = old_apb / oldFreq;
i2cSetFrequency(i2c,oldFreq);
}
I2C_MUTEX_UNLOCK();
break;
default :
log_e("unk ev %u",ev_type);
I2C_MUTEX_UNLOCK();
}
return;
}
/* End of CPU Clock change Support
*/
static void IRAM_ATTR i2cSetCmd(i2c_t * i2c, uint8_t index, uint8_t op_code, uint8_t byte_num, bool ack_val, bool ack_exp, bool ack_check)
{
I2C_COMMAND_t cmd;
@ -1142,7 +1181,7 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
if(tdq->ctrl.addrReq ==2) { // 10bit address
taddr =((tdq->ctrl.addr >> 7) & 0xFE)
|tdq->ctrl.mode;
taddr = (taddr <<8) || (tdq->ctrl.addr&0xFF);
taddr = (taddr <<8) | (tdq->ctrl.addr&0xFF);
} else { // 7bit address
taddr = ((tdq->ctrl.addr<<1)&0xFE)
|tdq->ctrl.mode;
@ -1215,6 +1254,12 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
I2C_MUTEX_UNLOCK();
return I2C_ERROR_MEMORY;
}
if( !addApbChangeCallback( i2c, i2cApbChangeCallback)) {
log_e("install apb Callback failed");
I2C_MUTEX_UNLOCK();
return I2C_ERROR_DEV;
}
}
//hang until it completes.
@ -1346,6 +1391,9 @@ static void i2cReleaseISR(i2c_t * i2c)
if(i2c->intr_handle) {
esp_intr_free(i2c->intr_handle);
i2c->intr_handle=NULL;
if (!removeApbChangeCallback( i2c, i2cApbChangeCallback)) {
log_e("unable to release apbCallback");
}
}
}
@ -1431,8 +1479,7 @@ i2c_err_t i2cDetachSDA(i2c_t * i2c, int8_t sda)
* PUBLIC API
* */
// 24Nov17 only supports Master Mode
i2c_t * i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t frequency) //before this is called, pins should be detached, else glitch
{
i2c_t * i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t frequency) {
log_v("num=%d sda=%d scl=%d freq=%d",i2c_num, sda, scl, frequency);
if(i2c_num > 1) {
return NULL;
@ -1440,6 +1487,7 @@ i2c_t * i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t frequency) //b
i2c_t * i2c = &_i2c_bus_array[i2c_num];
// pins should be detached, else glitch
if(i2c->sda >= 0){
i2cDetachSDA(i2c, i2c->sda);
}
@ -1451,7 +1499,7 @@ i2c_t * i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t frequency) //b
#if !CONFIG_DISABLE_HAL_LOCKS
if(i2c->lock == NULL) {
i2c->lock = xSemaphoreCreateMutex();
i2c->lock = xSemaphoreCreateRecursiveMutex();
if(i2c->lock == NULL) {
return NULL;
}
@ -1561,6 +1609,9 @@ i2c_err_t i2cFlush(i2c_t * i2c)
}
i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, bool sendStop, uint16_t timeOutMillis){
if((i2c==NULL)||((size>0)&&(buff==NULL))) { // need to have location to store requested data
return I2C_ERROR_DEV;
}
i2c_err_t last_error = i2cAddQueueWrite(i2c, address, buff, size, sendStop, NULL);
if(last_error == I2C_ERROR_OK) { //queued
@ -1580,6 +1631,9 @@ i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size,
}
i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, bool sendStop, uint16_t timeOutMillis, uint32_t *readCount){
if((size == 0)||(i2c == NULL)||(buff==NULL)){ // hardware will hang if no data requested on READ
return I2C_ERROR_DEV;
}
i2c_err_t last_error=i2cAddQueueRead(i2c, address, buff, size, sendStop, NULL);
if(last_error == I2C_ERROR_OK) { //queued
@ -1598,27 +1652,50 @@ i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, b
return last_error;
}
#define MIN_I2C_CLKS 100 // minimum ratio between cpu and i2c Bus clocks
#define INTERRUPT_CYCLE_OVERHEAD 16000 // number of cpu clocks necessary to respond to interrupt
i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed)
{
if(i2c == NULL) {
return I2C_ERROR_DEV;
}
I2C_FIFO_CONF_t f;
uint32_t period = (APB_CLK_FREQ/clk_speed) / 2;
uint32_t apb = getApbFrequency();
uint32_t period = (apb/clk_speed) / 2;
if((apb/8192 > clk_speed)||(apb/MIN_I2C_CLKS < clk_speed)){ //out of bounds
log_d("i2c freq(%d) out of bounds.vs APB Clock(%d), min=%d, max=%d",clk_speed,apb,(apb/8192),(apb/MIN_I2C_CLKS));
}
if(period < (MIN_I2C_CLKS/2) ){
period = (MIN_I2C_CLKS/2);
clk_speed = apb/(period*2);
log_d("APB Freq too slow, Reducing i2c Freq to %d Hz",clk_speed);
} else if ( period> 4095) {
period = 4095;
clk_speed = apb/(period*2);
log_d("APB Freq too fast, Increasing i2c Freq to %d Hz",clk_speed);
}
log_v("freq=%dHz",clk_speed);
uint32_t halfPeriod = period/2;
uint32_t quarterPeriod = period/4;
I2C_MUTEX_LOCK();
// Adjust Fifo thresholds based on frequency
I2C_FIFO_CONF_t f;
f.val = i2c->dev->fifo_conf.val;
uint32_t a = (clk_speed / 50000L )+1;
if (a > 24) a=24;
f.rx_fifo_full_thrhd = 32 - a;
f.tx_fifo_empty_thrhd = a;
/* Adjust Fifo thresholds based on differential between cpu frequency and bus clock.
The fifo_delta is calculated such that at least INTERRUPT_CYCLE_OVERHEAD cpu clocks are
available when a Fifo interrupt is triggered. This allows enough room in the Fifo so that
interrupt latency does not cause a Fifo overflow/underflow event.
*/
log_v("cpu Freq=%dMhz, i2c Freq=%dHz",getCpuFrequencyMhz(),clk_speed);
uint32_t fifo_delta = (INTERRUPT_CYCLE_OVERHEAD/((getCpuFrequencyMhz()*1000000 / clk_speed)*10))+1;
if (fifo_delta > 24) fifo_delta=24;
f.rx_fifo_full_thrhd = 32 - fifo_delta;
f.tx_fifo_empty_thrhd = fifo_delta;
i2c->dev->fifo_conf.val = f.val; // set thresholds
log_v("Fifo threshold=%d",a);
log_v("Fifo delta=%d",fifo_delta);
//the clock num during SCL is low level
i2c->dev->scl_low_period.period = period;
@ -1651,7 +1728,7 @@ uint32_t i2cGetFrequency(i2c_t * i2c)
uint32_t result = 0;
uint32_t old_count = (i2c->dev->scl_low_period.period+i2c->dev->scl_high_period.period);
if(old_count>0) {
result = APB_CLK_FREQ / old_count;
result = getApbFrequency() / old_count;
} else {
result = 0;
}
@ -1674,6 +1751,8 @@ uint32_t i2cGetStatus(i2c_t * i2c){
}
else return 0;
}
/* todo
22JUL18
need to add multi-thread capability, use dq.queueEvent as the group marker. When multiple threads

View File

@ -53,6 +53,33 @@ xSemaphoreHandle _ledc_sys_lock;
#define LEDC_CHAN(g,c) LEDC.channel_group[(g)].channel[(c)]
#define LEDC_TIMER(g,t) LEDC.timer_group[(g)].timer[(t)]
static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
if(ev_type == APB_AFTER_CHANGE && old_apb != new_apb){
uint32_t iarg = (uint32_t)arg;
uint8_t chan = iarg;
uint8_t group=(chan/8), timer=((chan/2)%4);
old_apb /= 1000000;
new_apb /= 1000000;
if(LEDC_TIMER(group, timer).conf.tick_sel){
LEDC_MUTEX_LOCK();
uint32_t old_div = LEDC_TIMER(group, timer).conf.clock_divider;
uint32_t div_num = (new_apb * old_div) / old_apb;
if(div_num > LEDC_DIV_NUM_HSTIMER0_V){
new_apb = REF_CLK_FREQ / 1000000;
div_num = (new_apb * old_div) / old_apb;
if(div_num > LEDC_DIV_NUM_HSTIMER0_V) {
div_num = LEDC_DIV_NUM_HSTIMER0_V;//lowest clock possible
}
LEDC_TIMER(group, timer).conf.tick_sel = 0;
} else if(div_num < 256) {
div_num = 256;//highest clock possible
}
LEDC_TIMER(group, timer).conf.clock_divider = div_num;
LEDC_MUTEX_UNLOCK();
}
}
}
//uint32_t frequency = (80MHz or 1MHz)/((div_num / 256.0)*(1 << bit_num));
static void _ledcSetupTimer(uint8_t chan, uint32_t div_num, uint8_t bit_num, bool apb_clk)
{
@ -78,13 +105,15 @@ static void _ledcSetupTimer(uint8_t chan, uint32_t div_num, uint8_t bit_num, boo
LEDC_TIMER(group, timer).conf.rst = 1;//This bit is used to reset timer the counter will be 0 after reset.
LEDC_TIMER(group, timer).conf.rst = 0;
LEDC_MUTEX_UNLOCK();
uint32_t iarg = chan;
addApbChangeCallback((void*)iarg, _on_apb_change);
}
//max div_num 0x3FFFF (262143)
//max bit_num 0x1F (31)
static double _ledcSetupTimerFreq(uint8_t chan, double freq, uint8_t bit_num)
{
uint64_t clk_freq = APB_CLK_FREQ;
uint64_t clk_freq = getApbFrequency();
clk_freq <<= 8;//div_num is 8 bit decimal
uint32_t div_num = (clk_freq >> bit_num) / freq;
bool apb_clk = true;
@ -117,7 +146,7 @@ static double _ledcTimerRead(uint8_t chan)
LEDC_MUTEX_UNLOCK();
uint64_t clk_freq = 1000000;
if(apb_clk) {
clk_freq *= 80;
clk_freq = getApbFrequency();
}
clk_freq <<= 8;//div_num is 8 bit decimal
return (clk_freq >> bit_num) / (double)div_num;

View File

@ -21,8 +21,18 @@
#include "esp_partition.h"
#include "esp_log.h"
#include "esp_timer.h"
#ifdef CONFIG_APP_ROLLBACK_ENABLE
#include "esp_ota_ops.h"
#endif //CONFIG_APP_ROLLBACK_ENABLE
#ifdef CONFIG_BT_ENABLED
#include "esp_bt.h"
#endif //CONFIG_BT_ENABLED
#include <sys/time.h>
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/apb_ctrl_reg.h"
#include "rom/rtc.h"
#include "esp_task_wdt.h"
#include "esp32-hal.h"
//Undocumented!!! Get chip temperature in Farenheit
@ -39,14 +49,76 @@ void yield()
vPortYield();
}
#if CONFIG_AUTOSTART_ARDUINO
extern TaskHandle_t loopTaskHandle;
extern bool loopTaskWDTEnabled;
void enableLoopWDT(){
if(loopTaskHandle != NULL){
if(esp_task_wdt_add(loopTaskHandle) != ESP_OK){
log_e("Failed to add loop task to WDT");
} else {
loopTaskWDTEnabled = true;
}
}
}
void disableLoopWDT(){
if(loopTaskHandle != NULL && loopTaskWDTEnabled){
loopTaskWDTEnabled = false;
if(esp_task_wdt_delete(loopTaskHandle) != ESP_OK){
log_e("Failed to remove loop task from WDT");
}
}
}
void feedLoopWDT(){
esp_err_t err = esp_task_wdt_reset();
if(err != ESP_OK){
log_e("Failed to feed WDT! Error: %d", err);
}
}
#endif
void enableCore0WDT(){
TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
if(idle_0 == NULL || esp_task_wdt_add(idle_0) != ESP_OK){
log_e("Failed to add Core 0 IDLE task to WDT");
}
}
void disableCore0WDT(){
TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
if(idle_0 == NULL || esp_task_wdt_delete(idle_0) != ESP_OK){
log_e("Failed to remove Core 0 IDLE task from WDT");
}
}
#ifndef CONFIG_FREERTOS_UNICORE
void enableCore1WDT(){
TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1);
if(idle_1 == NULL || esp_task_wdt_add(idle_1) != ESP_OK){
log_e("Failed to add Core 1 IDLE task to WDT");
}
}
void disableCore1WDT(){
TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1);
if(idle_1 == NULL || esp_task_wdt_delete(idle_1) != ESP_OK){
log_e("Failed to remove Core 1 IDLE task from WDT");
}
}
#endif
unsigned long IRAM_ATTR micros()
{
return (unsigned long) esp_timer_get_time();
return (unsigned long) (esp_timer_get_time());
}
unsigned long IRAM_ATTR millis()
{
return (unsigned long) (esp_timer_get_time() / 1000);
return (unsigned long) (esp_timer_get_time() / 1000ULL);
}
void delay(uint32_t ms)
@ -76,6 +148,9 @@ void initVariant() {}
void init() __attribute__((weak));
void init() {}
bool verifyOta() __attribute__((weak));
bool verifyOta() { return true; }
#ifdef CONFIG_BT_ENABLED
//overwritten in esp32-hal-bt.c
bool btInUse() __attribute__((weak));
@ -84,6 +159,25 @@ 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();
}
}
}
#endif
//init proper ref tick value for PLL (uncomment if REF_TICK is different than 1MHz)
//ESP_REG(APB_CTRL_PLL_TICK_CONF_REG) = APB_CLK_FREQ / REF_CLK_FREQ - 1;
#ifdef F_CPU
setCpuFrequencyMhz(F_CPU/1000000);
#endif
#if CONFIG_SPIRAM_SUPPORT
psramInit();
#endif

View File

@ -19,7 +19,7 @@ bool psramInit(){
}
uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG);
uint32_t pkg_ver = chip_ver & 0x7;
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 || pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2 || pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) {
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 || pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) {
spiramFailed = true;
log_w("PSRAM not supported!");
return false;

View File

@ -156,7 +156,7 @@ bool rmtSetCarrier(rmt_obj_t* rmt, bool carrier_en, bool carrier_level, uint32_t
RMT_MUTEX_LOCK(channel);
RMT.carrier_duty_ch[channel].low = low;
RMT.carrier_duty_ch[channel].low = high;
RMT.carrier_duty_ch[channel].high = high;
RMT.conf_ch[channel].conf0.carrier_en = carrier_en;
RMT.conf_ch[channel].conf0.carrier_out_lv = carrier_level;
@ -637,13 +637,13 @@ static void IRAM_ATTR _rmt_isr(void* arg)
data += MAX_DATA_PER_CHANNEL*(g_rmt_objects[ch].buffers);
}
}
uint32_t *data_received = data;
for (i = 0; i < g_rmt_objects[ch].data_size; i++ ) {
*data++ = RMTMEM.chan[ch].data32[i].val;
}
if (g_rmt_objects[ch].cb) {
// actually received data ptr
uint32_t * data = g_rmt_objects[ch].data_ptr;
(g_rmt_objects[ch].cb)(data, _rmt_get_mem_len(ch));
// actually received data ptr
(g_rmt_objects[ch].cb)(data_received, _rmt_get_mem_len(ch));
// restart the reception
RMT.conf_ch[ch].conf1.mem_owner = 1;

View File

@ -31,6 +31,26 @@
xSemaphoreHandle _sd_sys_lock;
#endif
static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
if(old_apb == new_apb){
return;
}
uint32_t iarg = (uint32_t)arg;
uint8_t channel = iarg;
if(ev_type == APB_BEFORE_CHANGE){
SIGMADELTA.cg.clk_en = 0;
} else {
old_apb /= 1000000;
new_apb /= 1000000;
SD_MUTEX_LOCK();
uint32_t old_prescale = SIGMADELTA.channel[channel].prescale + 1;
SIGMADELTA.channel[channel].prescale = ((new_apb * old_prescale) / old_apb) - 1;
SIGMADELTA.cg.clk_en = 0;
SIGMADELTA.cg.clk_en = 1;
SD_MUTEX_UNLOCK();
}
}
uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq) //chan 0-7 freq 1220-312500
{
if(channel > 7) {
@ -43,7 +63,8 @@ uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq) //chan 0-7 freq 1220-31
_sd_sys_lock = xSemaphoreCreateMutex();
}
#endif
uint32_t prescale = (10000000/(freq*32)) - 1;
uint32_t apb_freq = getApbFrequency();
uint32_t prescale = (apb_freq/(freq*256)) - 1;
if(prescale > 0xFF) {
prescale = 0xFF;
}
@ -52,7 +73,9 @@ uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq) //chan 0-7 freq 1220-31
SIGMADELTA.cg.clk_en = 0;
SIGMADELTA.cg.clk_en = 1;
SD_MUTEX_UNLOCK();
return 10000000/((prescale + 1) * 32);
uint32_t iarg = channel;
addApbChangeCallback((void*)iarg, _on_apb_change);
return apb_freq/((prescale + 1) * 256);
}
void sigmaDeltaWrite(uint8_t channel, uint8_t duty) //chan 0-7 duty 8 bit

View File

@ -26,6 +26,7 @@
#include "soc/io_mux_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/dport_reg.h"
#include "soc/rtc.h"
#define SPI_CLK_IDX(p) ((p==0)?SPICLK_OUT_IDX:((p==1)?SPICLK_OUT_IDX:((p==2)?HSPICLK_OUT_IDX:((p==3)?VSPICLK_OUT_IDX:0))))
#define SPI_MISO_IDX(p) ((p==0)?SPIQ_OUT_IDX:((p==1)?SPIQ_OUT_IDX:((p==2)?HSPIQ_OUT_IDX:((p==3)?VSPIQ_OUT_IDX:0))))
@ -371,6 +372,18 @@ void spiSetBitOrder(spi_t * spi, uint8_t bitOrder)
SPI_MUTEX_UNLOCK();
}
static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb)
{
spi_t * spi = (spi_t *)arg;
if(ev_type == APB_BEFORE_CHANGE){
SPI_MUTEX_LOCK();
while(spi->dev->cmd.usr);
} else {
spi->dev->clock.val = spiFrequencyToClockDiv(old_apb / ((spi->dev->clock.clkdiv_pre + 1) * (spi->dev->clock.clkcnt_n + 1)));
SPI_MUTEX_UNLOCK();
}
}
void spiStopBus(spi_t * spi)
{
if(!spi) {
@ -387,6 +400,7 @@ void spiStopBus(spi_t * spi)
spi->dev->ctrl2.val = 0;
spi->dev->clock.val = 0;
SPI_MUTEX_UNLOCK();
removeApbChangeCallback(spi, _on_apb_change);
}
spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder)
@ -433,6 +447,7 @@ spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_
}
SPI_MUTEX_UNLOCK();
addApbChangeCallback(spi, _on_apb_change);
return spi;
}
@ -750,7 +765,7 @@ void spiEndTransaction(spi_t * spi)
SPI_MUTEX_UNLOCK();
}
void spiWriteByteNL(spi_t * spi, uint8_t data)
void IRAM_ATTR spiWriteByteNL(spi_t * spi, uint8_t data)
{
if(!spi) {
return;
@ -776,7 +791,7 @@ uint8_t spiTransferByteNL(spi_t * spi, uint8_t data)
return data;
}
void spiWriteShortNL(spi_t * spi, uint16_t data)
void IRAM_ATTR spiWriteShortNL(spi_t * spi, uint16_t data)
{
if(!spi) {
return;
@ -811,7 +826,7 @@ uint16_t spiTransferShortNL(spi_t * spi, uint16_t data)
return data;
}
void spiWriteLongNL(spi_t * spi, uint32_t data)
void IRAM_ATTR spiWriteLongNL(spi_t * spi, uint32_t data)
{
if(!spi) {
return;
@ -959,7 +974,7 @@ void spiTransferBitsNL(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits)
}
}
void spiWritePixelsNL(spi_t * spi, const void * data_in, size_t len){
void IRAM_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, size_t len){
size_t longs = len >> 2;
if(len & 3){
longs++;
@ -1007,35 +1022,37 @@ void spiWritePixelsNL(spi_t * spi, const void * data_in, size_t len){
* */
typedef union {
uint32_t regValue;
uint32_t value;
struct {
unsigned regL :6;
unsigned regH :6;
unsigned regN :6;
unsigned regPre :13;
unsigned regEQU :1;
uint32_t clkcnt_l: 6; /*it must be equal to spi_clkcnt_N.*/
uint32_t clkcnt_h: 6; /*it must be floor((spi_clkcnt_N+1)/2-1).*/
uint32_t clkcnt_n: 6; /*it is the divider of spi_clk. So spi_clk frequency is system/(spi_clkdiv_pre+1)/(spi_clkcnt_N+1)*/
uint32_t clkdiv_pre: 13; /*it is pre-divider of spi_clk.*/
uint32_t clk_equ_sysclk: 1; /*1: spi_clk is eqaul to system 0: spi_clk is divided from system clock.*/
};
} spiClk_t;
#define ClkRegToFreq(reg) (CPU_CLK_FREQ / (((reg)->regPre + 1) * ((reg)->regN + 1)))
#define ClkRegToFreq(reg) (apb_freq / (((reg)->clkdiv_pre + 1) * ((reg)->clkcnt_n + 1)))
uint32_t spiClockDivToFrequency(uint32_t clockDiv)
{
uint32_t apb_freq = getApbFrequency();
spiClk_t reg = { clockDiv };
return ClkRegToFreq(&reg);
}
uint32_t spiFrequencyToClockDiv(uint32_t freq)
{
uint32_t apb_freq = getApbFrequency();
if(freq >= CPU_CLK_FREQ) {
if(freq >= apb_freq) {
return SPI_CLK_EQU_SYSCLK;
}
const spiClk_t minFreqReg = { 0x7FFFF000 };
uint32_t minFreq = ClkRegToFreq((spiClk_t*) &minFreqReg);
if(freq < minFreq) {
return minFreqReg.regValue;
return minFreqReg.value;
}
uint8_t calN = 1;
@ -1048,18 +1065,18 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq)
int32_t calPre;
int8_t calPreVari = -2;
reg.regN = calN;
reg.clkcnt_n = calN;
while(calPreVari++ <= 1) {
calPre = (((CPU_CLK_FREQ / (reg.regN + 1)) / freq) - 1) + calPreVari;
calPre = (((apb_freq / (reg.clkcnt_n + 1)) / freq) - 1) + calPreVari;
if(calPre > 0x1FFF) {
reg.regPre = 0x1FFF;
reg.clkdiv_pre = 0x1FFF;
} else if(calPre <= 0) {
reg.regPre = 0;
reg.clkdiv_pre = 0;
} else {
reg.regPre = calPre;
reg.clkdiv_pre = calPre;
}
reg.regL = ((reg.regN + 1) / 2);
reg.clkcnt_l = ((reg.clkcnt_n + 1) / 2);
calFreq = ClkRegToFreq(&reg);
if(calFreq == (int32_t) freq) {
memcpy(&bestReg, &reg, sizeof(bestReg));
@ -1076,6 +1093,6 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq)
}
calN++;
}
return bestReg.regValue;
return bestReg.value;
}

View File

@ -17,9 +17,9 @@
static void setTimeZone(long offset, int daylight)
{
char cst[16] = {0};
char cdt[16] = "DST";
char tz[32] = {0};
char cst[17] = {0};
char cdt[17] = "DST";
char tz[33] = {0};
if(offset % 3600){
sprintf(cst, "UTC%ld:%02u:%02u", offset / 3600, abs((offset % 3600) / 60), abs(offset % 60));

View File

@ -84,7 +84,7 @@ void IRAM_ATTR __timerISR(void * arg){
i = 4;
//call callbacks
while(i--){
if(__timerInterruptHandlers[i] && status & (1 << i)){
if(__timerInterruptHandlers[i] && (status & (1 << i))){
__timerInterruptHandlers[i]();
}
}
@ -184,6 +184,18 @@ bool timerAlarmEnabled(hw_timer_t *timer){
return timer->dev->config.alarm_en;
}
static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
hw_timer_t * timer = (hw_timer_t *)arg;
if(ev_type == APB_BEFORE_CHANGE){
timer->dev->config.enable = 0;
} else {
old_apb /= 1000000;
new_apb /= 1000000;
timer->dev->config.divider = (new_apb * timer->dev->config.divider) / old_apb;
timer->dev->config.enable = 1;
}
}
hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
if(num > 3){
return NULL;
@ -205,12 +217,14 @@ hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
timerAttachInterrupt(timer, NULL, false);
timerWrite(timer, 0);
timer->dev->config.enable = 1;
addApbChangeCallback(timer, _on_apb_change);
return timer;
}
void timerEnd(hw_timer_t *timer){
timer->dev->config.enable = 0;
timerAttachInterrupt(timer, NULL, false);
removeApbChangeCallback(timer, _on_apb_change);
}
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
@ -271,23 +285,23 @@ void timerDetachInterrupt(hw_timer_t *timer){
uint64_t timerReadMicros(hw_timer_t *timer){
uint64_t timer_val = timerRead(timer);
uint16_t div = timerGetDivider(timer);
return timer_val * div / 80;
return timer_val * div / (getApbFrequency() / 1000000);
}
double timerReadSeconds(hw_timer_t *timer){
uint64_t timer_val = timerRead(timer);
uint16_t div = timerGetDivider(timer);
return (double)timer_val * div / 80000000;
return (double)timer_val * div / getApbFrequency();
}
uint64_t timerAlarmReadMicros(hw_timer_t *timer){
uint64_t timer_val = timerAlarmRead(timer);
uint16_t div = timerGetDivider(timer);
return timer_val * div / 80;
return timer_val * div / (getApbFrequency() / 1000000);
}
double timerAlarmReadSeconds(hw_timer_t *timer){
uint64_t timer_val = timerAlarmRead(timer);
uint16_t div = timerGetDivider(timer);
return (double)timer_val * div / 80000000;
return (double)timer_val * div / getApbFrequency();
}

View File

@ -27,6 +27,7 @@
#include "soc/io_mux_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/dport_reg.h"
#include "soc/rtc.h"
#include "esp_intr_alloc.h"
#define UART_REG_BASE(u) ((u==0)?DR_REG_UART_BASE:( (u==1)?DR_REG_UART1_BASE:( (u==2)?DR_REG_UART2_BASE:0)))
@ -66,6 +67,8 @@ static uart_t _uart_bus_array[3] = {
};
#endif
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb);
static void IRAM_ATTR _uart_isr(void *arg)
{
uint8_t i, c;
@ -215,6 +218,7 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
uartAttachTx(uart, txPin, inverted);
}
addApbChangeCallback(uart, uart_on_apb_change);
return uart;
}
@ -223,11 +227,10 @@ void uartEnd(uart_t* uart)
if(uart == NULL) {
return;
}
removeApbChangeCallback(uart, uart_on_apb_change);
UART_MUTEX_LOCK();
if(uart->queue != NULL) {
uint8_t c;
while(xQueueReceive(uart->queue, &c, 0));
vQueueDelete(uart->queue);
uart->queue = NULL;
}
@ -247,8 +250,6 @@ size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) {
UART_MUTEX_LOCK();
if(uart->queue != NULL) {
uint8_t c;
while(xQueueReceive(uart->queue, &c, 0));
vQueueDelete(uart->queue);
uart->queue = xQueueCreate(new_size, sizeof(uint8_t));
if(uart->queue == NULL) {
@ -318,10 +319,9 @@ void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len)
}
UART_MUTEX_LOCK();
while(len) {
while(len && uart->dev->status.txfifo_cnt < 0x7F) {
uart->dev->fifo.rw_byte = *data++;
len--;
}
while(uart->dev->status.txfifo_cnt == 0x7F);
uart->dev->fifo.rw_byte = *data++;
len--;
}
UART_MUTEX_UNLOCK();
}
@ -352,19 +352,55 @@ void uartSetBaudRate(uart_t* uart, uint32_t baud_rate)
return;
}
UART_MUTEX_LOCK();
uint32_t clk_div = ((UART_CLK_FREQ<<4)/baud_rate);
uint32_t clk_div = ((getApbFrequency()<<4)/baud_rate);
uart->dev->clk_div.div_int = clk_div>>4 ;
uart->dev->clk_div.div_frag = clk_div & 0xf;
UART_MUTEX_UNLOCK();
}
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb)
{
uart_t* uart = (uart_t*)arg;
if(ev_type == APB_BEFORE_CHANGE){
UART_MUTEX_LOCK();
//disabple interrupt
uart->dev->int_ena.val = 0;
uart->dev->int_clr.val = 0xffffffff;
// read RX fifo
uint8_t c;
BaseType_t xHigherPriorityTaskWoken;
while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
c = uart->dev->fifo.rw_byte;
if(uart->queue != NULL && !xQueueIsQueueFullFromISR(uart->queue)) {
xQueueSendFromISR(uart->queue, &c, &xHigherPriorityTaskWoken);
}
}
// wait TX empty
while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out);
} else {
//todo:
// set baudrate
uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F);
uint32_t baud_rate = ((old_apb<<4)/clk_div);
clk_div = ((new_apb<<4)/baud_rate);
uart->dev->clk_div.div_int = clk_div>>4 ;
uart->dev->clk_div.div_frag = clk_div & 0xf;
//enable interrupts
uart->dev->int_ena.rxfifo_full = 1;
uart->dev->int_ena.frm_err = 1;
uart->dev->int_ena.rxfifo_tout = 1;
uart->dev->int_clr.val = 0xffffffff;
UART_MUTEX_UNLOCK();
}
}
uint32_t uartGetBaudRate(uart_t* uart)
{
if(uart == NULL) {
return 0;
}
uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F);
return ((UART_CLK_FREQ<<4)/clk_div);
return ((getApbFrequency()<<4)/clk_div);
}
static void IRAM_ATTR uart0_write_char(char c)
@ -385,17 +421,8 @@ static void IRAM_ATTR uart2_write_char(char c)
ESP_REG(DR_REG_UART2_BASE) = c;
}
void uartSetDebug(uart_t* uart)
void uart_install_putc()
{
if(uart == NULL || uart->num > 2) {
s_uart_debug_nr = -1;
ets_install_putc1(NULL);
return;
}
if(s_uart_debug_nr == uart->num) {
return;
}
s_uart_debug_nr = uart->num;
switch(s_uart_debug_nr) {
case 0:
ets_install_putc1((void (*)(char)) &uart0_write_char);
@ -412,6 +439,20 @@ void uartSetDebug(uart_t* uart)
}
}
void uartSetDebug(uart_t* uart)
{
if(uart == NULL || uart->num > 2) {
s_uart_debug_nr = -1;
//ets_install_putc1(NULL);
//return;
} else
if(s_uart_debug_nr == uart->num) {
return;
} else
s_uart_debug_nr = uart->num;
uart_install_putc();
}
int uartGetDebug()
{
return s_uart_debug_nr;
@ -440,7 +481,7 @@ int log_printf(const char *format, ...)
vsnprintf(temp, len+1, format, arg);
#if !CONFIG_DISABLE_HAL_LOCKS
if(_uart_bus_array[s_uart_debug_nr].lock){
while (xSemaphoreTake(_uart_bus_array[s_uart_debug_nr].lock, portMAX_DELAY) != pdPASS);
xSemaphoreTake(_uart_bus_array[s_uart_debug_nr].lock, portMAX_DELAY);
ets_printf("%s", temp);
xSemaphoreGive(_uart_bus_array[s_uart_debug_nr].lock);
} else {
@ -450,7 +491,7 @@ int log_printf(const char *format, ...)
ets_printf("%s", temp);
#endif
va_end(arg);
if(len > 64){
if(len >= sizeof(loc_buf)){
free(temp);
}
return len;
@ -499,7 +540,7 @@ uartDetectBaudrate(uart_t *uart)
uart->dev->auto_baud.en = 0;
uartStateDetectingBaudrate = false; // Initialize for the next round
unsigned long baudrate = UART_CLK_FREQ / divisor;
unsigned long baudrate = getApbFrequency() / divisor;
static const unsigned long default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400};
@ -517,3 +558,10 @@ uartDetectBaudrate(uart_t *uart)
return default_rates[i];
}
/*
* Returns the status of the RX state machine, if the value is non-zero the state machine is active.
*/
bool uartRxActive(uart_t* uart) {
return uart->dev->status.st_urx_out != 0;
}

View File

@ -74,6 +74,8 @@ int uartGetDebug();
unsigned long uartDetectBaudrate(uart_t *uart);
bool uartRxActive(uart_t* uart);
#ifdef __cplusplus
}
#endif

View File

@ -62,6 +62,7 @@ void yield(void);
#include "esp32-hal-timer.h"
#include "esp32-hal-bt.h"
#include "esp32-hal-psram.h"
#include "esp32-hal-cpu.h"
#ifndef BOARD_HAS_PSRAM
#ifdef CONFIG_SPIRAM_SUPPORT
@ -72,6 +73,23 @@ void yield(void);
//returns chip temperature in Celsius
float temperatureRead();
#if CONFIG_AUTOSTART_ARDUINO
//enable/disable WDT for Arduino's setup and loop functions
void enableLoopWDT();
void disableLoopWDT();
//feed WDT for the loop task
void feedLoopWDT();
#endif
//enable/disable WDT for the IDLE task on Core 0 (SYSTEM)
void enableCore0WDT();
void disableCore0WDT();
#ifndef CONFIG_FREERTOS_UNICORE
//enable/disable WDT for the IDLE task on Core 1 (Arduino)
void enableCore1WDT();
void disableCore1WDT();
#endif
unsigned long micros();
unsigned long millis();
void delay(uint32_t);

View File

@ -1,7 +1,10 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
#include "Arduino.h"
TaskHandle_t loopTaskHandle = NULL;
#if CONFIG_AUTOSTART_ARDUINO
#if CONFIG_FREERTOS_UNICORE
@ -10,18 +13,24 @@
#define ARDUINO_RUNNING_CORE 1
#endif
bool loopTaskWDTEnabled;
void loopTask(void *pvParameters)
{
setup();
for(;;) {
if(loopTaskWDTEnabled){
esp_task_wdt_reset();
}
loop();
}
}
extern "C" void app_main()
{
loopTaskWDTEnabled = false;
initArduino();
xTaskCreatePinnedToCore(loopTask, "loopTask", 8192, NULL, 1, NULL, ARDUINO_RUNNING_CORE);
xTaskCreatePinnedToCore(loopTask, "loopTask", 8192, NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
}
#endif

View File

@ -25,11 +25,12 @@ uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
uint8_t i;
for(i = 0; i < 8; ++i) {
digitalWrite(clockPin, HIGH);
//digitalWrite(clockPin, HIGH);
if(bitOrder == LSBFIRST)
value |= digitalRead(dataPin) << i;
else
value |= digitalRead(dataPin) << (7 - i);
digitalWrite(clockPin, HIGH);
digitalWrite(clockPin, LOW);
}
return value;

View File

@ -16,7 +16,7 @@ Installation instructions for Debian / Ubuntu OS
cd esp32 && \
git submodule update --init --recursive && \
cd tools && \
python2 get.py
python3 get.py
```
- Restart Arduino IDE
@ -32,5 +32,5 @@ Installation instructions for Debian / Ubuntu OS
cd esp32 && \
git submodule update --init --recursive && \
cd tools && \
python2 get.py
python3 get.py
```

View File

@ -561,26 +561,48 @@ static esp_err_t joinMulticastGroup(const ip_addr_t *addr, bool join, tcpip_adap
return ESP_ERR_INVALID_ARG;
}
netif = (struct netif *)nif;
}
if (addr->type == IPADDR_TYPE_V4) {
if(join){
if (igmp_joingroup_netif(netif, (const ip4_addr *)&(addr->u_addr.ip4))) {
return ESP_ERR_INVALID_STATE;
if (addr->type == IPADDR_TYPE_V4) {
if(join){
if (igmp_joingroup_netif(netif, (const ip4_addr *)&(addr->u_addr.ip4))) {
return ESP_ERR_INVALID_STATE;
}
} else {
if (igmp_leavegroup_netif(netif, (const ip4_addr *)&(addr->u_addr.ip4))) {
return ESP_ERR_INVALID_STATE;
}
}
} else {
if (igmp_leavegroup_netif(netif, (const ip4_addr *)&(addr->u_addr.ip4))) {
return ESP_ERR_INVALID_STATE;
if(join){
if (mld6_joingroup_netif(netif, &(addr->u_addr.ip6))) {
return ESP_ERR_INVALID_STATE;
}
} else {
if (mld6_leavegroup_netif(netif, &(addr->u_addr.ip6))) {
return ESP_ERR_INVALID_STATE;
}
}
}
} else {
if(join){
if (mld6_joingroup_netif(netif, &(addr->u_addr.ip6))) {
return ESP_ERR_INVALID_STATE;
} else {
if (addr->type == IPADDR_TYPE_V4) {
if(join){
if (igmp_joingroup((const ip4_addr *)IP4_ADDR_ANY, (const ip4_addr *)&(addr->u_addr.ip4))) {
return ESP_ERR_INVALID_STATE;
}
} else {
if (igmp_leavegroup((const ip4_addr *)IP4_ADDR_ANY, (const ip4_addr *)&(addr->u_addr.ip4))) {
return ESP_ERR_INVALID_STATE;
}
}
} else {
if (mld6_leavegroup_netif(netif, &(addr->u_addr.ip6))) {
return ESP_ERR_INVALID_STATE;
if(join){
if (mld6_joingroup((const ip6_addr *)IP6_ADDR_ANY, &(addr->u_addr.ip6))) {
return ESP_ERR_INVALID_STATE;
}
} else {
if (mld6_leavegroup((const ip6_addr *)IP6_ADDR_ANY, &(addr->u_addr.ip6))) {
return ESP_ERR_INVALID_STATE;
}
}
}
}

View File

@ -279,6 +279,7 @@ size_t EEPROMClass::readString (int address, char* value, size_t maxLen)
return 0;
memcpy((uint8_t*) value, _data + address, len);
value[len] = 0;
return len;
}

View File

@ -0,0 +1,173 @@
#include "esp_camera.h"
#include <WiFi.h>
//
// WARNING!!! Make sure that you have either selected ESP32 Wrover Module,
// or another board which has PSRAM enabled
//
// Select camera model
#define CAMERA_MODEL_WROVER_KIT
//#define CAMERA_MODEL_ESP_EYE
//#define CAMERA_MODEL_M5STACK_PSRAM
//#define CAMERA_MODEL_AI_THINKER
const char* ssid = "*********";
const char* password = "*********";
#if defined(CAMERA_MODEL_WROVER_KIT)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 21
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 19
#define Y4_GPIO_NUM 18
#define Y3_GPIO_NUM 5
#define Y2_GPIO_NUM 4
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
#elif defined(CAMERA_MODEL_ESP_EYE)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 4
#define SIOD_GPIO_NUM 18
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 36
#define Y8_GPIO_NUM 37
#define Y7_GPIO_NUM 38
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 35
#define Y4_GPIO_NUM 14
#define Y3_GPIO_NUM 13
#define Y2_GPIO_NUM 34
#define VSYNC_GPIO_NUM 5
#define HREF_GPIO_NUM 27
#define PCLK_GPIO_NUM 25
#elif defined(CAMERA_MODEL_M5STACK_PSRAM)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 25
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 32
#define VSYNC_GPIO_NUM 22
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#elif defined(CAMERA_MODEL_AI_THINKER)
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
#else
#error "Camera model not selected"
#endif
void startCameraServer();
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
//init with high specs to pre-allocate larger buffers
if(psramFound()){
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
#if defined(CAMERA_MODEL_ESP_EYE)
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
#endif
// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
//drop down frame size for higher initial frame rate
sensor_t * s = esp_camera_sensor_get();
s->set_framesize(s, FRAMESIZE_QVGA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
startCameraServer();
Serial.print("Camera Ready! Use 'http://");
Serial.print(WiFi.localIP());
Serial.println("' to connect");
}
void loop() {
// put your main code here, to run repeatedly:
delay(10000);
}

View File

@ -0,0 +1,650 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "esp_http_server.h"
#include "esp_timer.h"
#include "esp_camera.h"
#include "img_converters.h"
#include "camera_index.h"
#include "Arduino.h"
#include "fb_gfx.h"
#include "fd_forward.h"
#include "dl_lib.h"
#include "fr_forward.h"
#define ENROLL_CONFIRM_TIMES 5
#define FACE_ID_SAVE_NUMBER 7
#define FACE_COLOR_WHITE 0x00FFFFFF
#define FACE_COLOR_BLACK 0x00000000
#define FACE_COLOR_RED 0x000000FF
#define FACE_COLOR_GREEN 0x0000FF00
#define FACE_COLOR_BLUE 0x00FF0000
#define FACE_COLOR_YELLOW (FACE_COLOR_RED | FACE_COLOR_GREEN)
#define FACE_COLOR_CYAN (FACE_COLOR_BLUE | FACE_COLOR_GREEN)
#define FACE_COLOR_PURPLE (FACE_COLOR_BLUE | FACE_COLOR_RED)
typedef struct {
size_t size; //number of values used for filtering
size_t index; //current value index
size_t count; //value count
int sum;
int * values; //array to be filled with values
} ra_filter_t;
typedef struct {
httpd_req_t *req;
size_t len;
} jpg_chunking_t;
#define PART_BOUNDARY "123456789000000000000987654321"
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
static ra_filter_t ra_filter;
httpd_handle_t stream_httpd = NULL;
httpd_handle_t camera_httpd = NULL;
static mtmn_config_t mtmn_config = {0};
static int8_t detection_enabled = 0;
static int8_t recognition_enabled = 0;
static int8_t is_enrolling = 0;
static face_id_list id_list = {0};
static ra_filter_t * ra_filter_init(ra_filter_t * filter, size_t sample_size){
memset(filter, 0, sizeof(ra_filter_t));
filter->values = (int *)malloc(sample_size * sizeof(int));
if(!filter->values){
return NULL;
}
memset(filter->values, 0, sample_size * sizeof(int));
filter->size = sample_size;
return filter;
}
static int ra_filter_run(ra_filter_t * filter, int value){
if(!filter->values){
return value;
}
filter->sum -= filter->values[filter->index];
filter->values[filter->index] = value;
filter->sum += filter->values[filter->index];
filter->index++;
filter->index = filter->index % filter->size;
if (filter->count < filter->size) {
filter->count++;
}
return filter->sum / filter->count;
}
static void rgb_print(dl_matrix3du_t *image_matrix, 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);
}
static int rgb_printf(dl_matrix3du_t *image_matrix, uint32_t color, const char *format, ...){
char loc_buf[64];
char * temp = loc_buf;
int len;
va_list arg;
va_list copy;
va_start(arg, format);
va_copy(copy, arg);
len = vsnprintf(loc_buf, sizeof(loc_buf), format, arg);
va_end(copy);
if(len >= sizeof(loc_buf)){
temp = (char*)malloc(len+1);
if(temp == NULL) {
return 0;
}
}
vsnprintf(temp, len+1, format, arg);
va_end(arg);
rgb_print(image_matrix, color, temp);
if(len > 64){
free(temp);
}
return len;
}
static void draw_face_boxes(dl_matrix3du_t *image_matrix, box_array_t *boxes, int face_id){
int x, y, w, h, i;
uint32_t color = FACE_COLOR_YELLOW;
if(face_id < 0){
color = FACE_COLOR_RED;
} else if(face_id > 0){
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++){
// 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
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);
}
#endif
}
}
static int run_face_recognition(dl_matrix3du_t *image_matrix, box_array_t *net_boxes){
dl_matrix3du_t *aligned_face = NULL;
int matched_id = 0;
aligned_face = dl_matrix3du_alloc(1, FACE_WIDTH, FACE_HEIGHT, 3);
if(!aligned_face){
Serial.println("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);
if(left_sample_face == (ENROLL_CONFIRM_TIMES - 1)){
Serial.printf("Enrolling Face ID: %d\n", id_list.tail);
}
Serial.printf("Enrolling Face ID: %d sample %d\n", 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;
Serial.printf("Enrolled Face ID: %d\n", id_list.tail);
}
} else {
matched_id = recognize_face(&id_list, aligned_face);
if (matched_id >= 0) {
Serial.printf("Match Face ID: %u\n", matched_id);
rgb_printf(image_matrix, FACE_COLOR_GREEN, "Hello Subject %u", matched_id);
} else {
Serial.println("No Match Found");
rgb_print(image_matrix, FACE_COLOR_RED, "Intruder Alert!");
matched_id = -1;
}
}
} else {
Serial.println("Face Not Aligned");
//rgb_print(image_matrix, FACE_COLOR_YELLOW, "Human Detected");
}
dl_matrix3du_free(aligned_face);
return matched_id;
}
static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len){
jpg_chunking_t *j = (jpg_chunking_t *)arg;
if(!index){
j->len = 0;
}
if(httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK){
return 0;
}
j->len += len;
return len;
}
static esp_err_t capture_handler(httpd_req_t *req){
camera_fb_t * fb = NULL;
esp_err_t res = ESP_OK;
int64_t fr_start = esp_timer_get_time();
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
httpd_resp_send_500(req);
return ESP_FAIL;
}
httpd_resp_set_type(req, "image/jpeg");
httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg");
size_t out_len, out_width, out_height;
uint8_t * out_buf;
bool s;
bool detected = false;
int face_id = 0;
if(!detection_enabled || fb->width > 400){
size_t fb_len = 0;
if(fb->format == PIXFORMAT_JPEG){
fb_len = fb->len;
res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
} else {
jpg_chunking_t jchunk = {req, 0};
res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk)?ESP_OK:ESP_FAIL;
httpd_resp_send_chunk(req, NULL, 0);
fb_len = jchunk.len;
}
esp_camera_fb_return(fb);
int64_t fr_end = esp_timer_get_time();
Serial.printf("JPG: %uB %ums\n", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start)/1000));
return res;
}
dl_matrix3du_t *image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3);
if (!image_matrix) {
esp_camera_fb_return(fb);
Serial.println("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);
Serial.println("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(recognition_enabled){
face_id = run_face_recognition(image_matrix, net_boxes);
}
draw_face_boxes(image_matrix, net_boxes, face_id);
free(net_boxes->box);
free(net_boxes->landmark);
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){
Serial.println("JPEG compression failed");
return ESP_FAIL;
}
int64_t fr_end = esp_timer_get_time();
Serial.printf("FACE: %uB %ums %s%d\n", (uint32_t)(jchunk.len), (uint32_t)((fr_end - fr_start)/1000), detected?"DETECTED ":"", face_id);
return res;
}
static esp_err_t stream_handler(httpd_req_t *req){
camera_fb_t * fb = NULL;
esp_err_t res = ESP_OK;
size_t _jpg_buf_len = 0;
uint8_t * _jpg_buf = NULL;
char * part_buf[64];
dl_matrix3du_t *image_matrix = NULL;
bool detected = false;
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;
static int64_t last_frame = 0;
if(!last_frame) {
last_frame = esp_timer_get_time();
}
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if(res != ESP_OK){
return res;
}
while(true){
detected = false;
face_id = 0;
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
res = ESP_FAIL;
} else {
fr_start = esp_timer_get_time();
fr_ready = fr_start;
fr_face = fr_start;
fr_encode = fr_start;
fr_recognize = fr_start;
if(!detection_enabled || fb->width > 400){
if(fb->format != PIXFORMAT_JPEG){
bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
esp_camera_fb_return(fb);
fb = NULL;
if(!jpeg_converted){
Serial.println("JPEG compression failed");
res = ESP_FAIL;
}
} else {
_jpg_buf_len = fb->len;
_jpg_buf = fb->buf;
}
} else {
image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3);
if (!image_matrix) {
Serial.println("dl_matrix3du_alloc failed");
res = ESP_FAIL;
} else {
if(!fmt2rgb888(fb->buf, fb->len, fb->format, image_matrix->item)){
Serial.println("fmt2rgb888 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(recognition_enabled){
face_id = run_face_recognition(image_matrix, net_boxes);
}
fr_recognize = esp_timer_get_time();
draw_face_boxes(image_matrix, net_boxes, face_id);
free(net_boxes->box);
free(net_boxes->landmark);
free(net_boxes);
}
if(!fmt2jpg(image_matrix->item, fb->width*fb->height*3, fb->width, fb->height, PIXFORMAT_RGB888, 90, &_jpg_buf, &_jpg_buf_len)){
Serial.println("fmt2jpg failed");
res = ESP_FAIL;
}
esp_camera_fb_return(fb);
fb = NULL;
} else {
_jpg_buf = fb->buf;
_jpg_buf_len = fb->len;
}
fr_encode = esp_timer_get_time();
}
dl_matrix3du_free(image_matrix);
}
}
}
if(res == ESP_OK){
size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}
if(fb){
esp_camera_fb_return(fb);
fb = NULL;
_jpg_buf = NULL;
} else if(_jpg_buf){
free(_jpg_buf);
_jpg_buf = NULL;
}
if(res != ESP_OK){
break;
}
int64_t fr_end = esp_timer_get_time();
int64_t ready_time = (fr_ready - fr_start)/1000;
int64_t face_time = (fr_face - fr_ready)/1000;
int64_t recognize_time = (fr_recognize - fr_face)/1000;
int64_t encode_time = (fr_encode - fr_recognize)/1000;
int64_t process_time = (fr_encode - fr_start)/1000;
int64_t frame_time = fr_end - last_frame;
last_frame = fr_end;
frame_time /= 1000;
uint32_t avg_frame_time = ra_filter_run(&ra_filter, frame_time);
Serial.printf("MJPG: %uB %ums (%.1ffps), AVG: %ums (%.1ffps), %u+%u+%u+%u=%u %s%d\n",
(uint32_t)(_jpg_buf_len),
(uint32_t)frame_time, 1000.0 / (uint32_t)frame_time,
avg_frame_time, 1000.0 / avg_frame_time,
(uint32_t)ready_time, (uint32_t)face_time, (uint32_t)recognize_time, (uint32_t)encode_time, (uint32_t)process_time,
(detected)?"DETECTED ":"", face_id
);
}
last_frame = 0;
return res;
}
static esp_err_t cmd_handler(httpd_req_t *req){
char* buf;
size_t buf_len;
char variable[32] = {0,};
char value[32] = {0,};
buf_len = httpd_req_get_url_query_len(req) + 1;
if (buf_len > 1) {
buf = (char*)malloc(buf_len);
if(!buf){
httpd_resp_send_500(req);
return ESP_FAIL;
}
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
if (httpd_query_key_value(buf, "var", variable, sizeof(variable)) == ESP_OK &&
httpd_query_key_value(buf, "val", value, sizeof(value)) == ESP_OK) {
} else {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
} else {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
free(buf);
} else {
httpd_resp_send_404(req);
return ESP_FAIL;
}
int val = atoi(value);
sensor_t * s = esp_camera_sensor_get();
int res = 0;
if(!strcmp(variable, "framesize")) {
if(s->pixformat == PIXFORMAT_JPEG) res = s->set_framesize(s, (framesize_t)val);
}
else if(!strcmp(variable, "quality")) res = s->set_quality(s, val);
else if(!strcmp(variable, "contrast")) res = s->set_contrast(s, val);
else if(!strcmp(variable, "brightness")) res = s->set_brightness(s, val);
else if(!strcmp(variable, "saturation")) res = s->set_saturation(s, val);
else if(!strcmp(variable, "gainceiling")) res = s->set_gainceiling(s, (gainceiling_t)val);
else if(!strcmp(variable, "colorbar")) res = s->set_colorbar(s, val);
else if(!strcmp(variable, "awb")) res = s->set_whitebal(s, val);
else if(!strcmp(variable, "agc")) res = s->set_gain_ctrl(s, val);
else if(!strcmp(variable, "aec")) res = s->set_exposure_ctrl(s, val);
else if(!strcmp(variable, "hmirror")) res = s->set_hmirror(s, val);
else if(!strcmp(variable, "vflip")) res = s->set_vflip(s, val);
else if(!strcmp(variable, "awb_gain")) res = s->set_awb_gain(s, val);
else if(!strcmp(variable, "agc_gain")) res = s->set_agc_gain(s, val);
else if(!strcmp(variable, "aec_value")) res = s->set_aec_value(s, val);
else if(!strcmp(variable, "aec2")) res = s->set_aec2(s, val);
else if(!strcmp(variable, "dcw")) res = s->set_dcw(s, val);
else if(!strcmp(variable, "bpc")) res = s->set_bpc(s, val);
else if(!strcmp(variable, "wpc")) res = s->set_wpc(s, val);
else if(!strcmp(variable, "raw_gma")) res = s->set_raw_gma(s, val);
else if(!strcmp(variable, "lenc")) res = s->set_lenc(s, val);
else if(!strcmp(variable, "special_effect")) res = s->set_special_effect(s, val);
else if(!strcmp(variable, "wb_mode")) res = s->set_wb_mode(s, val);
else if(!strcmp(variable, "ae_level")) res = s->set_ae_level(s, val);
else if(!strcmp(variable, "face_detect")) {
detection_enabled = val;
if(!detection_enabled) {
recognition_enabled = 0;
}
}
else if(!strcmp(variable, "face_enroll")) is_enrolling = val;
else if(!strcmp(variable, "face_recognize")) {
recognition_enabled = val;
if(recognition_enabled){
detection_enabled = val;
}
}
else {
res = -1;
}
if(res){
return httpd_resp_send_500(req);
}
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}
static esp_err_t status_handler(httpd_req_t *req){
static char json_response[1024];
sensor_t * s = esp_camera_sensor_get();
char * p = json_response;
*p++ = '{';
p+=sprintf(p, "\"framesize\":%u,", s->status.framesize);
p+=sprintf(p, "\"quality\":%u,", s->status.quality);
p+=sprintf(p, "\"brightness\":%d,", s->status.brightness);
p+=sprintf(p, "\"contrast\":%d,", s->status.contrast);
p+=sprintf(p, "\"saturation\":%d,", s->status.saturation);
p+=sprintf(p, "\"special_effect\":%u,", s->status.special_effect);
p+=sprintf(p, "\"wb_mode\":%u,", s->status.wb_mode);
p+=sprintf(p, "\"awb\":%u,", s->status.awb);
p+=sprintf(p, "\"awb_gain\":%u,", s->status.awb_gain);
p+=sprintf(p, "\"aec\":%u,", s->status.aec);
p+=sprintf(p, "\"aec2\":%u,", s->status.aec2);
p+=sprintf(p, "\"ae_level\":%d,", s->status.ae_level);
p+=sprintf(p, "\"aec_value\":%u,", s->status.aec_value);
p+=sprintf(p, "\"agc\":%u,", s->status.agc);
p+=sprintf(p, "\"agc_gain\":%u,", s->status.agc_gain);
p+=sprintf(p, "\"gainceiling\":%u,", s->status.gainceiling);
p+=sprintf(p, "\"bpc\":%u,", s->status.bpc);
p+=sprintf(p, "\"wpc\":%u,", s->status.wpc);
p+=sprintf(p, "\"raw_gma\":%u,", s->status.raw_gma);
p+=sprintf(p, "\"lenc\":%u,", s->status.lenc);
p+=sprintf(p, "\"vflip\":%u,", s->status.vflip);
p+=sprintf(p, "\"hmirror\":%u,", s->status.hmirror);
p+=sprintf(p, "\"dcw\":%u,", s->status.dcw);
p+=sprintf(p, "\"colorbar\":%u,", s->status.colorbar);
p+=sprintf(p, "\"face_detect\":%u,", detection_enabled);
p+=sprintf(p, "\"face_enroll\":%u,", is_enrolling);
p+=sprintf(p, "\"face_recognize\":%u", recognition_enabled);
*p++ = '}';
*p++ = 0;
httpd_resp_set_type(req, "application/json");
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, json_response, strlen(json_response));
}
static esp_err_t index_handler(httpd_req_t *req){
httpd_resp_set_type(req, "text/html");
httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
return httpd_resp_send(req, (const char *)index_html_gz, index_html_gz_len);
}
void startCameraServer(){
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
httpd_uri_t index_uri = {
.uri = "/",
.method = HTTP_GET,
.handler = index_handler,
.user_ctx = NULL
};
httpd_uri_t status_uri = {
.uri = "/status",
.method = HTTP_GET,
.handler = status_handler,
.user_ctx = NULL
};
httpd_uri_t cmd_uri = {
.uri = "/control",
.method = HTTP_GET,
.handler = cmd_handler,
.user_ctx = NULL
};
httpd_uri_t capture_uri = {
.uri = "/capture",
.method = HTTP_GET,
.handler = capture_handler,
.user_ctx = NULL
};
httpd_uri_t stream_uri = {
.uri = "/stream",
.method = HTTP_GET,
.handler = stream_handler,
.user_ctx = NULL
};
ra_filter_init(&ra_filter, 20);
mtmn_config.min_face = 80;
mtmn_config.pyramid = 0.7;
mtmn_config.p_threshold.score = 0.6;
mtmn_config.p_threshold.nms = 0.7;
mtmn_config.r_threshold.score = 0.7;
mtmn_config.r_threshold.nms = 0.7;
mtmn_config.r_threshold.candidate_number = 4;
mtmn_config.o_threshold.score = 0.7;
mtmn_config.o_threshold.nms = 0.4;
mtmn_config.o_threshold.candidate_number = 1;
face_id_init(&id_list, FACE_ID_SAVE_NUMBER, ENROLL_CONFIRM_TIMES);
Serial.printf("Starting web server on port: '%d'\n", config.server_port);
if (httpd_start(&camera_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(camera_httpd, &index_uri);
httpd_register_uri_handler(camera_httpd, &cmd_uri);
httpd_register_uri_handler(camera_httpd, &status_uri);
httpd_register_uri_handler(camera_httpd, &capture_uri);
}
config.server_port += 1;
config.ctrl_port += 1;
Serial.printf("Starting stream server on port: '%d'\n", config.server_port);
if (httpd_start(&stream_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(stream_httpd, &stream_uri);
}
}

View File

@ -0,0 +1,233 @@
//File: index.html.gz, Size: 3663
#define index_html_gz_len 3663
const uint8_t index_html_gz[] = {
0x1F, 0x8B, 0x08, 0x08, 0x60, 0x15, 0x36, 0x5C, 0x00, 0x03, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x2E,
0x68, 0x74, 0x6D, 0x6C, 0x00, 0xDD, 0x5C, 0xEB, 0x72, 0x9B, 0xC8, 0x12, 0xFE, 0x7F, 0x9E, 0x02,
0x93, 0xDD, 0x08, 0x6A, 0x91, 0x2C, 0xC9, 0x8A, 0xE3, 0x20, 0x0B, 0x1F, 0x5B, 0x76, 0x92, 0xAD,
0xCA, 0x6D, 0xE3, 0x3D, 0xBB, 0x5B, 0xB5, 0xB5, 0x95, 0x8C, 0x60, 0x90, 0x26, 0x46, 0x8C, 0x02,
0x83, 0x2E, 0xD1, 0xF2, 0x1C, 0xE7, 0x81, 0xCE, 0x8B, 0x9D, 0x9E, 0x19, 0x40, 0xA0, 0x8B, 0x65,
0x49, 0x89, 0x94, 0x5A, 0xBB, 0xCA, 0x1A, 0xA0, 0xBB, 0xA7, 0xBB, 0xBF, 0xBE, 0x0C, 0x88, 0xF1,
0xF9, 0x91, 0x43, 0x6D, 0x36, 0x19, 0x60, 0xA5, 0xC7, 0xFA, 0x9E, 0xF5, 0xAF, 0x73, 0xF9, 0xA1,
0xC0, 0xCF, 0x79, 0x0F, 0x23, 0x47, 0x0E, 0xC5, 0x61, 0x1F, 0x33, 0xA4, 0xD8, 0x3D, 0x14, 0x84,
0x98, 0xB5, 0xD4, 0x88, 0xB9, 0xE5, 0x33, 0x75, 0xFE, 0xB2, 0x8F, 0xFA, 0xB8, 0xA5, 0x0E, 0x09,
0x1E, 0x0D, 0x68, 0xC0, 0x54, 0xC5, 0xA6, 0x3E, 0xC3, 0x3E, 0x90, 0x8F, 0x88, 0xC3, 0x7A, 0x2D,
0x07, 0x0F, 0x89, 0x8D, 0xCB, 0xE2, 0xC0, 0x20, 0x3E, 0x61, 0x04, 0x79, 0xE5, 0xD0, 0x46, 0x1E,
0x6E, 0xD5, 0xF2, 0xB2, 0x18, 0x61, 0x1E, 0xB6, 0x6E, 0x6E, 0xDF, 0x9D, 0xD4, 0x95, 0xB7, 0xBF,
0xD5, 0x1B, 0xA7, 0xD5, 0xF3, 0x63, 0x79, 0x6E, 0x46, 0x13, 0xB2, 0x09, 0x3F, 0xEE, 0x50, 0x67,
0x32, 0x75, 0x61, 0x9A, 0xB2, 0x8B, 0xFA, 0xC4, 0x9B, 0x98, 0x97, 0x01, 0x08, 0x35, 0x5E, 0x62,
0x6F, 0x88, 0x19, 0xB1, 0x91, 0x11, 0x22, 0x3F, 0x2C, 0x87, 0x38, 0x20, 0x6E, 0xB3, 0x83, 0xEC,
0xBB, 0x6E, 0x40, 0x23, 0xDF, 0x31, 0x1F, 0xD5, 0xCE, 0xF8, 0x6F, 0xD3, 0xA6, 0x1E, 0x0D, 0xCC,
0x47, 0x37, 0xCF, 0xF9, 0x6F, 0x53, 0xC8, 0x09, 0xC9, 0x17, 0x6C, 0xD6, 0x4E, 0x07, 0xE3, 0xB8,
0x57, 0x9F, 0xE6, 0xCE, 0x9C, 0xC1, 0x99, 0x10, 0xDB, 0x8C, 0x50, 0xBF, 0xD2, 0x47, 0xC4, 0x9F,
0x3A, 0x24, 0x1C, 0x78, 0x68, 0x62, 0xBA, 0x1E, 0x1E, 0xC7, 0x8F, 0xFA, 0xD8, 0x8F, 0x8C, 0xC2,
0x75, 0x7E, 0xBE, 0xEC, 0x90, 0x40, 0x9E, 0x33, 0x61, 0xAA, 0xA8, 0xEF, 0x4B, 0xC2, 0x8C, 0xD7,
0xA7, 0x3E, 0x6E, 0x0A, 0xC2, 0x51, 0x80, 0x06, 0x70, 0xC8, 0x3F, 0x9A, 0x7D, 0xE2, 0x4B, 0x27,
0x99, 0x27, 0x8D, 0xEA, 0x60, 0x5C, 0x50, 0xFC, 0xE4, 0x94, 0xFF, 0x36, 0x07, 0xC8, 0x71, 0x88,
0xDF, 0x35, 0xCF, 0xF8, 0x65, 0x1A, 0x38, 0x38, 0x28, 0x07, 0xC8, 0x21, 0x51, 0x68, 0x36, 0xE0,
0x4C, 0x1F, 0x05, 0x5D, 0x90, 0xC1, 0xE8, 0xC0, 0x2C, 0xD7, 0xAA, 0xB3, 0x13, 0x01, 0xE9, 0xF6,
0x98, 0xC9, 0xCF, 0xC4, 0x8F, 0x12, 0x6C, 0x0A, 0x66, 0xE4, 0x54, 0x11, 0x8A, 0x20, 0x8F, 0x74,
0xFD, 0x32, 0x61, 0xB8, 0x1F, 0x9A, 0x21, 0x0B, 0x30, 0xB3, 0x7B, 0xB1, 0x4B, 0xBA, 0x51, 0x80,
0xA7, 0xA9, 0x02, 0xD5, 0x44, 0x36, 0x0C, 0xCA, 0x23, 0xDC, 0xB9, 0x23, 0xAC, 0x9C, 0x4C, 0xD6,
0xC1, 0x2E, 0x0D, 0x70, 0x46, 0x50, 0xEE, 0x78, 0xD4, 0xBE, 0x2B, 0x87, 0x0C, 0x05, 0x6C, 0x91,
0x18, 0xB9, 0x0C, 0x07, 0xF3, 0xB4, 0x18, 0x0C, 0x5E, 0xA0, 0x4C, 0x05, 0x24, 0x87, 0xC4, 0xF7,
0x88, 0x8F, 0x57, 0x89, 0x95, 0x12, 0x8A, 0xA4, 0xE2, 0x5C, 0x62, 0x86, 0x42, 0xFA, 0xDD, 0xCC,
0x03, 0x62, 0xD2, 0xA6, 0x74, 0x7C, 0xAD, 0x5A, 0xFD, 0xB1, 0xD9, 0xC3, 0xC2, 0x5F, 0x28, 0x62,
0xF4, 0x7E, 0x27, 0xF3, 0xD8, 0xF8, 0x77, 0x1F, 0x3B, 0x04, 0x29, 0xDA, 0x0C, 0x3C, 0xE5, 0xAC,
0x0A, 0x9E, 0xD6, 0x15, 0xE4, 0x3B, 0x8A, 0x46, 0x03, 0x02, 0xDE, 0x46, 0x22, 0x14, 0x3C, 0x38,
0x03, 0x61, 0x3F, 0xC0, 0xFA, 0x74, 0x1D, 0x0C, 0x49, 0x44, 0xAC, 0x06, 0x62, 0x89, 0x05, 0x7D,
0x34, 0x2E, 0xE7, 0xAC, 0xE0, 0x87, 0x89, 0x25, 0x90, 0x6A, 0xB6, 0x06, 0x27, 0x87, 0x3D, 0xA5,
0xAC, 0xF0, 0xD0, 0xD2, 0x13, 0x73, 0x85, 0x89, 0x39, 0x73, 0xFF, 0x29, 0x28, 0xA7, 0x19, 0xFB,
0xA8, 0x13, 0x31, 0x46, 0xFD, 0x70, 0x8D, 0x9B, 0x3F, 0x45, 0x21, 0x23, 0xEE, 0xA4, 0x9C, 0x80,
0x62, 0x86, 0x03, 0x04, 0xF5, 0xAA, 0x83, 0xD9, 0x08, 0x63, 0x48, 0x5D, 0x1F, 0x0D, 0x01, 0xEE,
0x6E, 0xD7, 0xC3, 0x53, 0x3B, 0x0A, 0x42, 0xA8, 0x1C, 0x03, 0x4A, 0x80, 0x32, 0x68, 0x16, 0x00,
0xC8, 0x13, 0x96, 0xED, 0xCE, 0x94, 0x46, 0x8C, 0xAB, 0x04, 0x2A, 0x52, 0x90, 0x47, 0xD8, 0x04,
0x46, 0xD2, 0xED, 0xD5, 0xD4, 0xE7, 0xD5, 0x39, 0x1E, 0xD3, 0xEE, 0x61, 0xFB, 0x0E, 0x3B, 0x3F,
0x15, 0xCB, 0x85, 0x28, 0x35, 0x15, 0xE2, 0x0F, 0x22, 0x56, 0xE6, 0x05, 0x61, 0xB0, 0xC6, 0x1E,
0xE1, 0x89, 0x64, 0x8A, 0x7A, 0x3D, 0x8B, 0x59, 0xF3, 0xC9, 0x60, 0xAC, 0x54, 0x0B, 0x82, 0x2C,
0x0F, 0x75, 0xB0, 0x97, 0x89, 0x4B, 0x9C, 0x28, 0xE3, 0x29, 0x09, 0x82, 0x5C, 0xF5, 0xC8, 0x55,
0xA8, 0xC6, 0xD3, 0x1F, 0x0B, 0x82, 0x14, 0x31, 0x36, 0x0A, 0xA7, 0x42, 0xEC, 0x01, 0x0C, 0xB2,
0x20, 0xC2, 0x99, 0x91, 0x59, 0x8B, 0x2B, 0x01, 0xF2, 0xBB, 0x18, 0x00, 0x1C, 0x1B, 0xE9, 0x30,
0x57, 0x52, 0x97, 0x4D, 0x6F, 0x56, 0x15, 0x50, 0x3B, 0x96, 0x40, 0x2E, 0x44, 0x7C, 0x6A, 0x56,
0x8E, 0xBA, 0x56, 0xCF, 0x6A, 0x23, 0x38, 0xBA, 0xE0, 0x0A, 0x5E, 0x35, 0xE7, 0x10, 0x4C, 0x3A,
0x81, 0xEB, 0x16, 0xFB, 0x84, 0xEB, 0x9E, 0x54, 0x4F, 0x1A, 0x73, 0xD9, 0xCF, 0xE7, 0x29, 0xF6,
0x8A, 0x66, 0x86, 0x71, 0xA2, 0xA0, 0xD9, 0xA3, 0x43, 0x1C, 0x4C, 0x8B, 0xA2, 0x1A, 0xCF, 0x1A,
0x4E, 0x7A, 0x1D, 0x41, 0x5C, 0x0E, 0x71, 0x91, 0xA0, 0x5E, 0xB3, 0xEB, 0xB5, 0x84, 0xA0, 0x02,
0x16, 0xA2, 0x8E, 0x87, 0x9D, 0x34, 0xD4, 0x1C, 0xEC, 0xA2, 0xC8, 0x63, 0x05, 0xED, 0x50, 0x95,
0xFF, 0xC6, 0xC2, 0xD7, 0x7F, 0xF2, 0x36, 0xDE, 0x12, 0xBE, 0xFC, 0x6B, 0x9A, 0x26, 0x08, 0x1A,
0x0C, 0x30, 0x82, 0x73, 0x36, 0x96, 0xAD, 0x66, 0xB1, 0xB8, 0x89, 0xB0, 0x58, 0xD2, 0x60, 0xE6,
0xDC, 0x93, 0xA6, 0xFF, 0xE2, 0x5C, 0xA6, 0x4B, 0xED, 0x28, 0x9C, 0x05, 0xF9, 0x12, 0x0A, 0x33,
0x55, 0x27, 0xF4, 0x88, 0x70, 0x63, 0xE4, 0xFB, 0xDC, 0xB6, 0x32, 0x0B, 0x60, 0xE2, 0xE9, 0x12,
0xA5, 0x16, 0xF1, 0xC9, 0xAB, 0x98, 0xB4, 0xEB, 0x22, 0x28, 0xD5, 0x0C, 0x6B, 0x25, 0xA4, 0x30,
0x8F, 0x92, 0x90, 0x3D, 0x40, 0x1F, 0xD6, 0x8B, 0xFA, 0x9D, 0x69, 0xC2, 0x5E, 0x83, 0xDC, 0x90,
0x02, 0x82, 0x6E, 0x07, 0x69, 0x55, 0xA3, 0x6A, 0x9C, 0xC0, 0x1F, 0xBD, 0xE0, 0x30, 0xA9, 0x72,
0xBD, 0xBE, 0xD0, 0x7D, 0x9F, 0xCC, 0xF7, 0xEB, 0x24, 0x80, 0xE6, 0xAC, 0x59, 0x85, 0x4F, 0xA1,
0x71, 0xD7, 0x2A, 0x3C, 0xE0, 0x57, 0x38, 0x7C, 0x9D, 0x53, 0x17, 0xFD, 0xB5, 0xD4, 0x11, 0x7D,
0xFA, 0xA5, 0x2C, 0xF3, 0xEF, 0x60, 0x58, 0xE4, 0x54, 0xD8, 0x37, 0x0E, 0xCB, 0xF5, 0x09, 0xB7,
0xF4, 0x45, 0x55, 0x49, 0xED, 0x2E, 0xCB, 0x6A, 0x02, 0x62, 0x7C, 0x68, 0x21, 0x01, 0xB4, 0x92,
0xE6, 0xC2, 0x99, 0x55, 0x73, 0xBB, 0xC4, 0xF3, 0xCA, 0x1E, 0x1D, 0xCD, 0x55, 0x8F, 0x82, 0x9F,
0xE7, 0xFD, 0x3A, 0xEF, 0xFE, 0x7B, 0x65, 0x47, 0x10, 0x73, 0xDF, 0x40, 0xF6, 0xFE, 0x93, 0x68,
0x06, 0xCA, 0x3D, 0x49, 0xB2, 0xCE, 0xA3, 0x0F, 0x60, 0x5D, 0x74, 0x98, 0xAC, 0x91, 0x71, 0x25,
0x1C, 0x11, 0x58, 0x89, 0xCD, 0x35, 0xA3, 0x01, 0x0D, 0x89, 0x58, 0xE6, 0x05, 0xD8, 0x43, 0xBC,
0xC8, 0x2F, 0xB6, 0xE1, 0xB9, 0xE6, 0x91, 0xBB, 0x94, 0xCA, 0x94, 0x6D, 0xF4, 0x61, 0x4B, 0x87,
0x8A, 0xAC, 0x00, 0x49, 0xBC, 0x0A, 0xE7, 0x15, 0x8A, 0x7B, 0xC1, 0xB7, 0xF5, 0x7B, 0x63, 0x38,
0x09, 0xDC, 0x6E, 0x80, 0x27, 0xA9, 0x58, 0x23, 0xF9, 0x34, 0xE5, 0x4A, 0x6F, 0x79, 0x8F, 0x16,
0x71, 0x2D, 0xAD, 0xAE, 0x34, 0xC2, 0x78, 0x8E, 0x65, 0xD1, 0x23, 0xE9, 0x02, 0x4B, 0x55, 0x17,
0xA0, 0xCF, 0x92, 0x4D, 0xB8, 0x26, 0xC9, 0x41, 0x3E, 0xF4, 0xB0, 0xCB, 0xC4, 0xC2, 0x9B, 0x57,
0xC7, 0x93, 0x42, 0x84, 0x94, 0x67, 0xDD, 0x5B, 0xE2, 0x99, 0xAD, 0x9F, 0x52, 0xDF, 0x2C, 0xA3,
0xE5, 0x31, 0xB5, 0x9C, 0x3C, 0x55, 0x3C, 0x2D, 0xB1, 0xC2, 0x3C, 0x38, 0xD3, 0x97, 0x09, 0x0C,
0x46, 0xE0, 0x3F, 0xB4, 0xFA, 0x29, 0x5F, 0x3F, 0xAF, 0xBE, 0x14, 0x27, 0xCB, 0x9E, 0x85, 0x94,
0x48, 0x5B, 0x6C, 0x2E, 0x0A, 0x1A, 0x73, 0x98, 0xCD, 0x70, 0x5F, 0x58, 0x79, 0xC0, 0x6A, 0xAB,
0x8F, 0xA0, 0x58, 0x72, 0x17, 0xC2, 0x6D, 0x26, 0xD8, 0xB6, 0xE8, 0xDE, 0xD9, 0xF2, 0xAC, 0x76,
0xCA, 0x6F, 0xF6, 0x2A, 0xB6, 0x47, 0xC3, 0x1C, 0x0E, 0xA8, 0x03, 0x9A, 0x44, 0x0C, 0x37, 0xE5,
0x92, 0xEE, 0x49, 0xE2, 0xD4, 0x27, 0xCB, 0xD3, 0x2E, 0x87, 0x41, 0x1E, 0x9A, 0xA2, 0x66, 0x35,
0x7E, 0xAF, 0x93, 0x5F, 0x45, 0x31, 0x3C, 0x86, 0xFE, 0xC6, 0xEF, 0x5B, 0x4C, 0x1B, 0x8B, 0x30,
0xCB, 0xA7, 0x41, 0x6D, 0x71, 0x09, 0x16, 0x57, 0x7A, 0xC4, 0x71, 0xB0, 0x5F, 0xB8, 0x39, 0x8E,
0x67, 0x77, 0xFC, 0xC7, 0xC9, 0x2D, 0xBF, 0x3C, 0x98, 0x3D, 0x9D, 0x38, 0xE7, 0xCF, 0x00, 0xF2,
0x4F, 0x06, 0xE4, 0x92, 0x5F, 0xB1, 0x3D, 0x14, 0x86, 0x2D, 0x95, 0xDF, 0x8B, 0xE7, 0x1E, 0x2E,
0x08, 0x12, 0x87, 0x0C, 0x15, 0xE2, 0xB4, 0x54, 0x8F, 0x76, 0xE9, 0xDC, 0x35, 0x71, 0x5D, 0x2C,
0x86, 0x15, 0x40, 0xB5, 0xA5, 0x16, 0x96, 0xE5, 0xAA, 0xE0, 0x9A, 0x9D, 0x52, 0xAD, 0xC7, 0x8F,
0x9E, 0x3D, 0x7D, 0x7A, 0xDA, 0x7C, 0xEC, 0x77, 0xC2, 0x41, 0xF2, 0xF7, 0x57, 0x71, 0x09, 0x16,
0xBD, 0x8C, 0xC1, 0x42, 0x34, 0x3C, 0x3F, 0x16, 0xD2, 0xE6, 0x34, 0x38, 0x06, 0x15, 0x56, 0x28,
0x95, 0xE4, 0xC6, 0x32, 0xBD, 0x52, 0x92, 0x10, 0x82, 0xB4, 0x83, 0x82, 0x25, 0x24, 0x82, 0x4C,
0xC4, 0xB4, 0x22, 0x4A, 0x9A, 0x2A, 0x22, 0xBB, 0x43, 0xC7, 0xF3, 0xAA, 0x0B, 0x6B, 0x92, 0xB0,
0x4F, 0xA8, 0xB0, 0xB3, 0x4A, 0x20, 0xB0, 0x09, 0x76, 0x7E, 0x33, 0xB2, 0x82, 0x26, 0xD3, 0x2F,
0x71, 0x7B, 0x6E, 0xFD, 0x2F, 0xA7, 0x76, 0x03, 0xD4, 0xC7, 0x3C, 0xDA, 0x93, 0x93, 0xAB, 0xC5,
0xCC, 0x43, 0x90, 0x71, 0xAA, 0xD6, 0x7B, 0x2C, 0x02, 0x17, 0xE0, 0x5D, 0xEA, 0xD6, 0x05, 0x29,
0x32, 0x05, 0x8B, 0xF3, 0xAB, 0xA9, 0x8A, 0xC9, 0x8A, 0xBA, 0x8C, 0x44, 0xBC, 0xAC, 0x51, 0x48,
0x88, 0xA3, 0x03, 0x11, 0x59, 0x43, 0xE4, 0x45, 0xE0, 0xDA, 0x5A, 0x55, 0xB5, 0xFE, 0xF3, 0xC7,
0x8B, 0x4B, 0x0D, 0x92, 0xAC, 0x3A, 0xAE, 0xD5, 0xAB, 0x55, 0xFD, 0xFC, 0x58, 0x92, 0x6C, 0x2C,
0xEB, 0x99, 0x6A, 0xDD, 0x0A, 0x51, 0xF5, 0x33, 0x10, 0x55, 0xAD, 0x37, 0xB6, 0x17, 0x75, 0xA6,
0x5A, 0x42, 0x12, 0x08, 0x19, 0x3F, 0x3D, 0x3D, 0xDB, 0x5E, 0xD0, 0x53, 0xD0, 0xE9, 0x37, 0x90,
0x74, 0x06, 0xD6, 0x9D, 0xEE, 0x62, 0xDC, 0xA9, 0x6A, 0x71, 0x39, 0xA7, 0x8D, 0xEA, 0xB8, 0x71,
0xB6, 0x83, 0x9C, 0x27, 0x6A, 0x72, 0x2B, 0xC9, 0x43, 0x36, 0x1D, 0xA9, 0x56, 0xFB, 0xE7, 0xE7,
0x5A, 0x03, 0x74, 0xAC, 0x3F, 0x3B, 0xDD, 0x5E, 0x76, 0x43, 0xB5, 0x7E, 0xE1, 0x4A, 0x9E, 0xD4,
0x41, 0x50, 0x63, 0x07, 0x25, 0x4F, 0x54, 0xEB, 0xA5, 0x90, 0x04, 0x52, 0xC6, 0xB5, 0xA7, 0x3B,
0xA8, 0x04, 0xE1, 0xF5, 0x8B, 0x90, 0x04, 0xF1, 0xC5, 0xC3, 0xEB, 0x81, 0x92, 0xA0, 0x50, 0x0A,
0xD7, 0xDC, 0x93, 0xA7, 0x8B, 0xD5, 0xA7, 0x70, 0xF9, 0xBE, 0x34, 0xFE, 0x1C, 0x41, 0x4D, 0x67,
0x93, 0x8D, 0x93, 0x38, 0xE1, 0x03, 0x93, 0xE4, 0xE0, 0x61, 0xF9, 0x9B, 0xD3, 0x24, 0x7B, 0x4A,
0xA0, 0x5A, 0xB5, 0xEA, 0x1A, 0x0B, 0x04, 0x6F, 0xBE, 0x0A, 0x0A, 0xE6, 0x82, 0x01, 0xAA, 0x02,
0xA2, 0x44, 0x0E, 0x2B, 0x7D, 0x34, 0x86, 0x18, 0x3D, 0x51, 0x73, 0x79, 0xBD, 0x55, 0x89, 0x58,
0xA2, 0x2D, 0x1A, 0xAB, 0xD6, 0xE9, 0xC9, 0x3A, 0x7F, 0xEF, 0x00, 0x47, 0x47, 0x74, 0x70, 0x1F,
0x87, 0xE1, 0xC6, 0x88, 0xCC, 0x58, 0x55, 0xEB, 0x2A, 0x1B, 0xEF, 0x82, 0x4B, 0xB9, 0xBE, 0x03,
0x2E, 0x39, 0x75, 0x24, 0x34, 0xE5, 0x7A, 0x02, 0x4D, 0x5D, 0x9D, 0x65, 0xC4, 0xD7, 0x04, 0x66,
0x9D, 0xB6, 0xBB, 0xE0, 0xC2, 0x9B, 0x78, 0x80, 0x42, 0xB6, 0x31, 0x2A, 0x29, 0x23, 0x94, 0xB5,
0x64, 0x74, 0x30, 0x44, 0x32, 0x55, 0xFE, 0x01, 0x78, 0x84, 0x88, 0x45, 0x81, 0x78, 0xFA, 0xBE,
0x31, 0x22, 0x33, 0x56, 0xE8, 0x87, 0xD9, 0xF8, 0x60, 0xA8, 0xE4, 0xD4, 0xF9, 0x27, 0xE0, 0x32,
0xC0, 0x36, 0x41, 0xDE, 0x07, 0xEC, 0xBA, 0xD0, 0xB2, 0x36, 0xC7, 0xA6, 0xC0, 0x0E, 0xF8, 0xC8,
0x63, 0xE5, 0x46, 0x1C, 0x6F, 0xBC, 0x46, 0x9C, 0x13, 0xF7, 0xB5, 0x16, 0x8A, 0xD5, 0xE5, 0xEB,
0x96, 0x37, 0x34, 0xD3, 0x73, 0xCB, 0x15, 0x42, 0x0D, 0x84, 0xE0, 0xAE, 0xB8, 0xE7, 0xDB, 0x5A,
0x46, 0x5D, 0xB5, 0x5E, 0x04, 0x68, 0x22, 0xBE, 0x86, 0xDD, 0x65, 0xD1, 0xF3, 0x1E, 0x3B, 0xCA,
0xAF, 0x70, 0x23, 0xB7, 0xCB, 0x0A, 0xEC, 0x45, 0x80, 0xB1, 0xBF, 0x9B, 0x94, 0x27, 0xD0, 0xCC,
0x60, 0xB0, 0x9B, 0x10, 0x58, 0xB0, 0xDE, 0xE2, 0x01, 0x41, 0xDF, 0xC3, 0x82, 0x0B, 0x8D, 0x3A,
0x1B, 0xA7, 0x05, 0xF0, 0xA8, 0xD6, 0xE5, 0xEF, 0x57, 0x1B, 0x17, 0x29, 0xF9, 0xF0, 0xE9, 0x21,
0x11, 0x2E, 0xAB, 0x53, 0xA2, 0xA0, 0xBA, 0x70, 0xB3, 0xB9, 0x3C, 0x73, 0x1E, 0x7A, 0xC3, 0xB9,
0xC4, 0xAE, 0x54, 0x41, 0xF1, 0x7C, 0x46, 0xCD, 0x99, 0xF9, 0x30, 0x1B, 0xBF, 0x5D, 0x05, 0x03,
0x25, 0x3E, 0x74, 0x11, 0xD9, 0xBC, 0xAF, 0xA4, 0x8C, 0x02, 0x29, 0xE5, 0x05, 0x8C, 0xF6, 0x05,
0x97, 0x9C, 0xF6, 0x60, 0x98, 0x25, 0x56, 0x1F, 0x1A, 0x38, 0x50, 0xA4, 0x4F, 0x9D, 0xCD, 0x1F,
0x47, 0x24, 0x7C, 0xAA, 0x05, 0xA8, 0xBD, 0x86, 0xC1, 0xC6, 0x5D, 0x26, 0x15, 0xF0, 0x8D, 0xDB,
0xCB, 0x65, 0xC4, 0xE8, 0x2E, 0x9D, 0xE5, 0x36, 0xF2, 0xFD, 0xC9, 0x2E, 0x6D, 0xA5, 0xED, 0xD1,
0xC8, 0xD9, 0x5E, 0x02, 0xF4, 0x94, 0xB7, 0xAE, 0x4B, 0xEC, 0xED, 0xBB, 0x12, 0x74, 0x94, 0x97,
0xB4, 0xFF, 0x40, 0xFE, 0x6F, 0x5C, 0xC5, 0xB1, 0xBD, 0x79, 0x81, 0xC0, 0x36, 0xA0, 0x78, 0xD3,
0x56, 0x6E, 0x6F, 0xDE, 0xDC, 0xBE, 0x7D, 0xBF, 0x9F, 0xEA, 0x00, 0x73, 0x1E, 0xA8, 0x30, 0x70,
0x6B, 0x0F, 0x5D, 0x13, 0x40, 0x89, 0xFA, 0x36, 0x38, 0xD5, 0x25, 0x50, 0xD7, 0xB7, 0xEF, 0xF6,
0x85, 0x52, 0xFD, 0x70, 0x30, 0xD5, 0xBF, 0x07, 0x9C, 0x3E, 0x78, 0x78, 0x88, 0xBD, 0x2D, 0xB0,
0x92, 0x8C, 0x1C, 0x2F, 0xE5, 0x15, 0x1F, 0x1D, 0xEC, 0x46, 0x2E, 0x53, 0xE5, 0x1F, 0x70, 0x1B,
0x07, 0x51, 0xF1, 0x41, 0x28, 0xBD, 0x4D, 0xF2, 0x48, 0x4E, 0xD5, 0xBA, 0x19, 0x0F, 0x68, 0x18,
0x05, 0x0F, 0x6C, 0xA8, 0xCB, 0x11, 0xD9, 0xE5, 0xC9, 0xE0, 0x4C, 0x15, 0x89, 0x48, 0xFA, 0x68,
0x90, 0x3F, 0xD9, 0xCF, 0x30, 0xA9, 0x57, 0x1B, 0x5F, 0x15, 0x15, 0x2E, 0xFC, 0x5B, 0x02, 0xD3,
0xDD, 0xA2, 0xEF, 0x74, 0x79, 0xDF, 0x79, 0xD1, 0xDE, 0x4F, 0x29, 0xEB, 0x1E, 0xAC, 0xE1, 0x74,
0x0F, 0xDA, 0x70, 0x14, 0xF9, 0x6D, 0x67, 0x06, 0xD3, 0x96, 0x37, 0x11, 0x09, 0x23, 0xDC, 0x3B,
0x6F, 0x73, 0x03, 0x91, 0x7F, 0xA8, 0x3E, 0xDE, 0x25, 0x75, 0x52, 0x35, 0x8A, 0x99, 0x73, 0x32,
0xCB, 0x9B, 0x27, 0x5F, 0x35, 0x6B, 0x4E, 0xD6, 0x6A, 0xBB, 0x4B, 0xD2, 0x70, 0x4B, 0x6C, 0x4C,
0x3C, 0xFE, 0xD2, 0xE3, 0xA6, 0x80, 0xE4, 0x78, 0x25, 0x26, 0x4A, 0x5B, 0x1E, 0xED, 0x82, 0x4D,
0x7D, 0x17, 0x6C, 0xF2, 0x1A, 0x15, 0xE1, 0x39, 0xFD, 0x46, 0x9D, 0xA6, 0x56, 0x3F, 0xFB, 0x96,
0xF0, 0x74, 0x06, 0x9B, 0xD7, 0x34, 0xE0, 0x51, 0xAD, 0xAB, 0x77, 0xFB, 0xA9, 0x69, 0x7C, 0xB2,
0x07, 0xD6, 0xB4, 0x9D, 0x2A, 0x98, 0x30, 0xEA, 0xD0, 0x4B, 0xB1, 0xD1, 0x16, 0x68, 0x8C, 0xB8,
0xE2, 0xBF, 0xEF, 0x09, 0x8D, 0xD1, 0xC3, 0xD1, 0xF8, 0xCA, 0x1D, 0x66, 0xF4, 0x3D, 0xE0, 0x13,
0xA0, 0xD1, 0x87, 0x6E, 0x1F, 0x6D, 0x8C, 0x51, 0xC2, 0xA7, 0x5A, 0xEF, 0xD1, 0x48, 0x79, 0xF1,
0xFA, 0x72, 0x2F, 0x58, 0xA5, 0x93, 0x1E, 0x06, 0xAF, 0xCC, 0xE4, 0x43, 0x63, 0xE6, 0x61, 0x7F,
0xF3, 0xA4, 0xE2, 0x4C, 0xAA, 0xF5, 0x0A, 0xFB, 0xA1, 0xD2, 0xA6, 0x41, 0xB2, 0xED, 0x68, 0x2F,
0xA8, 0x89, 0x99, 0x0F, 0x03, 0x99, 0x34, 0xFA, 0xD0, 0x78, 0xF5, 0xFA, 0x24, 0x08, 0x68, 0xB0,
0x31, 0x64, 0x09, 0x9F, 0x6A, 0xBD, 0x2C, 0xBF, 0x16, 0xA3, 0xBD, 0xC0, 0x95, 0xCE, 0x7A, 0x18,
0xC4, 0x32, 0x9B, 0x0F, 0x0D, 0xDA, 0xD0, 0xF5, 0xC8, 0x60, 0x63, 0xC8, 0x04, 0x97, 0x6A, 0xFD,
0x56, 0x7E, 0x0E, 0x9F, 0x7B, 0x81, 0x4B, 0xCE, 0x78, 0x18, 0xB0, 0x12, 0x6B, 0x0F, 0x0D, 0x95,
0x63, 0x8F, 0x36, 0x06, 0x0A, 0x78, 0x54, 0xEB, 0xBA, 0xFD, 0xBB, 0xA2, 0x5D, 0xD3, 0x91, 0xCF,
0x5F, 0xFC, 0x53, 0x6E, 0xDE, 0xE8, 0x7B, 0x41, 0x8C, 0x4F, 0x7D, 0x18, 0xBC, 0x84, 0xD1, 0x87,
0x46, 0x4B, 0xBC, 0x04, 0xDC, 0x41, 0x9B, 0x97, 0xC3, 0x94, 0x91, 0xBF, 0xFB, 0x02, 0x23, 0xE5,
0x0A, 0xED, 0xA7, 0x20, 0x66, 0xF3, 0xEE, 0x63, 0xD1, 0x3E, 0x33, 0xF2, 0xD0, 0x38, 0xB9, 0xC8,
0xC6, 0x1F, 0x1C, 0xCC, 0xB6, 0x79, 0xF1, 0x22, 0xC7, 0xAB, 0x5A, 0xCF, 0xE1, 0x40, 0xB9, 0x16,
0x07, 0xFB, 0x5A, 0x72, 0xE4, 0xE7, 0xDF, 0x07, 0x6A, 0x05, 0x7B, 0xBF, 0x0B, 0xE0, 0x60, 0x81,
0x47, 0xBB, 0xFE, 0x56, 0xEF, 0x53, 0x17, 0xD8, 0x13, 0xF8, 0xDE, 0xCB, 0xE3, 0xFD, 0x02, 0x38,
0x53, 0x62, 0x6F, 0x18, 0xE6, 0xEC, 0xDE, 0x07, 0x8C, 0xE9, 0x66, 0x04, 0xF1, 0x58, 0x40, 0xEE,
0x41, 0x5E, 0x87, 0x94, 0x24, 0x93, 0x8F, 0x6E, 0x30, 0x2B, 0x87, 0x8C, 0x78, 0x9E, 0x6A, 0xBD,
0xC0, 0x4C, 0xB9, 0xE5, 0xC3, 0xF3, 0x63, 0x49, 0xF0, 0x70, 0x29, 0xC9, 0x0B, 0xFF, 0x7C, 0xDF,
0x38, 0xEA, 0xAB, 0xD6, 0x2D, 0xDF, 0x44, 0x0D, 0xB2, 0xF8, 0xD1, 0xE6, 0xC2, 0x84, 0x13, 0xB1,
0x1F, 0x50, 0x50, 0x2A, 0x03, 0x29, 0xD9, 0xAA, 0xAA, 0x2A, 0xE9, 0x28, 0x77, 0xCE, 0xBA, 0x11,
0xC4, 0x0A, 0x8F, 0xB2, 0xF5, 0xD3, 0xF1, 0x6F, 0x61, 0xED, 0xD5, 0x5F, 0xD6, 0x9E, 0x1F, 0xFB,
0x68, 0x89, 0xBB, 0x57, 0xA0, 0x70, 0x2E, 0x77, 0xB1, 0xAF, 0x10, 0x95, 0x6D, 0xA6, 0x10, 0x9E,
0x98, 0xED, 0xA7, 0xC9, 0xCC, 0x9A, 0xDB, 0x67, 0x93, 0x3E, 0xB0, 0x7D, 0x58, 0xD2, 0x8A, 0x1D,
0x37, 0x49, 0x3F, 0xE4, 0xC3, 0xCC, 0xFD, 0xFF, 0xFB, 0xEF, 0xBA, 0x98, 0x21, 0xFD, 0x6E, 0x4E,
0x31, 0x55, 0x09, 0x03, 0xBB, 0xA5, 0xAE, 0xDA, 0x9A, 0xB1, 0xC2, 0xF2, 0xE3, 0x65, 0xA6, 0xCF,
0x11, 0x2F, 0xF1, 0xF5, 0x79, 0x68, 0x07, 0x64, 0xC0, 0xAC, 0x7F, 0x39, 0xD4, 0x8E, 0xFA, 0xD8,
0x67, 0x15, 0xE4, 0x38, 0x37, 0x43, 0x18, 0xBC, 0x22, 0x21, 0xC3, 0xE0, 0x05, 0xAD, 0x74, 0xFD,
0xF6, 0x75, 0x5B, 0x6E, 0x51, 0x79, 0x45, 0x91, 0x83, 0x9D, 0x92, 0xE1, 0x46, 0xBE, 0x90, 0xA3,
0xE9, 0xD3, 0x74, 0xA8, 0x74, 0xB4, 0x2B, 0x7D, 0xEA, 0x41, 0xD0, 0xB6, 0x9B, 0xB2, 0x3C, 0x68,
0x57, 0x15, 0x9E, 0xE3, 0xFA, 0xD4, 0x46, 0x21, 0x2E, 0xA5, 0x89, 0x5E, 0x32, 0xDB, 0xAD, 0xAB,
0x4A, 0xB2, 0xF6, 0xB9, 0xA8, 0xF1, 0x0D, 0x4F, 0x60, 0xF4, 0x5D, 0x53, 0x10, 0x89, 0x47, 0x8A,
0x25, 0x53, 0x8C, 0xE5, 0x97, 0xF3, 0x65, 0xEA, 0x63, 0xC9, 0x22, 0x1E, 0x5C, 0xE6, 0x89, 0x65,
0x64, 0xA5, 0xD4, 0x51, 0xA7, 0x4F, 0x18, 0xA7, 0x2C, 0xD5, 0x4A, 0x09, 0x55, 0x52, 0x4A, 0xCC,
0x00, 0xB3, 0x28, 0xF0, 0x9B, 0x31, 0x00, 0x1B, 0x32, 0xE5, 0xBA, 0xF5, 0xF1, 0x87, 0xA9, 0x1D,
0x1F, 0x8B, 0x97, 0x5D, 0xA9, 0x77, 0x31, 0x44, 0x41, 0xEB, 0x87, 0xE9, 0x55, 0x85, 0x38, 0xF1,
0x63, 0x98, 0x03, 0xC6, 0xED, 0xF8, 0x63, 0xD3, 0xE5, 0xFF, 0x71, 0x41, 0xBB, 0xD6, 0x2B, 0xAC,
0x87, 0x7D, 0xED, 0xA6, 0x65, 0x4D, 0x39, 0x37, 0xF5, 0x70, 0xC5, 0xA3, 0x5D, 0xED, 0x63, 0x80,
0x3F, 0x47, 0x18, 0x84, 0x31, 0xAA, 0xFC, 0x30, 0xBD, 0x8E, 0x15, 0x97, 0xF8, 0x24, 0xEC, 0x61,
0xC7, 0x50, 0x42, 0x86, 0x58, 0x14, 0x9A, 0x70, 0xFA, 0xA6, 0x22, 0xC7, 0xF1, 0x47, 0x3D, 0xD6,
0x63, 0x98, 0x46, 0xB1, 0x5B, 0x99, 0x97, 0x3D, 0x6A, 0x8B, 0x57, 0x3A, 0x2B, 0x34, 0x20, 0x5D,
0xE2, 0x37, 0xA5, 0x6E, 0xB8, 0x75, 0x05, 0x33, 0x81, 0x7B, 0x78, 0x48, 0x71, 0x00, 0x38, 0x1A,
0x5A, 0x49, 0xC6, 0x61, 0x49, 0x8F, 0x0D, 0x77, 0x81, 0x20, 0xC0, 0x7D, 0x3A, 0xC4, 0x79, 0x9A,
0xEE, 0x72, 0x21, 0x69, 0x7E, 0x96, 0x74, 0xE3, 0x2A, 0xDB, 0x6B, 0xDE, 0x3A, 0xAA, 0xC6, 0x46,
0x6F, 0xA5, 0xD0, 0x15, 0x3C, 0xB5, 0xD8, 0x20, 0x2D, 0xED, 0xCA, 0x68, 0x1B, 0xD7, 0x3A, 0x70,
0x5E, 0xB7, 0x8E, 0x34, 0x3F, 0xF2, 0xBC, 0xA3, 0xD6, 0xB5, 0xFE, 0xF7, 0xDF, 0xD7, 0x4D, 0x1E,
0x04, 0x37, 0xCD, 0x19, 0xE2, 0xAD, 0x56, 0x4B, 0x86, 0xC2, 0x05, 0x38, 0x32, 0xC3, 0xDE, 0x68,
0xB7, 0x8E, 0x8E, 0xDA, 0x46, 0x76, 0xDC, 0x6A, 0xEB, 0xA6, 0xB8, 0x2E, 0x80, 0x36, 0x92, 0x4F,
0x38, 0x6B, 0x5C, 0x3F, 0x7E, 0x7C, 0x73, 0xD4, 0x6A, 0xB5, 0x2F, 0x78, 0x88, 0x99, 0x47, 0x70,
0xA8, 0x95, 0x10, 0xB6, 0xA5, 0x5C, 0xE2, 0x5C, 0xB4, 0x2F, 0xB0, 0x36, 0xD4, 0x4D, 0x97, 0xFF,
0x29, 0xA1, 0x6E, 0xFE, 0x82, 0xE6, 0x6A, 0x4C, 0x37, 0xB0, 0x16, 0xEA, 0x20, 0x1C, 0xF3, 0xB1,
0x2B, 0xC6, 0xA5, 0xF4, 0xAD, 0xA4, 0x1C, 0xAD, 0xAB, 0x8D, 0x75, 0x13, 0xF3, 0x3F, 0xA5, 0x62,
0xE3, 0x48, 0x69, 0x60, 0xDE, 0xF6, 0x45, 0x4F, 0xF3, 0x75, 0xB3, 0x0B, 0x7F, 0x74, 0x3D, 0x6E,
0x66, 0x70, 0x42, 0x34, 0x04, 0x93, 0x5B, 0x11, 0xB1, 0x34, 0xB8, 0xF4, 0x3C, 0xAD, 0x24, 0x77,
0xE0, 0x95, 0xF4, 0x0A, 0x74, 0xA2, 0x1B, 0xC4, 0xB3, 0x41, 0xF8, 0x98, 0xFA, 0xB6, 0x47, 0xEC,
0xBB, 0x96, 0xC6, 0x1D, 0x87, 0x21, 0x45, 0xE4, 0xDE, 0xE0, 0x37, 0xD4, 0xC1, 0x7A, 0x1C, 0x83,
0x7A, 0x22, 0xEE, 0x64, 0x84, 0xCA, 0xF0, 0xF9, 0x98, 0xC4, 0x60, 0x96, 0x73, 0x90, 0x66, 0x32,
0xA2, 0x95, 0xAB, 0xCA, 0xA7, 0x90, 0x27, 0x61, 0xBC, 0x84, 0xE4, 0x3E, 0xD5, 0x8A, 0x3D, 0x36,
0xA7, 0x63, 0x1B, 0x94, 0x22, 0x1A, 0x80, 0xF2, 0x67, 0x1B, 0xEC, 0xFD, 0xCB, 0x38, 0xAA, 0xF1,
0xD0, 0xD5, 0x93, 0xE8, 0xFC, 0x34, 0x0B, 0x5F, 0xE8, 0x53, 0x37, 0x1E, 0xE6, 0xC3, 0xAB, 0xC9,
0xCF, 0x10, 0x5C, 0xB2, 0x72, 0x41, 0x98, 0xDC, 0xAD, 0xA3, 0x99, 0x95, 0x57, 0xA0, 0xF6, 0x56,
0x53, 0x67, 0x9D, 0x10, 0xC8, 0xFA, 0xAB, 0xC9, 0x0A, 0xAD, 0x0E, 0x48, 0xFD, 0xD5, 0xA4, 0xB9,
0x46, 0x06, 0x84, 0x74, 0x35, 0x61, 0xBE, 0x7C, 0x03, 0xE5, 0x40, 0x82, 0x35, 0x22, 0xBE, 0x43,
0x47, 0x90, 0xD3, 0x74, 0xA0, 0x81, 0x4A, 0x15, 0xE2, 0x83, 0x0D, 0x2F, 0x7F, 0x7D, 0xFD, 0xAA,
0x55, 0xCA, 0x37, 0xD8, 0x52, 0x6C, 0x7C, 0x96, 0x0C, 0x9F, 0x2A, 0xBC, 0x8E, 0x73, 0x28, 0x7F,
0x2A, 0x99, 0x67, 0xB5, 0x12, 0x07, 0x94, 0x53, 0x7C, 0x84, 0x18, 0xBC, 0x5B, 0x90, 0x40, 0x07,
0x99, 0x80, 0xA6, 0x57, 0x0C, 0x13, 0x3E, 0xDF, 0x4C, 0x18, 0x54, 0x2E, 0x34, 0x00, 0xF8, 0xF1,
0xC5, 0x07, 0xBB, 0x03, 0xD5, 0xEA, 0x1A, 0x31, 0x5C, 0xF1, 0xE9, 0x08, 0xC2, 0x40, 0x4A, 0x8E,
0x0D, 0xBA, 0xC8, 0x8F, 0xC5, 0x85, 0x7E, 0xF1, 0x82, 0x84, 0xF5, 0xAA, 0x38, 0x3D, 0x04, 0x7B,
0x4E, 0xB5, 0xE6, 0xD5, 0x05, 0xB0, 0x9B, 0x9F, 0x41, 0xBA, 0xE1, 0x17, 0xB9, 0x3B, 0x90, 0x04,
0xB1, 0xB1, 0x55, 0x9C, 0x65, 0xB9, 0xD0, 0xE3, 0x05, 0x5F, 0x88, 0xE3, 0xB9, 0x9D, 0x45, 0x5A,
0xB0, 0x1A, 0x1C, 0x9E, 0xDF, 0xBA, 0x11, 0xDE, 0x4B, 0x90, 0xFB, 0x66, 0x15, 0x68, 0xD9, 0x3D,
0x41, 0x36, 0xFF, 0xBD, 0x5F, 0x49, 0x6F, 0x06, 0x45, 0xBD, 0xC0, 0xCC, 0x40, 0x37, 0x82, 0xAC,
0x63, 0xAD, 0xA8, 0x28, 0x71, 0xA2, 0x79, 0x74, 0x8F, 0x62, 0x98, 0x6B, 0x3E, 0xBC, 0x97, 0x20,
0xFF, 0x4E, 0x05, 0xE8, 0x12, 0x2D, 0xE8, 0x12, 0xE9, 0x46, 0x94, 0xE9, 0x92, 0x95, 0xBD, 0x74,
0xF6, 0xD1, 0x3D, 0xC2, 0xD3, 0x82, 0xA7, 0x1B, 0xE3, 0xD5, 0x54, 0x85, 0x57, 0x24, 0x41, 0x81,
0xD1, 0x82, 0x02, 0x23, 0xDD, 0x18, 0x65, 0x0A, 0x64, 0x25, 0x33, 0x55, 0x60, 0xB2, 0x26, 0xFD,
0xE4, 0x0D, 0x15, 0xE8, 0xF0, 0x65, 0x0D, 0xE1, 0xAC, 0xF8, 0xEA, 0xC6, 0xE5, 0x3D, 0xB4, 0xE9,
0x1E, 0x4F, 0xD0, 0xF5, 0x72, 0x41, 0xD7, 0x4B, 0xDD, 0x78, 0x72, 0x7E, 0x29, 0x1B, 0x09, 0x14,
0x6F, 0xA2, 0x4D, 0x78, 0x45, 0x33, 0x88, 0xF6, 0x85, 0x7F, 0x42, 0xF0, 0x4E, 0xE6, 0x58, 0x92,
0xBA, 0x9A, 0x31, 0x5D, 0x68, 0xC8, 0xC3, 0x01, 0xD3, 0x4A, 0xEF, 0x3C, 0x0C, 0xAB, 0x8C, 0xE4,
0xAD, 0x4B, 0xA5, 0xFD, 0xF3, 0x73, 0x85, 0x06, 0x8A, 0xF8, 0x0F, 0x03, 0x4A, 0x90, 0xED, 0x50,
0x55, 0xE4, 0x26, 0x72, 0x05, 0xF3, 0x7F, 0xCB, 0x01, 0x21, 0xA5, 0xB0, 0x1E, 0x09, 0x15, 0x17,
0xF3, 0xFD, 0x1B, 0xF8, 0x88, 0x63, 0x4F, 0x89, 0xA3, 0x24, 0x5A, 0xE8, 0x26, 0x3F, 0xD2, 0x3A,
0xDA, 0x44, 0x37, 0x8E, 0x26, 0xA9, 0x47, 0x41, 0x4B, 0xDE, 0x5B, 0x32, 0x15, 0x41, 0xC7, 0x2F,
0x07, 0xD1, 0xF1, 0x4B, 0x41, 0xC7, 0x2F, 0x00, 0xD8, 0x2C, 0x03, 0x7A, 0x52, 0x43, 0x30, 0xA3,
0xAA, 0x27, 0xBD, 0x10, 0x5A, 0x57, 0x33, 0xBF, 0xCC, 0x4C, 0x16, 0x95, 0xF2, 0x48, 0x6E, 0xD7,
0x3E, 0x3F, 0x16, 0xFF, 0x6A, 0xEE, 0xFF, 0x81, 0x09, 0x07, 0x8B, 0x81, 0x4E, 0x00, 0x00
};

View File

@ -0,0 +1,97 @@
#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif
#ifndef LED_BUILTIN
#define LED_BUILTIN 13
#endif
// define two tasks for Blink & AnalogRead
void TaskBlink( void *pvParameters );
void TaskAnalogReadA3( void *pvParameters );
// the setup function runs once when you press reset or power the board
void setup() {
// initialize serial communication at 115200 bits per second:
Serial.begin(115200);
// Now set up two tasks to run independently.
xTaskCreatePinnedToCore(
TaskBlink
, "TaskBlink" // A name just for humans
, 1024 // This stack size can be checked & adjusted by reading the Stack Highwater
, NULL
, 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
, NULL
, ARDUINO_RUNNING_CORE);
xTaskCreatePinnedToCore(
TaskAnalogReadA3
, "AnalogReadA3"
, 1024 // Stack size
, NULL
, 1 // Priority
, NULL
, ARDUINO_RUNNING_CORE);
// Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started.
}
void loop()
{
// Empty. Things are done in Tasks.
}
/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/
void TaskBlink(void *pvParameters) // This is a task.
{
(void) pvParameters;
/*
Blink
Turns on an LED on for one second, then off for one second, repeatedly.
If you want to know what pin the on-board LED is connected to on your ESP32 model, check
the Technical Specs of your board.
*/
// initialize digital LED_BUILTIN on pin 13 as an output.
pinMode(LED_BUILTIN, OUTPUT);
for (;;) // A Task shall never return or exit.
{
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
vTaskDelay(100); // one tick delay (15ms) in between reads for stability
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
vTaskDelay(100); // one tick delay (15ms) in between reads for stability
}
}
void TaskAnalogReadA3(void *pvParameters) // This is a task.
{
(void) pvParameters;
/*
AnalogReadSerial
Reads an analog input on pin A3, prints the result to the serial monitor.
Graphical representation is available using serial plotter (Tools > Serial Plotter menu)
Attach the center pin of a potentiometer to pin A3, and the outside pins to +5V and ground.
This example code is in the public domain.
*/
for (;;)
{
// read the input on analog pin A3:
int sensorValueA3 = analogRead(A3);
// print out the value you read:
Serial.println(sensorValueA3);
vTaskDelay(10); // one tick delay (15ms) in between reads for stability
}
}

View File

@ -0,0 +1,83 @@
/*
* This is an example to read analog data at high frequency using the I2S peripheral
* Run a wire between pins 27 & 32
* The readings from the device will be 12bit (0-4096)
*/
#include <driver/i2s.h>
#define I2S_SAMPLE_RATE 78125
#define ADC_INPUT ADC1_CHANNEL_4 //pin 32
#define OUTPUT_PIN 27
#define OUTPUT_VALUE 3800
#define READ_DELAY 9000 //microseconds
uint16_t adc_reading;
void i2sInit()
{
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN),
.sample_rate = I2S_SAMPLE_RATE, // The format of the signal using ADC_BUILT_IN
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 4,
.dma_buf_len = 8,
.use_apll = false,
.tx_desc_auto_clear = false,
.fixed_mclk = 0
};
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
i2s_set_adc_mode(ADC_UNIT_1, ADC_INPUT);
i2s_adc_enable(I2S_NUM_0);
}
void reader(void *pvParameters) {
uint32_t read_counter = 0;
uint64_t read_sum = 0;
// The 4 high bits are the channel, and the data is inverted
uint16_t offset = (int)ADC_INPUT * 0x1000 + 0xFFF;
size_t bytes_read;
while(1){
uint16_t buffer[2] = {0};
i2s_read(I2S_NUM_0, &buffer, sizeof(buffer), &bytes_read, 15);
//Serial.printf("%d %d\n", offset - buffer[0], offset - buffer[1]);
if (bytes_read == sizeof(buffer)) {
read_sum += offset - buffer[0];
read_sum += offset - buffer[1];
read_counter++;
} else {
Serial.println("buffer empty");
}
if (read_counter == I2S_SAMPLE_RATE) {
adc_reading = read_sum / I2S_SAMPLE_RATE / 2;
//Serial.printf("avg: %d millis: ", adc_reading);
//Serial.println(millis());
read_counter = 0;
read_sum = 0;
i2s_adc_disable(I2S_NUM_0);
delay(READ_DELAY);
i2s_adc_enable(I2S_NUM_0);
}
}
}
void setup() {
Serial.begin(115200);
// Put a signal out on pin
uint32_t freq = ledcSetup(0, I2S_SAMPLE_RATE, 10);
Serial.printf("Output frequency: %d\n", freq);
ledcWrite(0, OUTPUT_VALUE/4);
ledcAttachPin(OUTPUT_PIN, 0);
// Initialize the I2S peripheral
i2sInit();
// Create a task that will read the data
xTaskCreatePinnedToCore(reader, "ADC_reader", 2048, NULL, 1, NULL, 1);
}
void loop() {
delay(1020);
Serial.printf("ADC reading: %d\n", adc_reading);
delay(READ_DELAY);
}

View File

@ -43,6 +43,14 @@ License (MIT license):
#include <functional>
#include "esp_wifi.h"
// Add quotes around defined value
#ifdef __IN_ECLIPSE__
#define STR_EXPAND(tok) #tok
#define STR(tok) STR_EXPAND(tok)
#else
#define STR(tok) tok
#endif
static void _on_sys_event(system_event_t *event){
mdns_handle_system_event(NULL, event);
}
@ -82,7 +90,7 @@ void MDNSResponder::setInstanceName(String name) {
void MDNSResponder::enableArduino(uint16_t port, bool auth){
mdns_txt_item_t arduTxtData[4] = {
{(char*)"board" ,(char*)ARDUINO_VARIANT},
{(char*)"board" ,(char*)STR(ARDUINO_VARIANT)},
{(char*)"tcp_check" ,(char*)"no"},
{(char*)"ssh_upload" ,(char*)"no"},
{(char*)"auth_upload" ,(char*)"no"}

View File

@ -966,14 +966,14 @@ bool HTTPClient::connect(void)
return false;
}
// set Timeout for WiFiClient and for Stream::readBytesUntil() and Stream::readStringUntil()
_client->setTimeout((_tcpTimeout + 500) / 1000);
if(!_client->connect(_host.c_str(), _port)) {
log_d("failed connect to %s:%u", _host.c_str(), _port);
return false;
}
// set Timeout for WiFiClient and for Stream::readBytesUntil() and Stream::readStringUntil()
_client->setTimeout((_tcpTimeout + 500) / 1000);
log_d(" connected to %s:%u", _host.c_str(), _port);
#ifdef HTTPCLIENT_1_1_COMPATIBLE

View File

@ -56,7 +56,7 @@ void loop() {
switch (ret) {
case HTTP_UPDATE_FAILED:
Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str());
Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES:

View File

@ -49,14 +49,20 @@ HTTPUpdate::~HTTPUpdate(void)
HTTPUpdateResult HTTPUpdate::update(WiFiClient& client, const String& url, const String& currentVersion)
{
HTTPClient http;
http.begin(client, url);
if(!http.begin(client, url))
{
return HTTP_UPDATE_FAILED;
}
return handleUpdate(http, currentVersion, false);
}
HTTPUpdateResult HTTPUpdate::updateSpiffs(WiFiClient& client, const String& url, const String& currentVersion)
{
HTTPClient http;
http.begin(client, url);
if(!http.begin(client, url))
{
return HTTP_UPDATE_FAILED;
}
return handleUpdate(http, currentVersion, true);
}
@ -64,7 +70,10 @@ HTTPUpdateResult HTTPUpdate::update(WiFiClient& client, const String& host, uint
const String& currentVersion)
{
HTTPClient http;
http.begin(client, host, port, uri);
if(!http.begin(client, host, port, uri))
{
return HTTP_UPDATE_FAILED;
}
return handleUpdate(http, currentVersion, false);
}
@ -93,31 +102,33 @@ String HTTPUpdate::getLastErrorString(void)
StreamString error;
Update.printError(error);
error.trim(); // remove line ending
return String(F("Update error: ")) + error;
return String("Update error: ") + error;
}
// error from http client
if(_lastError > -100) {
return String(F("HTTP error: ")) + HTTPClient::errorToString(_lastError);
return String("HTTP error: ") + HTTPClient::errorToString(_lastError);
}
switch(_lastError) {
case HTTP_UE_TOO_LESS_SPACE:
return F("Not Enough space");
return "Not Enough space";
case HTTP_UE_SERVER_NOT_REPORT_SIZE:
return F("Server Did Not Report Size");
return "Server Did Not Report Size";
case HTTP_UE_SERVER_FILE_NOT_FOUND:
return F("File Not Found (404)");
return "File Not Found (404)";
case HTTP_UE_SERVER_FORBIDDEN:
return F("Forbidden (403)");
return "Forbidden (403)";
case HTTP_UE_SERVER_WRONG_HTTP_CODE:
return F("Wrong HTTP Code");
return "Wrong HTTP Code";
case HTTP_UE_SERVER_FAULTY_MD5:
return F("Wrong MD5");
return "Wrong MD5";
case HTTP_UE_BIN_VERIFY_HEADER_FAILED:
return F("Verify Bin Header Failed");
return "Verify Bin Header Failed";
case HTTP_UE_BIN_FOR_WRONG_FLASH:
return F("New Binary Does Not Fit Flash Size");
return "New Binary Does Not Fit Flash Size";
case HTTP_UE_NO_PARTITION:
return "Partition Could Not be Found";
}
return String();
@ -164,29 +175,32 @@ HTTPUpdateResult HTTPUpdate::handleUpdate(HTTPClient& http, const String& curren
// use HTTP/1.0 for update since the update handler not support any transfer Encoding
http.useHTTP10(true);
http.setTimeout(_httpClientTimeout);
http.setUserAgent(F("ESP32-http-Update"));
http.addHeader(F("Cache-Control"), F("no-cache"));
http.addHeader(F("x-ESP32-STA-MAC"), WiFi.macAddress());
http.addHeader(F("x-ESP32-AP-MAC"), WiFi.softAPmacAddress());
http.addHeader(F("x-ESP32-free-space"), String(ESP.getFreeSketchSpace()));
http.addHeader(F("x-ESP32-sketch-size"), String(ESP.getSketchSize()));
// To do http.addHeader(F("x-ESP32-sketch-md5"), String(ESP.getSketchMD5()));
// Sketch MD5 is not supported by the core, but SHA256 is, so add a SHA256 instead
http.setUserAgent("ESP32-http-Update");
http.addHeader("Cache-Control", "no-cache");
http.addHeader("x-ESP32-STA-MAC", WiFi.macAddress());
http.addHeader("x-ESP32-AP-MAC", WiFi.softAPmacAddress());
http.addHeader("x-ESP32-free-space", String(ESP.getFreeSketchSpace()));
http.addHeader("x-ESP32-sketch-size", String(ESP.getSketchSize()));
String sketchMD5 = ESP.getSketchMD5();
if(sketchMD5.length() != 0) {
http.addHeader("x-ESP32-sketch-md5", sketchMD5);
}
// Add also a SHA256
String sketchSHA256 = getSketchSHA256();
if(sketchSHA256.length() != 0) {
http.addHeader(F("x-ESP32-sketch-sha256"), sketchSHA256);
http.addHeader("x-ESP32-sketch-sha256", sketchSHA256);
}
http.addHeader(F("x-ESP32-chip-size"), String(ESP.getFlashChipSize()));
http.addHeader(F("x-ESP32-sdk-version"), ESP.getSdkVersion());
http.addHeader("x-ESP32-chip-size", String(ESP.getFlashChipSize()));
http.addHeader("x-ESP32-sdk-version", ESP.getSdkVersion());
if(spiffs) {
http.addHeader(F("x-ESP32-mode"), F("spiffs"));
http.addHeader("x-ESP32-mode", "spiffs");
} else {
http.addHeader(F("x-ESP32-mode"), F("sketch"));
http.addHeader("x-ESP32-mode", "sketch");
}
if(currentVersion && currentVersion[0] != 0x00) {
http.addHeader(F("x-ESP32-version"), currentVersion);
http.addHeader("x-ESP32-version", currentVersion);
}
const char * headerkeys[] = { "x-MD5" };
@ -229,14 +243,25 @@ HTTPUpdateResult HTTPUpdate::handleUpdate(HTTPClient& http, const String& curren
if(len > 0) {
bool startUpdate = true;
if(spiffs) {
// To do size_t spiffsSize = ((size_t) &_SPIFFS_end - (size_t) &_SPIFFS_start);
// To do if(len > (int) spiffsSize) {
// To do log_e("spiffsSize to low (%d) needed: %d\n", spiffsSize, len);
// To do startUpdate = false;
// To do }
const esp_partition_t* _partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, NULL);
if(!_partition){
_lastError = HTTP_UE_NO_PARTITION;
return HTTP_UPDATE_FAILED;
}
if(len > _partition->size) {
log_e("spiffsSize to low (%d) needed: %d\n", _partition->size, len);
startUpdate = false;
}
} else {
if(len > (int) ESP.getFreeSketchSpace()) {
log_e("FreeSketchSpace to low (%d) needed: %d\n", ESP.getFreeSketchSpace(), len);
int sketchFreeSpace = ESP.getFreeSketchSpace();
if(!sketchFreeSpace){
_lastError = HTTP_UE_NO_PARTITION;
return HTTP_UPDATE_FAILED;
}
if(len > sketchFreeSpace) {
log_e("FreeSketchSpace to low (%d) needed: %d\n", sketchFreeSpace, len);
startUpdate = false;
}
}
@ -366,6 +391,8 @@ bool HTTPUpdate::runUpdate(Stream& in, uint32_t size, String md5, int command)
}
}
// To do: the SHA256 could be checked if the server sends it
if(Update.writeStream(in) != size) {
_lastError = Update.getError();
Update.printError(error);

View File

@ -42,6 +42,7 @@
#define HTTP_UE_SERVER_FAULTY_MD5 (-105)
#define HTTP_UE_BIN_VERIFY_HEADER_FAILED (-106)
#define HTTP_UE_BIN_FOR_WRONG_FLASH (-107)
#define HTTP_UE_NO_PARTITION (-108)
enum HTTPUpdateResult {
HTTP_UPDATE_FAILED,

View File

@ -16,7 +16,7 @@ extern "C" {
#include "diskio.h"
#include "ffconf.h"
#include "ff.h"
#include "esp_vfs.h"
//#include "esp_vfs.h"
#include "esp_vfs_fat.h"
char CRC7(const char* data, int length);
unsigned short CRC16(const char* data, int length);

View File

@ -2,7 +2,7 @@
/* The ESP32 has four SPi buses, however as of right now only two of
* them are available to use, HSPI and VSPI. Simply using the SPI API
* as illustrated in Arduino examples will use HSPI, leaving VSPI unused.
* as illustrated in Arduino examples will use VSPI, leaving HSPI unused.
*
* However if we simply intialise two instance of the SPI class for both
* of these buses both can be used. However when just using these the Arduino

View File

@ -214,6 +214,11 @@ void SPIClass::writeBytes(uint8_t * data, uint32_t size)
spiEndTransaction(_spi);
}
void SPIClass::transfer(uint8_t * data, uint32_t size)
{
transferBytes(data, data, size);
}
/**
* @param data void *
* @param size uint32_t

View File

@ -65,10 +65,11 @@ public:
void beginTransaction(SPISettings settings);
void endTransaction(void);
void transfer(uint8_t * data, uint32_t size);
uint8_t transfer(uint8_t data);
uint16_t transfer16(uint16_t data);
uint32_t transfer32(uint32_t data);
void transferBytes(uint8_t * data, uint8_t * out, uint32_t size);
void transferBits(uint32_t data, uint32_t * out, uint8_t bits);

View File

@ -39,11 +39,16 @@ bool SPIFFSFS::begin(bool formatOnFail, const char * basePath, uint8_t maxOpenFi
.base_path = basePath,
.partition_label = NULL,
.max_files = maxOpenFiles,
.format_if_mount_failed = formatOnFail
.format_if_mount_failed = false
};
esp_err_t err = esp_vfs_spiffs_register(&conf);
if(err){
if(err == ESP_FAIL && formatOnFail){
if(format()){
err = esp_vfs_spiffs_register(&conf);
}
}
if(err != ESP_OK){
log_e("Mounting SPIFFS failed! Error: %d", err);
return false;
}
@ -65,7 +70,9 @@ void SPIFFSFS::end()
bool SPIFFSFS::format()
{
disableCore0WDT();
esp_err_t err = esp_spiffs_format(NULL);
enableCore0WDT();
if(err){
log_e("Formatting SPIFFS failed! Error: %d", err);
return false;

View File

@ -28,7 +28,8 @@
#include <ESPmDNS.h>
#define FILESYSTEM SPIFFS
#define FORMAT_FILESYSTEM true
// You only need to format the filesystem once
#define FORMAT_FILESYSTEM false
#define DBG_OUTPUT_PORT Serial
#if FILESYSTEM == FFat

View File

@ -20,18 +20,12 @@
*/
#include <Arduino.h>
#include <esp32-hal-log.h>
#include "WiFiServer.h"
#include "WiFiClient.h"
#include "WebServer.h"
#include "detail/mimetable.h"
//#define DEBUG_ESP_HTTP_SERVER
#ifdef DEBUG_ESP_PORT
#define DEBUG_OUTPUT DEBUG_ESP_PORT
#else
#define DEBUG_OUTPUT Serial
#endif
#ifndef WEBSERVER_MAX_POST_ARGS
#define WEBSERVER_MAX_POST_ARGS 32
#endif
@ -85,10 +79,7 @@ bool WebServer::_parseRequest(WiFiClient& client) {
int addr_start = req.indexOf(' ');
int addr_end = req.indexOf(' ', addr_start + 1);
if (addr_start == -1 || addr_end == -1) {
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Invalid request: ");
DEBUG_OUTPUT.println(req);
#endif
log_e("Invalid request: %s", req.c_str());
return false;
}
@ -119,14 +110,7 @@ bool WebServer::_parseRequest(WiFiClient& client) {
}
_currentMethod = method;
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("method: ");
DEBUG_OUTPUT.print(methodStr);
DEBUG_OUTPUT.print(" url: ");
DEBUG_OUTPUT.print(url);
DEBUG_OUTPUT.print(" search: ");
DEBUG_OUTPUT.println(searchStr);
#endif
log_v("method: %s url: %s search: %s", methodStr.c_str(), url.c_str(), searchStr.c_str());
//attach handler
RequestHandler* handler;
@ -159,12 +143,8 @@ bool WebServer::_parseRequest(WiFiClient& client) {
headerValue.trim();
_collectHeader(headerName.c_str(),headerValue.c_str());
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("headerName: ");
DEBUG_OUTPUT.println(headerName);
DEBUG_OUTPUT.print("headerValue: ");
DEBUG_OUTPUT.println(headerValue);
#endif
log_v("headerName: %s", headerName.c_str());
log_v("headerValue: %s", headerValue.c_str());
if (headerName.equalsIgnoreCase(FPSTR(Content_Type))){
using namespace mime;
@ -206,10 +186,7 @@ bool WebServer::_parseRequest(WiFiClient& client) {
arg.value = String(plainBuf);
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Plain: ");
DEBUG_OUTPUT.println(plainBuf);
#endif
log_v("Plain: %s", plainBuf);
free(plainBuf);
} else {
// No content - but we can still have arguments in the URL.
@ -239,12 +216,8 @@ bool WebServer::_parseRequest(WiFiClient& client) {
headerValue = req.substring(headerDiv + 2);
_collectHeader(headerName.c_str(),headerValue.c_str());
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("headerName: ");
DEBUG_OUTPUT.println(headerName);
DEBUG_OUTPUT.print("headerValue: ");
DEBUG_OUTPUT.println(headerValue);
#endif
log_v("headerName: %s", headerName.c_str());
log_v("headerValue: %s", headerValue.c_str());
if (headerName.equalsIgnoreCase("Host")){
_hostHeader = headerValue;
@ -254,12 +227,8 @@ bool WebServer::_parseRequest(WiFiClient& client) {
}
client.flush();
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Request: ");
DEBUG_OUTPUT.println(url);
DEBUG_OUTPUT.print(" Arguments: ");
DEBUG_OUTPUT.println(searchStr);
#endif
log_v("Request: %s", url.c_str());
log_v(" Arguments: %s", searchStr.c_str());
return true;
}
@ -275,10 +244,7 @@ bool WebServer::_collectHeader(const char* headerName, const char* headerValue)
}
void WebServer::_parseArguments(String data) {
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("args: ");
DEBUG_OUTPUT.println(data);
#endif
log_v("args: %s", data.c_str());
if (_currentArgs)
delete[] _currentArgs;
_currentArgs = 0;
@ -296,10 +262,7 @@ void WebServer::_parseArguments(String data) {
++i;
++_currentArgCount;
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("args count: ");
DEBUG_OUTPUT.println(_currentArgCount);
#endif
log_v("args count: %d", _currentArgCount);
_currentArgs = new RequestArgument[_currentArgCount+1];
int pos = 0;
@ -307,19 +270,9 @@ void WebServer::_parseArguments(String data) {
for (iarg = 0; iarg < _currentArgCount;) {
int equal_sign_index = data.indexOf('=', pos);
int next_arg_index = data.indexOf('&', pos);
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("pos ");
DEBUG_OUTPUT.print(pos);
DEBUG_OUTPUT.print("=@ ");
DEBUG_OUTPUT.print(equal_sign_index);
DEBUG_OUTPUT.print(" &@ ");
DEBUG_OUTPUT.println(next_arg_index);
#endif
log_v("pos %d =@%d &@%d", pos, equal_sign_index, next_arg_index);
if ((equal_sign_index == -1) || ((equal_sign_index > next_arg_index) && (next_arg_index != -1))) {
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("arg missing value: ");
DEBUG_OUTPUT.println(iarg);
#endif
log_e("arg missing value: %d", iarg);
if (next_arg_index == -1)
break;
pos = next_arg_index + 1;
@ -328,24 +281,14 @@ void WebServer::_parseArguments(String data) {
RequestArgument& arg = _currentArgs[iarg];
arg.key = urlDecode(data.substring(pos, equal_sign_index));
arg.value = urlDecode(data.substring(equal_sign_index + 1, next_arg_index));
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("arg ");
DEBUG_OUTPUT.print(iarg);
DEBUG_OUTPUT.print(" key: ");
DEBUG_OUTPUT.print(arg.key);
DEBUG_OUTPUT.print(" value: ");
DEBUG_OUTPUT.println(arg.value);
#endif
log_v("arg %d key: %s value: %s", iarg, arg.key.c_str(), arg.value.c_str());
++iarg;
if (next_arg_index == -1)
break;
pos = next_arg_index + 1;
}
_currentArgCount = iarg;
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("args count: ");
DEBUG_OUTPUT.println(_currentArgCount);
#endif
log_v("args count: %d", _currentArgCount);
}
@ -371,12 +314,7 @@ int WebServer::_uploadReadByte(WiFiClient& client){
bool WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
(void) len;
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Parse Form: Boundary: ");
DEBUG_OUTPUT.print(boundary);
DEBUG_OUTPUT.print(" Length: ");
DEBUG_OUTPUT.println(len);
#endif
log_v("Parse Form: Boundary: %s Length: %d", boundary.c_str(), len);
String line;
int retry = 0;
do {
@ -410,18 +348,12 @@ bool WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
argFilename = argName.substring(nameStart+2, argName.length() - 1);
argName = argName.substring(0, argName.indexOf('"'));
argIsFile = true;
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("PostArg FileName: ");
DEBUG_OUTPUT.println(argFilename);
#endif
log_v("PostArg FileName: %s",argFilename.c_str());
//use GET to set the filename if uploading using blob
if (argFilename == F("blob") && hasArg(FPSTR(filename)))
if (argFilename == F("blob") && hasArg(FPSTR(filename)))
argFilename = arg(FPSTR(filename));
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("PostArg Name: ");
DEBUG_OUTPUT.println(argName);
#endif
log_v("PostArg Name: %s", argName.c_str());
using namespace mime;
argType = FPSTR(mimeTable[txt].mimeType);
line = client.readStringUntil('\r');
@ -432,10 +364,7 @@ bool WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
client.readStringUntil('\r');
client.readStringUntil('\n');
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("PostArg Type: ");
DEBUG_OUTPUT.println(argType);
#endif
log_v("PostArg Type: %s", argType.c_str());
if (!argIsFile){
while(1){
line = client.readStringUntil('\r');
@ -444,20 +373,14 @@ bool WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
if (argValue.length() > 0) argValue += "\n";
argValue += line;
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("PostArg Value: ");
DEBUG_OUTPUT.println(argValue);
DEBUG_OUTPUT.println();
#endif
log_v("PostArg Value: %s", argValue.c_str());
RequestArgument& arg = _postArgs[_postArgsLen++];
arg.key = argName;
arg.value = argValue;
if (line == ("--"+boundary+"--")){
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("Done Parsing POST");
#endif
log_v("Done Parsing POST");
break;
}
} else {
@ -468,12 +391,7 @@ bool WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
_currentUpload->type = argType;
_currentUpload->totalSize = 0;
_currentUpload->currentSize = 0;
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Start File: ");
DEBUG_OUTPUT.print(_currentUpload->filename);
DEBUG_OUTPUT.print(" Type: ");
DEBUG_OUTPUT.println(_currentUpload->type);
#endif
log_v("Start File: %s Type: %s", _currentUpload->filename.c_str(), _currentUpload->type.c_str());
if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload);
_currentUpload->status = UPLOAD_FILE_WRITE;
@ -518,20 +436,11 @@ readfile:
_currentUpload->status = UPLOAD_FILE_END;
if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload);
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("End File: ");
DEBUG_OUTPUT.print(_currentUpload->filename);
DEBUG_OUTPUT.print(" Type: ");
DEBUG_OUTPUT.print(_currentUpload->type);
DEBUG_OUTPUT.print(" Size: ");
DEBUG_OUTPUT.println(_currentUpload->totalSize);
#endif
log_v("End File: %s Type: %s Size: %d", _currentUpload->filename.c_str(), _currentUpload->type.c_str(), _currentUpload->totalSize);
line = client.readStringUntil(0x0D);
client.readStringUntil(0x0A);
if (line == "--"){
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("Done Parsing POST");
#endif
log_v("Done Parsing POST");
break;
}
continue;
@ -579,10 +488,7 @@ readfile:
}
return true;
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.print("Error: line: ");
DEBUG_OUTPUT.println(line);
#endif
log_e("Error: line: %s", line.c_str());
return false;
}

View File

@ -22,6 +22,7 @@
#include <Arduino.h>
#include <esp32-hal-log.h>
#include <libb64/cencode.h>
#include "WiFiServer.h"
#include "WiFiClient.h"
@ -30,12 +31,6 @@
#include "detail/RequestHandlersImpl.h"
#include "mbedtls/md5.h"
//#define DEBUG_ESP_HTTP_SERVER
#ifdef DEBUG_ESP_PORT
#define DEBUG_OUTPUT DEBUG_ESP_PORT
#else
#define DEBUG_OUTPUT Serial
#endif
static const char AUTHORIZATION_HEADER[] = "Authorization";
static const char qop_auth[] = "qop=auth";
@ -163,9 +158,7 @@ bool WebServer::authenticate(const char * username, const char * password){
delete[] encoded;
} else if(authReq.startsWith(F("Digest"))) {
authReq = authReq.substring(7);
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println(authReq);
#endif
log_v("%s", authReq.c_str());
String _username = _extractParam(authReq,F("username=\""));
if(!_username.length() || _username != String(username)) {
authReq = "";
@ -193,9 +186,7 @@ bool WebServer::authenticate(const char * username, const char * password){
_cnonce = _extractParam(authReq, F("cnonce=\""));
}
String _H1 = md5str(String(username) + ':' + _realm + ':' + String(password));
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("Hash of user:realm:pass=" + _H1);
#endif
log_v("Hash of user:realm:pass=%s", _H1.c_str());
String _H2 = "";
if(_currentMethod == HTTP_GET){
_H2 = md5str(String(F("GET:")) + _uri);
@ -208,18 +199,14 @@ bool WebServer::authenticate(const char * username, const char * password){
}else{
_H2 = md5str(String(F("GET:")) + _uri);
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("Hash of GET:uri=" + _H2);
#endif
log_v("Hash of GET:uri=%s", _H2.c_str());
String _responsecheck = "";
if(authReq.indexOf(FPSTR(qop_auth)) != -1) {
_responsecheck = md5str(_H1 + ':' + _nonce + ':' + _nc + ':' + _cnonce + F(":auth:") + _H2);
} else {
_responsecheck = md5str(_H1 + ':' + _nonce + ':' + _H2);
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("The Proper response=" +_responsecheck);
#endif
log_v("The Proper response=%s", _responsecheck.c_str());
if(_response == _responsecheck){
authReq = "";
return true;
@ -294,9 +281,7 @@ void WebServer::handleClient() {
return;
}
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("New client");
#endif
log_v("New client");
_currentClient = client;
_currentStatus = HC_WAIT_READ;
@ -614,17 +599,13 @@ void WebServer::onNotFound(THandlerFunction fn) {
void WebServer::_handleRequest() {
bool handled = false;
if (!_currentHandler){
#ifdef DEBUG_ESP_HTTP_SERVER
DEBUG_OUTPUT.println("request handler not found");
#endif
log_e("request handler not found");
}
else {
handled = _currentHandler->handle(*this, _currentMethod, _currentUri);
#ifdef DEBUG_ESP_HTTP_SERVER
if (!handled) {
DEBUG_OUTPUT.println("request handler failed to handle request");
log_e("request handler failed to handle request");
}
#endif
}
if (!handled && _notFoundHandler) {
_notFoundHandler();

View File

@ -18,7 +18,7 @@ void setup()
Serial.println();
Serial.println();
Serial.print("Wait for WiFi... ");
Serial.print("Waiting for WiFi... ");
while(WiFiMulti.run() != WL_CONNECTED) {
Serial.print(".");
@ -39,32 +39,30 @@ void loop()
const uint16_t port = 80;
const char * host = "192.168.1.1"; // ip or dns
Serial.print("connecting to ");
Serial.print("Connecting to ");
Serial.println(host);
// Use WiFiClient class to create TCP connections
WiFiClient client;
if (!client.connect(host, port)) {
Serial.println("connection failed");
Serial.println("wait 5 sec...");
Serial.println("Connection failed.");
Serial.println("Waiting 5 seconds before retrying...");
delay(5000);
return;
}
// This will send the request to the server
client.print("Send this data to server");
// This will send a request to the server
client.print("Send this data to the server");
//read back one line from server
//read back one line from the server
String line = client.readStringUntil('\r');
client.println(line);
Serial.println("closing connection");
Serial.println("Closing connection.");
client.stop();
Serial.println("wait 5 sec...");
Serial.println("Waiting 5 seconds before restarting...");
delay(5000);
}

View File

@ -18,7 +18,7 @@
|University|Board|Method|Result|
|-------------|-------------| -----|------|
|Technical University in Košice (Slovakia)|ESP32 Devkit v1|PEAP + MsCHAPv2|Working|
|Technical University in Košice (Slovakia)|ESP32 DevKitc v4|PEAP + MsCHAPv2|Working|
|Technical University in Košice (Slovakia)|ESP32 Devmodule v4|PEAP + MsCHAPv2|Working on 6th attempt in loop|
|Slovak Technical University in Bratislava (Slovakia)|ESP32 Devkit v1|PEAP + MsCHAPv2|Working|
|University of Antwerp (Belgium)|Lolin32|PEAP + MsCHAPv2|Working|
|UPV Universitat Politècnica de València (Spain)|ESP32 Devmodule v4|PEAP + MsCHAPv2|Working|
@ -27,7 +27,8 @@
|Universidad de Granada (Spain)|Lolin D32 Pro|PEAP + MsCHAPv2|Working|
|Universidad de Granada (Spain)|Lolin D32|PEAP + MsCHAPv2|Working|
|Universidade Federal de Santa Catarina (Brazil)|xxx|EAP-TTLS + MsCHAPv2|Working|
|University of Regensburg (Germany)|Lolin32|PEAP + MsCHAPv2|Working|
|University of Central Florida (Orlando, Florida)|ESP32 Built-in OLED Heltec WiFi Kit 32|PEAP + MsCHAPv2|Working|
|Université de Montpellier (France)|NodeMCU-32S|PEAP + MsCHAPv2|Working|
# Common errors - Switch to Debug mode for Serial monitor prints
|Error|Appearance|Solution|

View File

@ -1,5 +1,5 @@
/*
ESP8266WiFi.h - esp8266 Wifi support.
WiFi.h - esp32 Wifi support.
Based on WiFi.h from Arduino WiFi shield library.
Copyright (c) 2011-2014 Arduino. All right reserved.
Modified by Ivan Grokhotkov, December 2014

View File

@ -58,6 +58,11 @@ private:
{
if(!_buffer){
_buffer = (uint8_t *)malloc(_size);
if(!_buffer) {
log_e("Not enough memory to allocate buffer");
_failed = true;
return 0;
}
}
if(_fill && _pos == _fill){
_fill = 0;
@ -67,8 +72,10 @@ private:
return 0;
}
int res = recv(_fd, _buffer + _fill, _size - _fill, MSG_DONTWAIT);
if(res < 0 && errno != EWOULDBLOCK) {
_failed = true;
if(res < 0) {
if(errno != EWOULDBLOCK) {
_failed = true;
}
return 0;
}
_fill += res;
@ -195,12 +202,17 @@ void WiFiClient::stop()
}
int WiFiClient::connect(IPAddress ip, uint16_t port)
{
return connect(ip,port,-1);
}
int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout)
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
log_e("socket: %d", errno);
return 0;
}
fcntl( sockfd, F_SETFL, fcntl( sockfd, F_GETFL, 0 ) | O_NONBLOCK );
uint32_t ip_addr = ip;
struct sockaddr_in serveraddr;
@ -208,12 +220,21 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
serveraddr.sin_family = AF_INET;
bcopy((const void *)(&ip_addr), (void *)&serveraddr.sin_addr.s_addr, 4);
serveraddr.sin_port = htons(port);
int res = lwip_connect_r(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
if (res < 0) {
log_e("lwip_connect_r: %d", errno);
fd_set fdset;
struct timeval tv;
FD_ZERO(&fdset);
FD_SET(sockfd, &fdset);
tv.tv_sec = 0;
tv.tv_usec = timeout * 1000;
lwip_connect_r(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
int res = select(sockfd + 1, nullptr, &fdset, nullptr, timeout<0 ? nullptr : &tv);
if (res != 1)
{
log_e("select: %d",errno);
close(sockfd);
return 0;
}
fcntl( sockfd, F_SETFL, fcntl( sockfd, F_GETFL, 0 ) & (~O_NONBLOCK) );
clientSocketHandle.reset(new WiFiClientSocketHandle(sockfd));
_rxBuffer.reset(new WiFiClientRxBuffer(sockfd));
_connected = true;
@ -221,12 +242,16 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
}
int WiFiClient::connect(const char *host, uint16_t port)
{
return connect(host,port,-1);
}
int WiFiClient::connect(const char *host, uint16_t port, int32_t timeout)
{
IPAddress srv((uint32_t)0);
if(!WiFiGenericClass::hostByName(host, srv)){
return 0;
}
return connect(srv, port);
return connect(srv, port, timeout);
}
int WiFiClient::setSocketOption(int option, char* value, size_t len)
@ -398,7 +423,8 @@ int WiFiClient::peek()
int WiFiClient::available()
{
if(!_connected) {
if(!_rxBuffer)
{
return 0;
}
int res = _rxBuffer->available();
@ -439,6 +465,8 @@ uint8_t WiFiClient::connected()
if (_connected) {
uint8_t dummy;
int res = recv(fd(), &dummy, 0, MSG_DONTWAIT);
// avoid unused var warning by gcc
(void)res;
switch (errno) {
case EWOULDBLOCK:
case ENOENT: //caused by vfs

View File

@ -41,7 +41,9 @@ public:
WiFiClient(int fd);
~WiFiClient();
int connect(IPAddress ip, uint16_t port);
int connect(IPAddress ip, uint16_t port, int32_t timeout);
int connect(const char *host, uint16_t port);
int connect(const char *host, uint16_t port, int32_t timeout);
size_t write(uint8_t data);
size_t write(const uint8_t *buf, size_t size);
size_t write_P(PGM_P buf, size_t size);

View File

@ -96,7 +96,7 @@ static bool _start_network_event_task(){
}
}
if(!_network_event_task_handle){
xTaskCreatePinnedToCore(_network_event_task, "network_event", 4096, NULL, 2, &_network_event_task_handle, ARDUINO_RUNNING_CORE);
xTaskCreatePinnedToCore(_network_event_task, "network_event", 4096, NULL, ESP_TASKD_EVENT_PRIO - 1, &_network_event_task_handle, ARDUINO_RUNNING_CORE);
if(!_network_event_task_handle){
log_e("Network Event Task Start Failed!");
return false;
@ -168,7 +168,7 @@ static bool espWiFiStop(){
_esp_wifi_started = false;
err = esp_wifi_stop();
if(err){
log_e("Could not stop WiFi! %u", err);
log_e("Could not stop WiFi! %d", err);
_esp_wifi_started = true;
return false;
}
@ -187,7 +187,7 @@ typedef struct WiFiEventCbList {
WiFiEventSysCb scb;
system_event_id_t event;
WiFiEventCbList() : id(current_id++) {}
WiFiEventCbList() : id(current_id++), cb(NULL), fcb(NULL), scb(NULL), event(SYSTEM_EVENT_WIFI_READY) {}
} WiFiEventCbList_t;
wifi_event_id_t WiFiEventCbList::current_id = 1;
@ -339,7 +339,7 @@ const char * system_event_reasons[] = { "UNSPECIFIED", "AUTH_EXPIRE", "AUTH_LEAV
#endif
esp_err_t WiFiGenericClass::_eventCallback(void *arg, system_event_t *event)
{
log_d("Event: %d - %s", event->event_id, system_event_names[event->event_id]);
if(event->event_id < 26) log_d("Event: %d - %s", event->event_id, system_event_names[event->event_id]);
if(event->event_id == SYSTEM_EVENT_SCAN_DONE) {
WiFiScanClass::_scanDone();
@ -371,8 +371,7 @@ esp_err_t WiFiGenericClass::_eventCallback(void *arg, system_event_t *event)
(reason >= WIFI_REASON_BEACON_TIMEOUT && reason != WIFI_REASON_AUTH_FAIL)) &&
WiFi.getAutoReconnect())
{
WiFi.enableSTA(false);
WiFi.enableSTA(true);
WiFi.disconnect(true);
WiFi.begin();
}
} else if(event->event_id == SYSTEM_EVENT_STA_GOT_IP) {
@ -497,7 +496,7 @@ bool WiFiGenericClass::mode(wifi_mode_t m)
esp_err_t err;
err = esp_wifi_set_mode(m);
if(err){
log_e("Could not set mode! %u", err);
log_e("Could not set mode! %d", err);
return false;
}
return true;

View File

@ -1,6 +1,6 @@
/**
*
* @file ESP8266WiFiMulti.cpp
* @file WiFiMulti.cpp
* @date 16.05.2015
* @author Markus Sattler
*
@ -47,112 +47,117 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout)
int8_t scanResult;
uint8_t status = WiFi.status();
if(status != WL_CONNECTED || status == WL_NO_SSID_AVAIL || status == WL_IDLE_STATUS || status == WL_CONNECT_FAILED) {
if(status == WL_CONNECTED) {
for(uint32_t x = 0; x < APlist.size(); x++) {
if(WiFi.SSID()==APlist[x].ssid){
return status;
}
}
WiFi.disconnect(false,false);
delay(10);
status = WiFi.status();
}
scanResult = WiFi.scanNetworks();
if(scanResult == WIFI_SCAN_RUNNING) {
// scan is running
return WL_NO_SSID_AVAIL;
} else if(scanResult > 0) {
// scan done analyze
WifiAPlist_t bestNetwork { NULL, NULL };
int bestNetworkDb = INT_MIN;
uint8_t bestBSSID[6];
int32_t bestChannel = 0;
scanResult = WiFi.scanNetworks();
if(scanResult == WIFI_SCAN_RUNNING) {
// scan is running
return WL_NO_SSID_AVAIL;
} else if(scanResult >= 0) {
// scan done analyze
WifiAPlist_t bestNetwork { NULL, NULL };
int bestNetworkDb = INT_MIN;
uint8_t bestBSSID[6];
int32_t bestChannel = 0;
log_i("[WIFI] scan done");
log_i("[WIFI] scan done");
if(scanResult <= 0) {
log_e("[WIFI] no networks found");
} else {
log_i("[WIFI] %d networks found", scanResult);
for(int8_t i = 0; i < scanResult; ++i) {
if(scanResult == 0) {
log_e("[WIFI] no networks found");
} else {
log_i("[WIFI] %d networks found", scanResult);
for(int8_t i = 0; i < scanResult; ++i) {
String ssid_scan;
int32_t rssi_scan;
uint8_t sec_scan;
uint8_t* BSSID_scan;
int32_t chan_scan;
String ssid_scan;
int32_t rssi_scan;
uint8_t sec_scan;
uint8_t* BSSID_scan;
int32_t chan_scan;
WiFi.getNetworkInfo(i, ssid_scan, sec_scan, rssi_scan, BSSID_scan, chan_scan);
WiFi.getNetworkInfo(i, ssid_scan, sec_scan, rssi_scan, BSSID_scan, chan_scan);
bool known = false;
for(uint32_t x = 0; x < APlist.size(); x++) {
WifiAPlist_t entry = APlist[x];
bool known = false;
for(uint32_t x = 0; x < APlist.size(); x++) {
WifiAPlist_t entry = APlist[x];
if(ssid_scan == entry.ssid) { // SSID match
known = true;
if(rssi_scan > bestNetworkDb) { // best network
if(sec_scan == WIFI_AUTH_OPEN || entry.passphrase) { // check for passphrase if not open wlan
bestNetworkDb = rssi_scan;
bestChannel = chan_scan;
memcpy((void*) &bestNetwork, (void*) &entry, sizeof(bestNetwork));
memcpy((void*) &bestBSSID, (void*) BSSID_scan, sizeof(bestBSSID));
}
if(ssid_scan == entry.ssid) { // SSID match
known = true;
if(rssi_scan > bestNetworkDb) { // best network
if(sec_scan == WIFI_AUTH_OPEN || entry.passphrase) { // check for passphrase if not open wlan
bestNetworkDb = rssi_scan;
bestChannel = chan_scan;
memcpy((void*) &bestNetwork, (void*) &entry, sizeof(bestNetwork));
memcpy((void*) &bestBSSID, (void*) BSSID_scan, sizeof(bestBSSID));
}
break;
}
break;
}
}
if(known) {
log_d(" ---> %d: [%d][%02X:%02X:%02X:%02X:%02X:%02X] %s (%d) %c", i, chan_scan, BSSID_scan[0], BSSID_scan[1], BSSID_scan[2], BSSID_scan[3], BSSID_scan[4], BSSID_scan[5], ssid_scan.c_str(), rssi_scan, (sec_scan == WIFI_AUTH_OPEN) ? ' ' : '*');
} else {
log_d(" %d: [%d][%02X:%02X:%02X:%02X:%02X:%02X] %s (%d) %c", i, chan_scan, BSSID_scan[0], BSSID_scan[1], BSSID_scan[2], BSSID_scan[3], BSSID_scan[4], BSSID_scan[5], ssid_scan.c_str(), rssi_scan, (sec_scan == WIFI_AUTH_OPEN) ? ' ' : '*');
}
if(known) {
log_d(" ---> %d: [%d][%02X:%02X:%02X:%02X:%02X:%02X] %s (%d) %c", i, chan_scan, BSSID_scan[0], BSSID_scan[1], BSSID_scan[2], BSSID_scan[3], BSSID_scan[4], BSSID_scan[5], ssid_scan.c_str(), rssi_scan, (sec_scan == WIFI_AUTH_OPEN) ? ' ' : '*');
} else {
log_d(" %d: [%d][%02X:%02X:%02X:%02X:%02X:%02X] %s (%d) %c", i, chan_scan, BSSID_scan[0], BSSID_scan[1], BSSID_scan[2], BSSID_scan[3], BSSID_scan[4], BSSID_scan[5], ssid_scan.c_str(), rssi_scan, (sec_scan == WIFI_AUTH_OPEN) ? ' ' : '*');
}
}
}
// clean up ram
WiFi.scanDelete();
// clean up ram
WiFi.scanDelete();
if(bestNetwork.ssid) {
log_i("[WIFI] Connecting BSSID: %02X:%02X:%02X:%02X:%02X:%02X SSID: %s Channal: %d (%d)", bestBSSID[0], bestBSSID[1], bestBSSID[2], bestBSSID[3], bestBSSID[4], bestBSSID[5], bestNetwork.ssid, bestChannel, bestNetworkDb);
if(bestNetwork.ssid) {
log_i("[WIFI] Connecting BSSID: %02X:%02X:%02X:%02X:%02X:%02X SSID: %s Channal: %d (%d)", bestBSSID[0], bestBSSID[1], bestBSSID[2], bestBSSID[3], bestBSSID[4], bestBSSID[5], bestNetwork.ssid, bestChannel, bestNetworkDb);
WiFi.begin(bestNetwork.ssid, bestNetwork.passphrase, bestChannel, bestBSSID);
WiFi.begin(bestNetwork.ssid, bestNetwork.passphrase, bestChannel, bestBSSID);
status = WiFi.status();
auto startTime = millis();
// wait for connection, fail, or timeout
while(status != WL_CONNECTED && status != WL_NO_SSID_AVAIL && status != WL_CONNECT_FAILED && (millis() - startTime) <= connectTimeout) {
delay(10);
status = WiFi.status();
auto startTime = millis();
// wait for connection, fail, or timeout
while(status != WL_CONNECTED && status != WL_NO_SSID_AVAIL && status != WL_CONNECT_FAILED && (millis() - startTime) <= connectTimeout) {
delay(10);
status = WiFi.status();
}
}
IPAddress ip;
uint8_t * mac;
switch(status) {
case 3:
ip = WiFi.localIP();
mac = WiFi.BSSID();
log_i("[WIFI] Connecting done.");
log_d("[WIFI] SSID: %s", WiFi.SSID().c_str());
log_d("[WIFI] IP: %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
log_d("[WIFI] MAC: %02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
log_d("[WIFI] Channel: %d", WiFi.channel());
break;
case 1:
log_e("[WIFI] Connecting Failed AP not found.");
break;
case 4:
log_e("[WIFI] Connecting Failed.");
break;
default:
log_e("[WIFI] Connecting Failed (%d).", status);
break;
}
} else {
log_e("[WIFI] no matching wifi found!");
switch(status) {
case 3:
log_i("[WIFI] Connecting done.");
log_d("[WIFI] SSID: %s", WiFi.SSID().c_str());
log_d("[WIFI] IP: %s", WiFi.localIP().toString().c_str());
log_d("[WIFI] MAC: %s", WiFi.BSSIDstr().c_str());
log_d("[WIFI] Channel: %d", WiFi.channel());
break;
case 1:
log_e("[WIFI] Connecting Failed AP not found.");
break;
case 4:
log_e("[WIFI] Connecting Failed.");
break;
default:
log_e("[WIFI] Connecting Failed (%d).", status);
break;
}
} else {
// start scan
log_d("[WIFI] delete old wifi config...");
WiFi.disconnect();
log_d("[WIFI] start scan");
// scan wifi async mode
WiFi.scanNetworks(true);
log_e("[WIFI] no matching wifi found!");
}
} else {
// start scan
log_d("[WIFI] delete old wifi config...");
WiFi.disconnect();
log_d("[WIFI] start scan");
// scan wifi async mode
WiFi.scanNetworks(true);
}
return status;
}

View File

@ -1,5 +1,5 @@
/*
ESP8266WiFiSTA.cpp - WiFi library for esp8266
WiFiSTA.cpp - WiFi library for esp32
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
@ -416,7 +416,10 @@ IPAddress WiFiSTAClass::localIP()
uint8_t* WiFiSTAClass::macAddress(uint8_t* mac)
{
if(WiFiGenericClass::getMode() != WIFI_MODE_NULL){
esp_wifi_get_mac(WIFI_IF_STA, mac);
esp_wifi_get_mac(WIFI_IF_STA, mac);
}
else{
esp_read_mac(mac, ESP_MAC_WIFI_STA);
}
return mac;
}
@ -430,10 +433,11 @@ String WiFiSTAClass::macAddress(void)
uint8_t mac[6];
char macStr[18] = { 0 };
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return String();
esp_read_mac(mac, ESP_MAC_WIFI_STA);
}
else{
esp_wifi_get_mac(WIFI_IF_STA, mac);
}
esp_wifi_get_mac(WIFI_IF_STA, mac);
sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return String(macStr);
}
@ -683,8 +687,10 @@ void WiFiSTAClass::_smartConfigCallback(uint32_t st, void* result) {
smartconfig_status_t status = (smartconfig_status_t) st;
log_d("Status: %s", sc_status_strings[st % 5]);
if (status == SC_STATUS_GETTING_SSID_PSWD) {
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
smartconfig_type_t * type = (smartconfig_type_t *)result;
log_d("Type: %s", sc_type_strings[*type % 3]);
#endif
} else if (status == SC_STATUS_LINK) {
wifi_sta_config_t *sta_conf = reinterpret_cast<wifi_sta_config_t *>(result);
log_d("SSID: %s", (char *)(sta_conf->ssid));
@ -694,8 +700,10 @@ void WiFiSTAClass::_smartConfigCallback(uint32_t st, void* result) {
_smartConfigDone = true;
} else if (status == SC_STATUS_LINK_OVER) {
if(result){
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
ip4_addr_t * ip = (ip4_addr_t *)result;
log_d("Sender IP: " IPSTR, IP2STR(ip));
#endif
}
WiFi.stopSmartConfig();
}

View File

@ -0,0 +1,67 @@
WiFiClientSecure
================
The WiFiClientSecure class implements support for secure connections using TLS (SSL).
It inherits from WiFiClient and thus implements a superset of that class' interface.
There are three ways to establish a secure connection using the WiFiClientSecure class:
using a root certificate authority (CA) cert, using a root CA cert plus a client cert and key,
and using a pre-shared key (PSK).
Using a root certificate authority cert
---------------------------------------
This method authenticates the server and negotiates an encrypted connection.
It is the same functionality as implemented in your web browser when you connect to HTTPS sites.
If you are accessing your own server:
- Generate a root certificate for your own certificate authority
- Generate a cert & private key using your root certificate ("self-signed cert") for your server
If you are accessing a public server:
- Obtain the cert of the public CA that signed that server's cert
Then:
- In WiFiClientSecure use setCACert (or the appropriate connect method) to set the root cert of your
CA or of the public CA
- When WiFiClientSecure connects to the target server it uses the CA cert to verify the certificate
presented by the server, and then negotiates encryption for the connection
Please see the WiFiClientSecure example.
Using a root CA cert and client cert/keys
-----------------------------------------
This method authenticates the server and additionally also authenticates
the client to the server, then negotiates an encrypted connection.
- Follow steps above
- Using your root CA generate cert/key for your client
- Register the keys with the server you will be accessing so the server can authenticate your client
- In WiFiClientSecure use setCACert (or the appropriate connect method) to set the root cert of your
CA or of the public CA, this is used to authenticate the server
- In WiFiClientSecure use setCertificate, and setPrivateKey (or the appropriate connect method) to
set your client's cert & key, this will be used to authenticate your client to the server
- When WiFiClientSecure connects to the target server it uses the CA cert to verify the certificate
presented by the server, it will use the cert/key to authenticate your client to the server, and
it will then negotiate encryption for the connection
Using Pre-Shared Keys (PSK)
---------------------------
TLS supports authentication and encryption using a pre-shared key (i.e. a key that both client and
server know) as an alternative to the public key cryptography commonly used on the web for HTTPS.
PSK is starting to be used for MQTT, e.g. in mosquitto, to simplify the set-up and avoid having to
go through the whole CA, cert, and private key process.
A pre-shared key is a binary string of up to 32 bytes and is commonly represented in hex form. In
addition to the key, clients can also present an id and typically the server allows a different key
to be associated with each client id. In effect this is very similar to username and password pairs,
except that unlike a password the key is not directly transmitted to the server, thus a connection to a
malicious server does not divulge the password. Plus the server is also authenticated to the client.
To use PSK:
- Generate a random hex string (generating an MD5 or SHA for some file is one way to do this)
- Come up with a string id for your client and configure your server to accept the id/key pair
- In WiFiClientSecure use setPreSharedKey (or the appropriate connect method) to
set the id/key combo
- When WiFiClientSecure connects to the target server it uses the id/key combo to authenticate the
server (it must prove that it has the key too), authenticate the client and then negotiate
encryption for the connection
Please see the WiFiClientPSK example.

View File

@ -0,0 +1,85 @@
/*
Wifi secure connection example for ESP32 using a pre-shared key (PSK)
This is useful with MQTT servers instead of using a self-signed cert, tested with mosquitto.
Running on TLS 1.2 using mbedTLS
To test run a test server using: openssl s_server -accept 8443 -psk 1a2b3c4d -nocert
It will show the http request made, but there's no easy way to send a reply back...
2017 - Evandro Copercini - Apache 2.0 License.
2018 - Adapted for PSK by Thorsten von Eicken
*/
#include <WiFiClientSecure.h>
#if 0
const char* ssid = "your-ssid"; // your network SSID (name of wifi network)
const char* password = "your-password"; // your network password
#else
const char* ssid = "test"; // your network SSID (name of wifi network)
const char* password = "securetest"; // your network password
#endif
//const char* server = "server.local"; // Server hostname
const IPAddress server = IPAddress(192, 168, 0, 14); // Server IP address
const int port = 8443; // server's port (8883 for MQTT)
const char* pskIdent = "Client_identity"; // PSK identity (sometimes called key hint)
const char* psKey = "1a2b3c4d"; // PSK Key (must be hex string without 0x)
WiFiClientSecure client;
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(115200);
delay(100);
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
// attempt to connect to Wifi network:
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
// wait 1 second for re-trying
delay(1000);
}
Serial.print("Connected to ");
Serial.println(ssid);
client.setPreSharedKey(pskIdent, psKey);
Serial.println("\nStarting connection to server...");
if (!client.connect(server, port))
Serial.println("Connection failed!");
else {
Serial.println("Connected to server!");
// Make a HTTP request:
client.println("GET /a/check HTTP/1.0");
client.print("Host: ");
client.println(server);
client.println("Connection: close");
client.println();
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line == "\r") {
Serial.println("headers received");
break;
}
}
// if there are incoming bytes available
// from the server, read them and print them:
while (client.available()) {
char c = client.read();
Serial.write(c);
}
client.stop();
}
}
void loop() {
// do nothing
}

View File

@ -39,6 +39,8 @@ WiFiClientSecure::WiFiClientSecure()
_CA_cert = NULL;
_cert = NULL;
_private_key = NULL;
_pskIdent = NULL;
_psKey = NULL;
next = NULL;
}
@ -59,6 +61,8 @@ WiFiClientSecure::WiFiClientSecure(int sock)
_CA_cert = NULL;
_cert = NULL;
_private_key = NULL;
_pskIdent = NULL;
_psKey = NULL;
next = NULL;
}
@ -89,11 +93,15 @@ void WiFiClientSecure::stop()
int WiFiClientSecure::connect(IPAddress ip, uint16_t port)
{
if (_pskIdent && _psKey)
return connect(ip, port, _pskIdent, _psKey);
return connect(ip, port, _CA_cert, _cert, _private_key);
}
int WiFiClientSecure::connect(const char *host, uint16_t port)
{
if (_pskIdent && _psKey)
return connect(host, port, _pskIdent, _psKey);
return connect(host, port, _CA_cert, _cert, _private_key);
}
@ -104,7 +112,24 @@ int WiFiClientSecure::connect(IPAddress ip, uint16_t port, const char *_CA_cert,
int WiFiClientSecure::connect(const char *host, uint16_t port, const char *_CA_cert, const char *_cert, const char *_private_key)
{
int ret = start_ssl_client(sslclient, host, port, _CA_cert, _cert, _private_key);
int ret = start_ssl_client(sslclient, host, port, _CA_cert, _cert, _private_key, NULL, NULL);
_lastError = ret;
if (ret < 0) {
log_e("start_ssl_client: %d", ret);
stop();
return 0;
}
_connected = true;
return 1;
}
int WiFiClientSecure::connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey) {
return connect(ip.toString().c_str(), port,_pskIdent, _psKey);
}
int WiFiClientSecure::connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey) {
log_v("start_ssl_client with PSK");
int ret = start_ssl_client(sslclient, host, port, NULL, NULL, NULL, _pskIdent, _psKey);
_lastError = ret;
if (ret < 0) {
log_e("start_ssl_client: %d", ret);
@ -131,13 +156,6 @@ size_t WiFiClientSecure::write(uint8_t data)
int WiFiClientSecure::read()
{
uint8_t data = -1;
if(_peek >= 0){
data = _peek;
_peek = -1;
return data;
}
int res = read(&data, 1);
if (res < 0) {
return res;
@ -161,7 +179,8 @@ size_t WiFiClientSecure::write(const uint8_t *buf, size_t size)
int WiFiClientSecure::read(uint8_t *buf, size_t size)
{
int peeked = 0;
if ((!buf && size) || (_peek < 0 && !available())) {
int avail = available();
if ((!buf && size) || avail <= 0) {
return -1;
}
if(!size){
@ -171,7 +190,8 @@ int WiFiClientSecure::read(uint8_t *buf, size_t size)
buf[0] = _peek;
_peek = -1;
size--;
if(!size || !available()){
avail--;
if(!size || !avail){
return 1;
}
buf++;
@ -181,23 +201,23 @@ int WiFiClientSecure::read(uint8_t *buf, size_t size)
int res = get_ssl_receive(sslclient, buf, size);
if (res < 0) {
stop();
return res;
return peeked?peeked:res;
}
return res + peeked;
}
int WiFiClientSecure::available()
{
int peeked = (_peek >= 0);
if (!_connected) {
return 0;
return peeked;
}
int res = data_to_read(sslclient);
if (res < 0 ) {
if (res < 0) {
stop();
} else if(_peek >= 0) {
res += 1;
return peeked?peeked:res;
}
return res;
return res+peeked;
}
uint8_t WiFiClientSecure::connected()
@ -223,6 +243,11 @@ void WiFiClientSecure::setPrivateKey (const char *private_key)
_private_key = private_key;
}
void WiFiClientSecure::setPreSharedKey(const char *pskIdent, const char *psKey) {
_pskIdent = pskIdent;
_psKey = psKey;
}
bool WiFiClientSecure::verify(const char* fp, const char* domain_name)
{
if (!sslclient)
@ -232,18 +257,19 @@ bool WiFiClientSecure::verify(const char* fp, const char* domain_name)
}
char *WiFiClientSecure::_streamLoad(Stream& stream, size_t size) {
char *dest = (char*)malloc(size);
static char *dest = nullptr;
if(dest) {
free(dest);
}
dest = (char*)malloc(size);
if (!dest) {
return nullptr;
}
if (size != stream.readBytes(dest, size)) {
free(dest);
return nullptr;
dest = nullptr;
}
char ret[size+1];
snprintf(ret, size, "%s", dest);
free(dest);
return ret;
return dest;
}
bool WiFiClientSecure::loadCACert(Stream& stream, size_t size) {
@ -290,4 +316,4 @@ int WiFiClientSecure::lastError(char *buf, const size_t size)
void WiFiClientSecure::setHandshakeTimeout(unsigned long handshake_timeout)
{
sslclient->handshake_timeout = handshake_timeout * 1000;
}
}

View File

@ -35,6 +35,8 @@ protected:
const char *_CA_cert;
const char *_cert;
const char *_private_key;
const char *_pskIdent; // identity for PSK cipher suites
const char *_psKey; // key in hex for PSK cipher suites
public:
WiFiClientSecure *next;
@ -45,6 +47,8 @@ public:
int connect(const char *host, uint16_t port);
int connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
int connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey);
int connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey);
int peek();
size_t write(uint8_t data);
size_t write(const uint8_t *buf, size_t size);
@ -55,6 +59,7 @@ public:
void stop();
uint8_t connected();
int lastError(char *buf, const size_t size);
void setPreSharedKey(const char *pskIdent, const char *psKey); // psKey in Hex
void setCACert(const char *rootCA);
void setCertificate(const char *client_ca);
void setPrivateKey (const char *private_key);

View File

@ -45,12 +45,12 @@ void ssl_init(sslclient_context *ssl_client)
}
int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key)
int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey)
{
char buf[512];
int ret, flags, timeout;
int enable = 1;
log_v("Free heap before TLS %u", xPortGetFreeHeapSize());
log_v("Free internal heap before TLS %u", ESP.getFreeHeap());
log_v("Starting socket");
ssl_client->socket = -1;
@ -116,6 +116,36 @@ int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t p
if (ret < 0) {
return handle_error(ret);
}
} else if (pskIdent != NULL && psKey != NULL) {
log_v("Setting up PSK");
// convert PSK from hex to binary
if ((strlen(psKey) & 1) != 0 || strlen(psKey) > 2*MBEDTLS_PSK_MAX_LEN) {
log_e("pre-shared key not valid hex or too long");
return -1;
}
unsigned char psk[MBEDTLS_PSK_MAX_LEN];
size_t psk_len = strlen(psKey)/2;
for (int j=0; j<strlen(psKey); j+= 2) {
char c = psKey[j];
if (c >= '0' && c <= '9') c -= '0';
else if (c >= 'A' && c <= 'F') c -= 'A' - 10;
else if (c >= 'a' && c <= 'f') c -= 'a' - 10;
else return -1;
psk[j/2] = c<<4;
c = psKey[j+1];
if (c >= '0' && c <= '9') c -= '0';
else if (c >= 'A' && c <= 'F') c -= 'A' - 10;
else if (c >= 'a' && c <= 'f') c -= 'a' - 10;
else return -1;
psk[j/2] |= c;
}
// set mbedtls config
ret = mbedtls_ssl_conf_psk(&ssl_client->ssl_conf, psk, psk_len,
(const unsigned char *)pskIdent, strlen(pskIdent));
if (ret != 0) {
log_e("mbedtls_ssl_conf_psk returned %d", ret);
return handle_error(ret);
}
} else {
mbedtls_ssl_conf_authmode(&ssl_client->ssl_conf, MBEDTLS_SSL_VERIFY_NONE);
log_i("WARNING: Use certificates for a more secure communication!");
@ -202,7 +232,7 @@ int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t p
mbedtls_pk_free(&ssl_client->client_key);
}
log_v("Free heap after TLS %u", xPortGetFreeHeapSize());
log_v("Free internal heap after TLS %u", ESP.getFreeHeap());
return ssl_client->socket;
}

View File

@ -29,7 +29,7 @@ typedef struct sslclient_context {
void ssl_init(sslclient_context *ssl_client);
int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey);
void stop_ssl_socket(sslclient_context *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key);
int data_to_read(sslclient_context *ssl_client);
int send_ssl_data(sslclient_context *ssl_client, const uint8_t *data, uint16_t len);

View File

@ -0,0 +1,276 @@
# Debugging I2C
With the release of Arduino-ESP32 V1.0.1 the I2C subsystem contains code to exhaustively report communication errors.
* Basic debugging can be enable by setting the *CORE DEBUG LEVEL* at or above *ERROR*. All errors will be directed the the *DEBUG OUTPUT* normally connected to `Serial()`.
* Enhanced debugging can be used to generate specified information at specific positions during the i2c communication sequence. Increase *CORE DEBUG LEVEL* to ***DEBUG***
## Enable Debug Buffer
The Enhanced debug features are enabled by uncommenting the `\\#define ENABLE_I2C_DEBUG_BUFFER` at line 45 of `esp32-hal-i2c.c`.
* When Arduino-Esp32 is installed in Windows with Arduino Boards Manager, `esp32-hal-i2c.c` can be found in:
`C:\Users\{user}\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.1\cores\esp32\`
* When Arduino-Esp32 Development version is installed from GitHub, `esp32-hal-i2c.c` can be found in:
`{arduino Sketch}\hardware\espressif\esp32\cores\esp32\`
```c++
//#define ENABLE_I2C_DEBUG_BUFFER
```
Change it to:
```c++
#define ENABLE_I2C_DEBUG_BUFFER
```
and recompile/upload the resulting code to your ESP32.
Enabling this `#define` will consume an additional 2570 bytes of RAM and include a commensurate amount of code FLASH. If you see the message `"Debug Buffer not Enabled"` in your console log I would suggest you un-comment the line and regenerate the error. Additional information will be supplied on the log console.
## Manually controlled Debugging
Manual logging of the i2c control data buffers can be accomplished by using the debug control function of `Wire()`:
```c++
uint32_t setDebugFlags( uint32_t setBits, uint32_t resetBits);
```
`setBits`, and `resetBits` manually cause output of the control structures to the log console. They are bit fields that enable/disable the reporting of individual control structures during specific phases of the i2c communications sequence. The 32bit values are divided into four 8bit fields. Currently only five bits are defined. ***If an error is detected during normal operations, the relevant control structure will bit added to the log irrespective of the current debug flags.***
* **bit 0** causes DumpI2c to execute
header information about current communications event,
and the dataQueue elements showing the logical i2c transaction commands
* **bit 1** causes DumpInts to execute
Actual sequence of interrupts handled during last communications event, cleared on entry into `ProcQueue()`.
* **bit 2** causes DumpCmdqueue to execute
The last block of commands to the i2c peripheral.
* **bit 3** causes DumpStatus to execute
A descriptive display of the 32bit i2c peripheral status word.
* **bit 4** causes DumpFifo to execute
A buffer listing the sequence of data added to the txFifo of the i2c peripheral.
Of the four division, only three are currently implemented:
* 0xXX - - - - - - : at entry of ProcQueue (`bitFlags << 24`)
* 0x - - XX - - - - : at exit of ProcQueue (`bitFlags << 16`)
* 0x - - - - - - XX : at entry of Flush (`bitFlags`)
For example, to display the sequence of Interrupts processed during the i2c communication transaction, **bit 1** would be set, and, since this information on Interrupt usage would only be valid after the communications have completed, the locus would be *at exit of ProcQueue*. The following code would be necessary.
### code
```c++
uint8_t flag = 1 << 1; // turn on bit 1
uint32_t debugFlag = flag << 16; // correctly position the 8bits of flag as the second byte of setBits.
Wire.setDebugFlags(debugFlag,0);// resetBits=0 says leave all current setBits as is.
Wire.requestFrom(id,byteCount); // read byteCount bytes from slave at id
Wire.setDebugFlags(0,debugFlag); // don't add any new debug, remove debugFlag
```
### output of log console
```
[I][esp32-hal-i2c.c:437] i2cTriggerDumps(): after ProcQueue
[I][esp32-hal-i2c.c:346] i2cDumpInts(): 0 row count INTR TX RX Tick
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [01] 0x0001 0x0002 0x0003 0x0000 0x005baac5
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [02] 0x0001 0x0200 0x0000 0x0000 0x005baac5
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [03] 0x0001 0x0080 0x0000 0x0008 0x005baac6
```
# Debug Log example
### Code
To read eight bytes of data from a DS1307 RTCC
```
uint32_t debugFlag = 0x001F0000;
uint8_t ID = 0x68;
uint8_t block=8;
if(debugFlag >0){
Wire.setDebugFlags(debugFlag,0);
}
Wire.beginTransmission(ID);
Wire.write(lowByte(addr));
if((err=Wire.endTransmission(false))!=0) {
Serial.printf(" EndTransmission=%d(%s)",Wire.lastError(),Wire.getErrorText(Wire.lastError()));
if(err!=2) {
Serial.printf(", resetting\n");
if( !Wire.begin()) Serial.printf(" Reset Failed\n");
if(debugFlag >0) Wire.setDebugFlags(0,debugFlag);
return;
} else {
Serial.printf(", No Device present, aborting\n");
currentCommand= NO_COMMAND;
return;
}
}
err = Wire.requestFrom(ID,block,true);
if(debugFlag >0){
Wire.setDebugFlags(0,debugFlag);
}
```
### output of log console
```
[I][esp32-hal-i2c.c:437] i2cTriggerDumps(): after ProcQueue
[E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbdc78
[I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000
[I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffb843c
[I][esp32-hal-i2c.c:323] i2cDumpI2c(): num=0
[I][esp32-hal-i2c.c:324] i2cDumpI2c(): mode=1
[I][esp32-hal-i2c.c:325] i2cDumpI2c(): stage=3
[I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=1
[I][esp32-hal-i2c.c:327] i2cDumpI2c(): event=0x3ffb85c4 bits=10
[I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffb85f4
[I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffb858c
[I][esp32-hal-i2c.c:330] i2cDumpI2c(): queueCount=2
[I][esp32-hal-i2c.c:331] i2cDumpI2c(): queuePos=1
[I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=0
[I][esp32-hal-i2c.c:333] i2cDumpI2c(): errorQueue=0
[I][esp32-hal-i2c.c:334] i2cDumpI2c(): debugFlags=0x001F0000
[I][esp32-hal-i2c.c:288] i2cDumpDqData(): [0] 7bit 68 W buf@=0x3ffc04b2, len=1, pos=1, ctrl=11101
[I][esp32-hal-i2c.c:306] i2cDumpDqData(): 0x0000: . 00
[I][esp32-hal-i2c.c:288] i2cDumpDqData(): [1] 7bit 68 R STOP buf@=0x3ffc042c, len=8, pos=8, ctrl=11111
[I][esp32-hal-i2c.c:306] i2cDumpDqData(): 0x0000: 5P...... 35 50 07 06 13 09 18 00
[I][esp32-hal-i2c.c:346] i2cDumpInts(): 0 row count INTR TX RX Tick
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [01] 0x0001 0x0002 0x0003 0x0000 0x000073d5
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [02] 0x0001 0x0200 0x0000 0x0000 0x000073d5
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [03] 0x0001 0x0080 0x0000 0x0008 0x000073d6
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 0] Y RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 1] Y WRITE val[0] exp[0] en[1] bytes[1]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 2] Y WRITE val[0] exp[0] en[1] bytes[1]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 3] Y RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 4] Y WRITE val[0] exp[0] en[1] bytes[1]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 5] Y READ val[0] exp[0] en[0] bytes[7]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 6] Y READ val[1] exp[0] en[0] bytes[1]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 7] Y STOP val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 8] N RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 9] N RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [10] N RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [11] N RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [12] N RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [13] N RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [14] N RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [15] N RSTART val[0] exp[0] en[0] bytes[0]
[I][esp32-hal-i2c.c:385] i2cDumpStatus(): ack(0) sl_rw(0) to(0) arb(0) busy(0) sl(1) trans(0) rx(0) tx(0) sclMain(5) scl(6)
[I][esp32-hal-i2c.c:424] i2cDumpFifo(): WRITE 0x68 0
[I][esp32-hal-i2c.c:424] i2cDumpFifo(): READ 0x68
```
## Explaination of log output
### DumpI2c
```
[I][esp32-hal-i2c.c:437] i2cTriggerDumps(): after ProcQueue
[E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbdc78
[I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000
[I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffb843c
[I][esp32-hal-i2c.c:323] i2cDumpI2c(): num=0
[I][esp32-hal-i2c.c:324] i2cDumpI2c(): mode=1
[I][esp32-hal-i2c.c:325] i2cDumpI2c(): stage=3
[I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=1
[I][esp32-hal-i2c.c:327] i2cDumpI2c(): event=0x3ffb85c4 bits=10
[I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffb85f4
[I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffb858c
[I][esp32-hal-i2c.c:330] i2cDumpI2c(): queueCount=2
[I][esp32-hal-i2c.c:331] i2cDumpI2c(): queuePos=1
[I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=0
[I][esp32-hal-i2c.c:333] i2cDumpI2c(): errorQueue=0
[I][esp32-hal-i2c.c:334] i2cDumpI2c(): debugFlags=0x001F0000
```
variable | description
---- | ----
**i2c** | *memory address for control block*
**dev** | *memory address for access to i2c peripheral registers*
**date** | *revision date of peripheral silicon 2016, 42 week*
**lock** | *hal lock handle*
**num** | *0,1 which peripheral is being controlled*
**mode** | *configuration of driver 0=none, 1=MASTER, 2=SLAVE, 3=MASTER and SLAVE*
**stage** | *internal STATE of driver 0=not configured, 1=startup, 2=running, 3=done*
**error** | *internal ERROR status 0=not configured, 1=ok, 2=error, 3=address NAK, 4=data NAK, 5=arbitration loss, 6=timeout*
**event** | *handle for interprocess FreeRTOS eventSemaphore for communication between ISR and APP*
**intr_handle** | *FreeRTOS handle for allocated interrupt*
**dq** | *memory address for data queue control block*
**queueCount** | *number of data operations in queue control block*
**queuePos** | *last executed data block*
**errorByteCnt** | *position in current data block when error occured -1=address byte*
**errorQueue** | *queue that was executing when error occurred*
**debugFlags** | *current specified error bits*
### DQ data
```
[I][esp32-hal-i2c.c:288] i2cDumpDqData(): [0] 7bit 68 W buf@=0x3ffc04b2, len=1, pos=1, ctrl=11101
[I][esp32-hal-i2c.c:306] i2cDumpDqData(): 0x0000: . 00
[I][esp32-hal-i2c.c:288] i2cDumpDqData(): [1] 7bit 68 R STOP buf@=0x3ffc042c, len=8, pos=8, ctrl=11111
[I][esp32-hal-i2c.c:306] i2cDumpDqData(): 0x0000: 5P...... 35 50 07 06 13 09 18 00
```
variable | description
--- | ---
**[n]** | *index of data queue element*
**i2c address** | *7bit= 7bit i2c slave address, 10bit= 10bit i2c slave address*
**direction** | *W=Write, R=READ*
**STOP** | *command issued a I2C STOP, else if blank, a RESTART was issued by next dq element.*
**buf@** | *pointer to data buffer*
**len** | *length of data buffer*
**pos** | *last position used in buffer*
**ctrl** | *bit field for data queue control, this bits describe if all necessary commands have been added to peripheral command buffer. in order(START,ADDRESS_Write,DATA,STOP,ADDRESS_value*
**0xnnnn** | *data buffer content, displayable followed by HEX, 32 bytes on a line.*
### DumpInts
```
[I][esp32-hal-i2c.c:346] i2cDumpInts(): 0 row count INTR TX RX Tick
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [01] 0x0001 0x0002 0x0003 0x0000 0x000073d5
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [02] 0x0001 0x0200 0x0000 0x0000 0x000073d5
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [03] 0x0001 0x0080 0x0000 0x0008 0x000073d6
```
variable | description
---- | ----
**row** | *array index*
**count** | *number of consecutive, duplicate interrupts*
**INTR** | *bit value of active interrupt (from ..\esp32\tools\sdk\include\soc\soc\i2c_struct.h)*
**TX** | *number of bytes added to txFifo*
**RX** | *number of bytes read from rxFifo*
**Tick** | *current tick counter from xTaskGetTickCountFromISR()*
### DumpCmdQueue
```
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 0] Y RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 1] Y WRITE val[0] exp[0] en[1] bytes[1]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 2] Y WRITE val[0] exp[0] en[1] bytes[1]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 3] Y RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 4] Y WRITE val[0] exp[0] en[1] bytes[1]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 5] Y READ val[0] exp[0] en[0] bytes[7]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 6] Y READ val[1] exp[0] en[0] bytes[1]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 7] Y STOP val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 8] N RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [ 9] N RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [10] N RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [11] N RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [12] N RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [13] N RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [14] N RSTART val[0] exp[0] en[0] bytes[0]
[E][esp32-hal-i2c.c:243] i2cDumpCmdQueue(): [15] N RSTART val[0] exp[0] en[0] bytes[0]
```
Column | description
---- | ----
**command** | *RSTART= generate i2c START sequence, WRITE= output byte(s), READ= input byte(s), STOP= generate i2c STOP sequence, END= continuation flag for peripheral to pause execution waiting for a refilled command list*
**val** | *value for ACK bit, 0 = LOW, 1= HIGH*
**exp** | *test of ACK bit 0=no, 1=yes*
**en** | *output of val, 0=no, 1=yes*
**bytes** | *number of byte to send(WRITE) or receive(READ) 1..255*
### DumpStatus
```
[I][esp32-hal-i2c.c:385] i2cDumpStatus(): ack(0) sl_rw(0) to(0) arb(0) busy(0) sl(1) trans(0) rx(0) tx(0) sclMain(5) scl(6)
```
variable | description
---- | ----
**ack** | *last value for ACK bit*
**sl_rw** | *mode for SLAVE operation 0=write, 1=read*
**to** | *timeout*
**arb** | *arbitration loss*
**busy** | *bus is inuse by other Master, or SLAVE is holding SCL,SDA*
**sl** | *last address on bus was equal to slave_addr*
**trans** | *a byte has moved though peripheral*
**rx** | *count of bytes in rxFifo*
**tx** | *count of bytes in txFifo*
**sclMain** | *state machine for i2c module. 0: SCL_MAIN_IDLE, 1: SCL_ADDRESS_SHIFT, 2: SCL_ACK_ADDRESS, 3: SCL_RX_DATA, 4: SCL_TX_DATA, 5: SCL_SEND_ACK, 6 :SCL_WAIT_ACK*
**scl** | *SCL clock state. 0: SCL_IDLE, 1: SCL_START, 2: SCL_LOW_EDGE, 3: SCL_LOW, 4: SCL_HIGH_EDGE, 5: SCL_HIGH, 6:SCL_STOP*
### DumpFifo
```
[I][esp32-hal-i2c.c:424] i2cDumpFifo(): WRITE 0x68 0
[I][esp32-hal-i2c.c:424] i2cDumpFifo(): READ 0x68
```
Mode | datavalues
--- | ---
**WRITE** | the following bytes added to the txFifo are in response to a WRITE command
**READ** | the following bytes added to the txFifo are in response to a READ command

View File

@ -154,14 +154,15 @@ void TwoWire::beginTransmission(uint16_t address)
uint8_t TwoWire::endTransmission(bool sendStop) // Assumes Wire.beginTransaction(), Wire.write()
{
if(transmitting == 1) {
last_error = writeTransmission(txAddress, &txBuffer[txQueued], txLength - txQueued, sendStop);
rxIndex = 0;
rxLength = rxQueued;
rxQueued = 0;
txQueued = 0; // the SendStop=true will restart all Queueing
if(last_error == I2C_ERROR_CONTINUE){
// txlength is howmany bytes in txbuffer have been use
last_error = writeTransmission(txAddress, &txBuffer[txQueued], txLength - txQueued, sendStop);
if(last_error == I2C_ERROR_CONTINUE){
txQueued = txLength;
} else if( last_error == I2C_ERROR_OK){
rxIndex = 0;
rxLength = rxQueued;
rxQueued = 0;
txQueued = 0; // the SendStop=true will restart all Queueing
}
} else {
last_error = I2C_ERROR_NO_BEGIN;
@ -170,7 +171,7 @@ uint8_t TwoWire::endTransmission(bool sendStop) // Assumes Wire.beginTransactio
txIndex = 0;
txLength = 0;
transmitting = 0;
return last_error;
return (last_error == I2C_ERROR_CONTINUE)?I2C_ERROR_OK:last_error; // Don't return Continue for compatibility.
}
/* @stickBreaker 11/2017 fix for ReSTART timeout, ISR
@ -191,12 +192,19 @@ uint8_t TwoWire::requestFrom(uint16_t address, uint8_t size, bool sendStop)
last_error = readTransmission(address, &rxBuffer[cnt], size, sendStop, &cnt);
rxIndex = 0;
rxLength = rxQueued;
rxQueued = 0;
txQueued = 0; // the SendStop=true will restart all Queueing
if(last_error != I2C_ERROR_OK){
rxLength = cnt;
if( last_error != I2C_ERROR_CONTINUE){ // not a buffered ReSTART operation
// so this operation actually moved data, queuing is done.
rxQueued = 0;
txQueued = 0; // the SendStop=true will restart all Queueing or error condition
}
if(last_error != I2C_ERROR_OK){ // ReSTART on read does not return any data
cnt = 0;
}
return cnt;
}

View File

@ -30,7 +30,7 @@
#include "freertos/queue.h"
#include "Stream.h"
#define STICKBREAKER V1.0.1
#define STICKBREAKER 'V1.1.0'
#define I2C_BUFFER_LENGTH 128
typedef void(*user_onRequest)(void);
typedef void(*user_onReceive)(uint8_t*, int);
@ -67,12 +67,13 @@ protected:
public:
TwoWire(uint8_t bus_num);
~TwoWire();
bool begin(int sda=-1, int scl=-1, uint32_t frequency=0);
bool begin(int sda=-1, int scl=-1, uint32_t frequency=0); // returns true, if successful init of i2c bus
// calling will attemp to recover hung bus
void setClock(uint32_t frequency); // change bus clock without initing hardware
size_t getClock(); // current bus clock rate in hz
void setTimeOut(uint16_t timeOutMillis);
void setTimeOut(uint16_t timeOutMillis); // default timeout of i2c transactions is 50ms
uint16_t getTimeOut();
uint8_t lastError();
@ -137,6 +138,8 @@ extern TwoWire Wire1;
/*
V1.1.0 08JAN2019 Support CPU Clock frequency changes
V1.0.2 30NOV2018 stop returning I2C_ERROR_CONTINUE on ReSTART operations, regain compatibility with Arduino libs
V1.0.1 02AUG2018 First Fix after release, Correct ReSTART handling, change Debug control, change begin()
to a function, this allow reporting if bus cannot be initialized, Wire.begin() can be used to recover
a hung bus busy condition.

View File

@ -37,8 +37,8 @@
},
{
"packager": "esp32",
"name": "esptool",
"version": "2.5.0"
"name": "esptool_py",
"version": "2.6.1"
},
{
"packager": "esp32",
@ -84,43 +84,43 @@
]
},
{
"name": "esptool",
"version": "2.5.0",
"name": "esptool_py",
"version": "2.6.1",
"systems": [
{
"host": "i686-mingw32",
"url": "https://dl.espressif.com/dl/esptool-2.5.0-windows.zip",
"archiveFileName": "esptool-2.5.0-windows.zip",
"checksum": "SHA-256:576b8068b577cae0e6e937566a9d32a08ff7ff82963fb60400eacb6691f2fbfb",
"size": "3420959"
"url": "https://dl.espressif.com/dl/esptool-2.6.1-windows.zip",
"archiveFileName": "esptool-2.6.1-windows.zip",
"checksum": "SHA-256:84cf0b369a7707fe566434faba148852fc464992111d5baa95b658b374802f96",
"size": "3422445"
},
{
"host": "x86_64-apple-darwin",
"url": "https://dl.espressif.com/dl/esptool-2.5.0-macos.tar.gz",
"archiveFileName": "esptool-2.5.0-macos.tar.gz",
"checksum": "SHA-256:2da8ba3b83d99b5d808cab955a077e3e0738ec640b51de932d047cad7fac1157",
"size": "3835397"
"url": "https://dl.espressif.com/dl/esptool-2.6.1-macos.tar.gz",
"archiveFileName": "esptool-2.6.1-macos.tar.gz",
"checksum": "SHA-256:f4eb758a301d6902cc9dfcd49d36345d2f075ad123da7cf8132d15cfb7533457",
"size": "3837085"
},
{
"host": "x86_64-pc-linux-gnu",
"url": "https://dl.espressif.com/dl/esptool-2.5.0-linux.tar.gz",
"archiveFileName": "esptool-2.5.0-linux.tar.gz",
"checksum": "SHA-256:34d63b9a0bf2acb9b6fdac15f91a8756f4e722065de031e8fbce4e4abc369e54",
"size": "43468"
"url": "https://dl.espressif.com/dl/esptool-2.6.1-linux.tar.gz",
"archiveFileName": "esptool-2.6.1-linux.tar.gz",
"checksum": "SHA-256:eaf82ff4070d9792f6a42ae1e485375de5a87bec59ef01dfb95de901519ec7fb",
"size": "44762"
},
{
"host": "i686-pc-linux-gnu",
"url": "https://dl.espressif.com/dl/esptool-2.5.0-linux.tar.gz",
"archiveFileName": "esptool-2.5.0-linux.tar.gz",
"checksum": "SHA-256:34d63b9a0bf2acb9b6fdac15f91a8756f4e722065de031e8fbce4e4abc369e54",
"size": "43468"
"url": "https://dl.espressif.com/dl/esptool-2.6.1-linux.tar.gz",
"archiveFileName": "esptool-2.6.1-linux.tar.gz",
"checksum": "SHA-256:eaf82ff4070d9792f6a42ae1e485375de5a87bec59ef01dfb95de901519ec7fb",
"size": "44762"
},
{
"host": "arm-linux-gnueabihf",
"url": "https://dl.espressif.com/dl/esptool-2.5.0-linux.tar.gz",
"archiveFileName": "esptool-2.5.0-linux.tar.gz",
"checksum": "SHA-256:34d63b9a0bf2acb9b6fdac15f91a8756f4e722065de031e8fbce4e4abc369e54",
"size": "43468"
"url": "https://dl.espressif.com/dl/esptool-2.6.1-linux.tar.gz",
"archiveFileName": "esptool-2.6.1-linux.tar.gz",
"checksum": "SHA-256:eaf82ff4070d9792f6a42ae1e485375de5a87bec59ef01dfb95de901519ec7fb",
"size": "44762"
}
]
},

View File

@ -3,13 +3,13 @@ version=0.0.1
runtime.tools.xtensa-esp32-elf-gcc.path={runtime.platform.path}/tools/xtensa-esp32-elf
tools.esptool.path={runtime.platform.path}/tools/esptool
tools.esptool.cmd=esptool
tools.esptool.cmd.linux=esptool.py
tools.esptool.cmd.windows=esptool.exe
tools.esptool_py.path={runtime.platform.path}/tools/esptool
tools.esptool_py.cmd=esptool
tools.esptool_py.cmd.linux=esptool.py
tools.esptool_py.cmd.windows=esptool.exe
tools.esptool.network_cmd=python "{runtime.platform.path}/tools/espota.py"
tools.esptool.network_cmd.windows="{runtime.platform.path}/tools/espota.exe"
tools.esptool_py.network_cmd=python "{runtime.platform.path}/tools/espota.py"
tools.esptool_py.network_cmd.windows="{runtime.platform.path}/tools/espota.exe"
tools.gen_esp32part.cmd=python "{runtime.platform.path}/tools/gen_esp32part.py"
tools.gen_esp32part.cmd.windows="{runtime.platform.path}/tools/gen_esp32part.exe"
@ -22,7 +22,7 @@ compiler.warning_flags.all=-Wall -Werror=all -Wextra
compiler.path={runtime.tools.xtensa-esp32-elf-gcc.path}/bin/
compiler.sdk.path={runtime.platform.path}/tools/sdk
compiler.cpreprocessor.flags=-DESP_PLATFORM -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h" -DHAVE_CONFIG_H "-I{compiler.sdk.path}/include/config" "-I{compiler.sdk.path}/include/app_trace" "-I{compiler.sdk.path}/include/app_update" "-I{compiler.sdk.path}/include/asio" "-I{compiler.sdk.path}/include/bootloader_support" "-I{compiler.sdk.path}/include/bt" "-I{compiler.sdk.path}/include/coap" "-I{compiler.sdk.path}/include/console" "-I{compiler.sdk.path}/include/driver" "-I{compiler.sdk.path}/include/esp-tls" "-I{compiler.sdk.path}/include/esp32" "-I{compiler.sdk.path}/include/esp_adc_cal" "-I{compiler.sdk.path}/include/esp_event" "-I{compiler.sdk.path}/include/esp_http_client" "-I{compiler.sdk.path}/include/esp_http_server" "-I{compiler.sdk.path}/include/esp_https_ota" "-I{compiler.sdk.path}/include/esp_https_server" "-I{compiler.sdk.path}/include/esp_ringbuf" "-I{compiler.sdk.path}/include/ethernet" "-I{compiler.sdk.path}/include/expat" "-I{compiler.sdk.path}/include/fatfs" "-I{compiler.sdk.path}/include/freemodbus" "-I{compiler.sdk.path}/include/freertos" "-I{compiler.sdk.path}/include/heap" "-I{compiler.sdk.path}/include/idf_test" "-I{compiler.sdk.path}/include/jsmn" "-I{compiler.sdk.path}/include/json" "-I{compiler.sdk.path}/include/libsodium" "-I{compiler.sdk.path}/include/log" "-I{compiler.sdk.path}/include/lwip" "-I{compiler.sdk.path}/include/mbedtls" "-I{compiler.sdk.path}/include/mdns" "-I{compiler.sdk.path}/include/micro-ecc" "-I{compiler.sdk.path}/include/mqtt" "-I{compiler.sdk.path}/include/newlib" "-I{compiler.sdk.path}/include/nghttp" "-I{compiler.sdk.path}/include/nvs_flash" "-I{compiler.sdk.path}/include/openssl" "-I{compiler.sdk.path}/include/protobuf-c" "-I{compiler.sdk.path}/include/protocomm" "-I{compiler.sdk.path}/include/pthread" "-I{compiler.sdk.path}/include/sdmmc" "-I{compiler.sdk.path}/include/smartconfig_ack" "-I{compiler.sdk.path}/include/soc" "-I{compiler.sdk.path}/include/spi_flash" "-I{compiler.sdk.path}/include/spiffs" "-I{compiler.sdk.path}/include/tcp_transport" "-I{compiler.sdk.path}/include/tcpip_adapter" "-I{compiler.sdk.path}/include/ulp" "-I{compiler.sdk.path}/include/unity" "-I{compiler.sdk.path}/include/vfs" "-I{compiler.sdk.path}/include/wear_levelling" "-I{compiler.sdk.path}/include/wifi_provisioning" "-I{compiler.sdk.path}/include/wpa_supplicant" "-I{compiler.sdk.path}/include/xtensa-debug-module"
compiler.cpreprocessor.flags=-DESP_PLATFORM -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h" -DHAVE_CONFIG_H "-I{compiler.sdk.path}/include/config" "-I{compiler.sdk.path}/include/app_trace" "-I{compiler.sdk.path}/include/app_update" "-I{compiler.sdk.path}/include/asio" "-I{compiler.sdk.path}/include/bootloader_support" "-I{compiler.sdk.path}/include/bt" "-I{compiler.sdk.path}/include/coap" "-I{compiler.sdk.path}/include/console" "-I{compiler.sdk.path}/include/driver" "-I{compiler.sdk.path}/include/efuse" "-I{compiler.sdk.path}/include/esp-tls" "-I{compiler.sdk.path}/include/esp32" "-I{compiler.sdk.path}/include/esp_adc_cal" "-I{compiler.sdk.path}/include/esp_event" "-I{compiler.sdk.path}/include/esp_http_client" "-I{compiler.sdk.path}/include/esp_http_server" "-I{compiler.sdk.path}/include/esp_https_ota" "-I{compiler.sdk.path}/include/esp_https_server" "-I{compiler.sdk.path}/include/esp_ringbuf" "-I{compiler.sdk.path}/include/espcoredump" "-I{compiler.sdk.path}/include/ethernet" "-I{compiler.sdk.path}/include/expat" "-I{compiler.sdk.path}/include/fatfs" "-I{compiler.sdk.path}/include/freemodbus" "-I{compiler.sdk.path}/include/freertos" "-I{compiler.sdk.path}/include/heap" "-I{compiler.sdk.path}/include/idf_test" "-I{compiler.sdk.path}/include/jsmn" "-I{compiler.sdk.path}/include/json" "-I{compiler.sdk.path}/include/libsodium" "-I{compiler.sdk.path}/include/log" "-I{compiler.sdk.path}/include/lwip" "-I{compiler.sdk.path}/include/mbedtls" "-I{compiler.sdk.path}/include/mdns" "-I{compiler.sdk.path}/include/micro-ecc" "-I{compiler.sdk.path}/include/mqtt" "-I{compiler.sdk.path}/include/newlib" "-I{compiler.sdk.path}/include/nghttp" "-I{compiler.sdk.path}/include/nvs_flash" "-I{compiler.sdk.path}/include/openssl" "-I{compiler.sdk.path}/include/protobuf-c" "-I{compiler.sdk.path}/include/protocomm" "-I{compiler.sdk.path}/include/pthread" "-I{compiler.sdk.path}/include/sdmmc" "-I{compiler.sdk.path}/include/smartconfig_ack" "-I{compiler.sdk.path}/include/soc" "-I{compiler.sdk.path}/include/spi_flash" "-I{compiler.sdk.path}/include/spiffs" "-I{compiler.sdk.path}/include/tcp_transport" "-I{compiler.sdk.path}/include/tcpip_adapter" "-I{compiler.sdk.path}/include/ulp" "-I{compiler.sdk.path}/include/unity" "-I{compiler.sdk.path}/include/vfs" "-I{compiler.sdk.path}/include/wear_levelling" "-I{compiler.sdk.path}/include/wifi_provisioning" "-I{compiler.sdk.path}/include/wpa_supplicant" "-I{compiler.sdk.path}/include/xtensa-debug-module" "-I{compiler.sdk.path}/include/esp32-camera" "-I{compiler.sdk.path}/include/esp-face" "-I{compiler.sdk.path}/include/fb_gfx"
compiler.c.cmd=xtensa-esp32-elf-gcc
compiler.c.flags=-std=gnu99 -Os -g3 -fstack-protector -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -mlongcalls -nostdlib -Wpointer-arith {compiler.warning_flags} -Wno-error=unused-function -Wno-error=unused-but-set-variable -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-sign-compare -Wno-old-style-declaration -MMD -c
@ -35,7 +35,7 @@ compiler.S.flags=-c -g3 -x assembler-with-cpp -MMD -mlongcalls
compiler.c.elf.cmd=xtensa-esp32-elf-gcc
compiler.c.elf.flags=-nostdlib "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" -T esp32_out.ld -T esp32.common.ld -T esp32.rom.ld -T esp32.peripherals.ld -T esp32.rom.spiram_incompatible_fns.ld -u ld_include_panic_highint_hdl -u call_user_start_cpu0 -Wl,--gc-sections -Wl,-static -Wl,--undefined=uxTopUsedPriority -u __cxa_guard_dummy -u __cxx_fatal_exception
compiler.c.elf.libs=-lgcc -lopenssl -lbtdm_app -lfatfs -lwps -lcoexist -lwear_levelling -lesp_http_client -lprotobuf-c -lhal -lnewlib -ldriver -lbootloader_support -lpp -lfreemodbus -lmesh -lsmartconfig -ljsmn -lwpa -lethernet -lphy -lapp_trace -lconsole -lulp -lwpa_supplicant -lfreertos -lbt -lmicro-ecc -lcxx -lxtensa-debug-module -ltcp_transport -lmdns -lvfs -lesp_ringbuf -lsoc -lcore -lsdmmc -llibsodium -lcoap -ltcpip_adapter -lprotocomm -lesp_event -lc_nano -lesp-tls -lasio -lrtc -lspi_flash -lwpa2 -lwifi_provisioning -lesp32 -lapp_update -lnghttp -lspiffs -lunity -lesp_https_server -lespnow -lnvs_flash -lesp_adc_cal -llog -lsmartconfig_ack -lexpat -lm -lmqtt -lc -lheap -lmbedtls -llwip -lnet80211 -lesp_http_server -lpthread -ljson -lesp_https_ota -lstdc++
compiler.c.elf.libs=-lgcc -lopenssl -lbtdm_app -lfatfs -lwps -lcoexist -lwear_levelling -lesp_http_client -lprotobuf-c -lhal -lnewlib -ldriver -lbootloader_support -lpp -lfreemodbus -lmesh -lsmartconfig -ljsmn -lwpa -lethernet -lphy -lfrmn -lapp_trace -lfr_coefficients -lconsole -lulp -lwpa_supplicant -lfreertos -lbt -lmicro-ecc -lesp32-camera -lcxx -lxtensa-debug-module -ltcp_transport -lmdns -lvfs -lmtmn -lespcoredump -lesp_ringbuf -lsoc -lcore -lfb_gfx -lsdmmc -llibsodium -lcoap -ltcpip_adapter -lprotocomm -lesp_event -limage_util -lc_nano -lesp-tls -lasio -lrtc -lspi_flash -lwpa2 -lwifi_provisioning -lesp32 -lface_recognition -lapp_update -lnghttp -lspiffs -lface_detection -lefuse -lunity -lesp_https_server -lespnow -lnvs_flash -lesp_adc_cal -llog -ldl_lib -lsmartconfig_ack -lexpat -lfd_coefficients -lm -lmqtt -lc -lheap -lmbedtls -llwip -lnet80211 -lesp_http_server -lpthread -ljson -lesp_https_ota -lstdc++
compiler.as.cmd=xtensa-esp32-elf-as
@ -71,17 +71,17 @@ recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpreprocessor
recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" -DARDUINO_VARIANT="{build.variant}" {compiler.S.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"
## Create archives
recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{build.path}/arduino.ar" "{object_file}"
recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}"
## Combine gc-sections, archives, and objects
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} -Wl,--start-group {object_files} "{build.path}/arduino.ar" {compiler.c.elf.libs} -Wl,--end-group -Wl,-EL -o "{build.path}/{build.project_name}.elf"
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} -Wl,--start-group {object_files} "{archive_file_path}" {compiler.c.elf.libs} -Wl,--end-group -Wl,-EL -o "{build.path}/{build.project_name}.elf"
## Create eeprom
recipe.objcopy.eep.pattern={tools.gen_esp32part.cmd} -q "{runtime.platform.path}/tools/partitions/{build.partitions}.csv" "{build.path}/{build.project_name}.partitions.bin"
## Create hex
recipe.objcopy.hex.pattern="{tools.esptool.path}/{tools.esptool.cmd}" --chip esp32 elf2image --flash_mode "{build.flash_mode}" --flash_freq "{build.flash_freq}" --flash_size "{build.flash_size}" -o "{build.path}/{build.project_name}.bin" "{build.path}/{build.project_name}.elf"
recipe.objcopy.hex.pattern.linux=python "{tools.esptool.path}/{tools.esptool.cmd}" --chip esp32 elf2image --flash_mode "{build.flash_mode}" --flash_freq "{build.flash_freq}" --flash_size "{build.flash_size}" -o "{build.path}/{build.project_name}.bin" "{build.path}/{build.project_name}.elf"
recipe.objcopy.hex.pattern="{tools.esptool_py.path}/{tools.esptool_py.cmd}" --chip esp32 elf2image --flash_mode "{build.flash_mode}" --flash_freq "{build.flash_freq}" --flash_size "{build.flash_size}" -o "{build.path}/{build.project_name}.bin" "{build.path}/{build.project_name}.elf"
recipe.objcopy.hex.pattern.linux=python "{tools.esptool_py.path}/{tools.esptool_py.cmd}" --chip esp32 elf2image --flash_mode "{build.flash_mode}" --flash_freq "{build.flash_freq}" --flash_size "{build.flash_size}" -o "{build.path}/{build.project_name}.bin" "{build.path}/{build.project_name}.elf"
## Save hex
recipe.output.tmp_file={build.project_name}.bin
@ -94,9 +94,9 @@ recipe.size.regex.data=^(?:\.dram0\.data|\.dram0\.bss|\.noinit)\s+([0-9]+).*
# ------------------------------
tools.esptool.upload.protocol=esp32
tools.esptool.upload.params.verbose=
tools.esptool.upload.params.quiet=
tools.esptool.upload.pattern="{path}/{cmd}" --chip esp32 --port "{serial.port}" --baud {upload.speed} --before default_reset --after hard_reset write_flash -z --flash_mode {build.flash_mode} --flash_freq {build.flash_freq} --flash_size detect 0xe000 "{runtime.platform.path}/tools/partitions/boot_app0.bin" 0x1000 "{runtime.platform.path}/tools/sdk/bin/bootloader_{build.boot}_{build.flash_freq}.bin" 0x10000 "{build.path}/{build.project_name}.bin" 0x8000 "{build.path}/{build.project_name}.partitions.bin"
tools.esptool.upload.pattern.linux=python "{path}/{cmd}" --chip esp32 --port "{serial.port}" --baud {upload.speed} --before default_reset --after hard_reset write_flash -z --flash_mode {build.flash_mode} --flash_freq {build.flash_freq} --flash_size detect 0xe000 "{runtime.platform.path}/tools/partitions/boot_app0.bin" 0x1000 "{runtime.platform.path}/tools/sdk/bin/bootloader_{build.boot}_{build.flash_freq}.bin" 0x10000 "{build.path}/{build.project_name}.bin" 0x8000 "{build.path}/{build.project_name}.partitions.bin"
tools.esptool.upload.network_pattern={network_cmd} -i "{serial.port}" -p "{network.port}" "--auth={network.password}" -f "{build.path}/{build.project_name}.bin"
tools.esptool_py.upload.protocol=esp32
tools.esptool_py.upload.params.verbose=
tools.esptool_py.upload.params.quiet=
tools.esptool_py.upload.pattern="{path}/{cmd}" --chip esp32 --port "{serial.port}" --baud {upload.speed} --before default_reset --after hard_reset write_flash -z --flash_mode {build.flash_mode} --flash_freq {build.flash_freq} --flash_size detect 0xe000 "{runtime.platform.path}/tools/partitions/boot_app0.bin" 0x1000 "{runtime.platform.path}/tools/sdk/bin/bootloader_{build.boot}_{build.flash_freq}.bin" 0x10000 "{build.path}/{build.project_name}.bin" 0x8000 "{build.path}/{build.project_name}.partitions.bin"
tools.esptool_py.upload.pattern.linux=python "{path}/{cmd}" --chip esp32 --port "{serial.port}" --baud {upload.speed} --before default_reset --after hard_reset write_flash -z --flash_mode {build.flash_mode} --flash_freq {build.flash_freq} --flash_size detect 0xe000 "{runtime.platform.path}/tools/partitions/boot_app0.bin" 0x1000 "{runtime.platform.path}/tools/sdk/bin/bootloader_{build.boot}_{build.flash_freq}.bin" 0x10000 "{build.path}/{build.project_name}.bin" 0x8000 "{build.path}/{build.project_name}.partitions.bin"
tools.esptool_py.upload.network_pattern={network_cmd} -i "{serial.port}" -p "{network.port}" "--auth={network.password}" -f "{build.path}/{build.project_name}.bin"

View File

@ -231,7 +231,7 @@ echo " - updating platform.txt..."
cat $srcdir/platform.txt | \
sed "s/version=.*/version=$ver$extent/g" | \
sed 's/runtime.tools.xtensa-esp32-elf-gcc.path={runtime.platform.path}\/tools\/xtensa-esp32-elf//g' | \
sed 's/tools.esptool.path={runtime.platform.path}\/tools\/esptool/tools.esptool.path=\{runtime.tools.esptool.path\}/g' \
sed 's/tools.esptool_py.path={runtime.platform.path}\/tools\/esptool/tools.esptool_py.path=\{runtime.tools.esptool_py.path\}/g' \
> $outdir/platform.txt
# Put core version and short hash of git version into core_version.h
@ -338,7 +338,7 @@ if [ ! -z "$prev_any_release" ] && [ "$prev_any_release" != "null" ]; then
# Release notes: GIT log comments (prev_any_release, current_release>
echo " - executing: git log --oneline $prev_any_release.."
#git log --oneline $prev_any_release.. > $releaseDir/commits.txt
git log --oneline $prev_any_release.. > $releaseDir/commits.txt
fi
# for RELEASE run update REL JSON as well
@ -353,7 +353,7 @@ if [ $bIsPrerelease -eq 0 ]; then
# Release notes: GIT log comments (prev_release, current_release>
echo " - executing: git log --oneline $prev_release.."
#git log --oneline $prev_release.. > $releaseDir/commits.txt
git log --oneline $prev_release.. > $releaseDir/commits.txt
fi
fi

View File

@ -48,6 +48,7 @@ platformio ci --board esp32dev libraries/WiFi/examples/WiFiClient && \
platformio ci --board esp32dev libraries/WiFiClientSecure/examples/WiFiClientSecure && \
platformio ci --board esp32dev libraries/BluetoothSerial/examples/SerialToSerialBT && \
platformio ci --board esp32dev libraries/BLE/examples/BLE_server && \
platformio ci --board esp32dev libraries/AzureIoT/examples/GetStarted
platformio ci --board esp32dev libraries/AzureIoT/examples/GetStarted && \
platformio ci --board esp32dev libraries/ESP32/examples/Camera/CameraWebServer --project-option="board_build.partitions = huge_app.csv"
if [ $? -ne 0 ]; then exit 1; fi
echo -e "travis_fold:end:platformio_test"

View File

@ -46,6 +46,7 @@ def compile(tmp_dir, sketch, tools_dir, hardware_dir, ide_path, f, args):
# Debug=Serial,DebugLevel=Core____
cmd += '-fqbn=espressif:esp32:{board_name}:' \
'FlashFreq={flash_freq},' \
'PartitionScheme=huge_app,' \
'UploadSpeed=921600'.format(**vars(args))
cmd += ' '
cmd += '-ide-version=10607 '

View File

@ -205,7 +205,7 @@ def serve(remoteAddr, localAddr, remotePort, localPort, password, filename, comm
data = connection.recv(32).decode()
logging.info('Result: %s' ,data)
if data == "OK":
if "OK" in data:
logging.info('Success')
connection.close()
f.close()

View File

@ -32,9 +32,12 @@ import sys
import time
import zlib
import string
import serial.tools.list_ports as list_ports
import serial
try:
import serial
except ImportError:
print("Pyserial is not installed for %s. Check the README for installation instructions." % (sys.executable))
raise
# check 'serial' is 'pyserial' and not 'serial' https://github.com/espressif/esptool/issues/269
try:
@ -50,8 +53,14 @@ See https://github.com/espressif/esptool/issues/269#issuecomment-385298196 for d
except TypeError:
pass # __doc__ returns None for pyserial
try:
import serial.tools.list_ports as list_ports
except ImportError:
print("The installed version (%s) of pyserial appears to be too old for esptool.py (Python interpreter %s). "
"Check the README for installation instructions." % (sys.VERSION, sys.executable))
raise
__version__ = "2.6-beta1"
__version__ = "2.6"
MAX_UINT32 = 0xffffffff
MAX_UINT24 = 0xffffff
@ -221,7 +230,12 @@ class ESPLoader(object):
self._set_port_baudrate(baud)
self._trace_enabled = trace_enabled
# set write timeout, to prevent esptool blocked at write forever.
self._port.write_timeout = DEFAULT_SERIAL_WRITE_TIMEOUT
try:
self._port.write_timeout = DEFAULT_SERIAL_WRITE_TIMEOUT
except NotImplementedError:
# no write timeout for RFC2217 ports
# need to set the property back to None or it will continue to fail
self._port.write_timeout = None
def _set_port_baudrate(self, baud):
try:
@ -1274,19 +1288,26 @@ class ELFSection(ImageSegment):
class BaseFirmwareImage(object):
SEG_HEADER_LEN = 8
SHA256_DIGEST_LEN = 32
""" Base class with common firmware image functions """
def __init__(self):
self.segments = []
self.entrypoint = 0
self.elf_sha256 = None
self.elf_sha256_offset = 0
def load_common_header(self, load_file, expected_magic):
(magic, segments, self.flash_mode, self.flash_size_freq, self.entrypoint) = struct.unpack('<BBBBI', load_file.read(8))
if magic != expected_magic or segments > 16:
raise FatalError('Invalid firmware image magic=%d segments=%d' % (magic, segments))
if magic != expected_magic:
raise FatalError('Invalid firmware image magic=0x%x' % (magic))
return segments
def verify(self):
if len(self.segments) > 16:
raise FatalError('Invalid segment count %d (max 16). Usually this indicates a linker script problem.' % len(self.segments))
def load_segment(self, f, is_irom_segment=False):
""" Load the next segment from the image file """
file_offs = f.tell()
@ -1304,12 +1325,33 @@ class BaseFirmwareImage(object):
if offset > 0x40200000 or offset < 0x3ffe0000 or size > 65536:
print('WARNING: Suspicious segment 0x%x, length %d' % (offset, size))
def maybe_patch_segment_data(self, f, segment_data):
"""If SHA256 digest of the ELF file needs to be inserted into this segment, do so. Returns segment data."""
segment_len = len(segment_data)
file_pos = f.tell()
if self.elf_sha256_offset >= file_pos and self.elf_sha256_offset < file_pos + segment_len:
# SHA256 digest needs to be patched into this segment,
# calculate offset of the digest inside the segment.
patch_offset = self.elf_sha256_offset - file_pos
# Sanity checks
if patch_offset < self.SEG_HEADER_LEN or patch_offset + self.SHA256_DIGEST_LEN > segment_len:
raise FatalError('Can not place SHA256 digest on segment boundary' +
'(elf_sha256_offset=%d, file_pos=%d, segment_size=%d)' %
(self.elf_sha256_offset, file_pos, segment_len))
assert(len(self.elf_sha256) == self.SHA256_DIGEST_LEN)
# offset relative to the data part
patch_offset -= self.SEG_HEADER_LEN
segment_data = segment_data[0:patch_offset] + self.elf_sha256 + \
segment_data[patch_offset + self.SHA256_DIGEST_LEN:]
return segment_data
def save_segment(self, f, segment, checksum=None):
""" Save the next segment to the image file, return next checksum value if provided """
f.write(struct.pack('<II', segment.addr, len(segment.data)))
f.write(segment.data)
segment_data = self.maybe_patch_segment_data(f, segment.data)
f.write(struct.pack('<II', segment.addr, len(segment_data)))
f.write(segment_data)
if checksum is not None:
return ESPLoader.checksum(segment.data, checksum)
return ESPLoader.checksum(segment_data, checksum)
def read_checksum(self, f):
""" Return ESPLoader checksum from end of just-read image """
@ -1374,6 +1416,8 @@ class ESP8266ROMFirmwareImage(BaseFirmwareImage):
self.load_segment(load_file)
self.checksum = self.read_checksum(load_file)
self.verify()
def default_output_name(self, input_file):
""" Derive a default output name from the ELF name. """
return input_file + '-'
@ -1442,6 +1486,8 @@ class ESP8266V2FirmwareImage(BaseFirmwareImage):
self.load_segment(load_file)
self.checksum = self.read_checksum(load_file)
self.verify()
def default_output_name(self, input_file):
""" Derive a default output name from the ELF name. """
irom_segment = self.get_irom_segment()
@ -1514,6 +1560,8 @@ class ESP32FirmwareImage(BaseFirmwareImage):
EXTENDED_HEADER_STRUCT_FMT = "B" * 16
IROM_ALIGN = 65536
def __init__(self, load_file=None):
super(ESP32FirmwareImage, self).__init__()
self.secure_pad = False
@ -1549,6 +1597,8 @@ class ESP32FirmwareImage(BaseFirmwareImage):
calc_digest.update(load_file.read(end - start))
self.calc_digest = calc_digest.digest() # TODO: decide what to do here?
self.verify()
def is_flash_addr(self, addr):
return (ESP32ROM.IROM_MAP_START <= addr < ESP32ROM.IROM_MAP_END) \
or (ESP32ROM.DROM_MAP_START <= addr < ESP32ROM.DROM_MAP_END)
@ -1575,8 +1625,6 @@ class ESP32FirmwareImage(BaseFirmwareImage):
flash_segments = [copy.deepcopy(s) for s in sorted(self.segments, key=lambda s:s.addr) if self.is_flash_addr(s.addr)]
ram_segments = [copy.deepcopy(s) for s in sorted(self.segments, key=lambda s:s.addr) if not self.is_flash_addr(s.addr)]
IROM_ALIGN = 65536
# check for multiple ELF sections that are mapped in the same flash mapping region.
# this is usually a sign of a broken linker script, but if you have a legitimate
# use case then let us know (we can merge segments here, but as a rule you probably
@ -1584,7 +1632,7 @@ class ESP32FirmwareImage(BaseFirmwareImage):
if len(flash_segments) > 0:
last_addr = flash_segments[0].addr
for segment in flash_segments[1:]:
if segment.addr // IROM_ALIGN == last_addr // IROM_ALIGN:
if segment.addr // self.IROM_ALIGN == last_addr // self.IROM_ALIGN:
raise FatalError(("Segment loaded at 0x%08x lands in same 64KB flash mapping as segment loaded at 0x%08x. " +
"Can't generate binary. Suggest changing linker script or ELF to merge sections.") %
(segment.addr, last_addr))
@ -1596,15 +1644,15 @@ class ESP32FirmwareImage(BaseFirmwareImage):
#
# (this is because the segment's vaddr may not be IROM_ALIGNed, more likely is aligned
# IROM_ALIGN+0x18 to account for the binary file header
align_past = (segment.addr % IROM_ALIGN) - self.SEG_HEADER_LEN
pad_len = (IROM_ALIGN - (f.tell() % IROM_ALIGN)) + align_past
if pad_len == 0 or pad_len == IROM_ALIGN:
align_past = (segment.addr % self.IROM_ALIGN) - self.SEG_HEADER_LEN
pad_len = (self.IROM_ALIGN - (f.tell() % self.IROM_ALIGN)) + align_past
if pad_len == 0 or pad_len == self.IROM_ALIGN:
return 0 # already aligned
# subtract SEG_HEADER_LEN a second time, as the padding block has a header as well
pad_len -= self.SEG_HEADER_LEN
if pad_len < 0:
pad_len += IROM_ALIGN
pad_len += self.IROM_ALIGN
return pad_len
# try to fit each flash segment on a 64kB aligned boundary
@ -1623,8 +1671,8 @@ class ESP32FirmwareImage(BaseFirmwareImage):
total_segments += 1
else:
# write the flash segment
assert (f.tell() + 8) % IROM_ALIGN == segment.addr % IROM_ALIGN
checksum = self.save_segment(f, segment, checksum)
assert (f.tell() + 8) % self.IROM_ALIGN == segment.addr % self.IROM_ALIGN
checksum = self.save_flash_segment(f, segment, checksum)
flash_segments.pop(0)
total_segments += 1
@ -1638,12 +1686,12 @@ class ESP32FirmwareImage(BaseFirmwareImage):
# This ensures all mapped flash content will be verified.
if not self.append_digest:
raise FatalError("secure_pad only applies if a SHA-256 digest is also appended to the image")
align_past = (f.tell() + self.SEG_HEADER_LEN) % IROM_ALIGN
align_past = (f.tell() + self.SEG_HEADER_LEN) % self.IROM_ALIGN
# 16 byte aligned checksum (force the alignment to simplify calculations)
checksum_space = 16
# after checksum: SHA-256 digest + (to be added by signing process) version, signature + 12 trailing bytes due to alignment
space_after_checksum = 32 + 4 + 64 + 12
pad_len = (IROM_ALIGN - align_past - checksum_space - space_after_checksum) % IROM_ALIGN
pad_len = (self.IROM_ALIGN - align_past - checksum_space - space_after_checksum) % self.IROM_ALIGN
pad_segment = ImageSegment(0, b'\x00' * pad_len, f.tell())
checksum = self.save_segment(f, pad_segment, checksum)
@ -1654,7 +1702,7 @@ class ESP32FirmwareImage(BaseFirmwareImage):
image_length = f.tell()
if self.secure_pad:
assert ((image_length + space_after_checksum) % IROM_ALIGN) == 0
assert ((image_length + space_after_checksum) % self.IROM_ALIGN) == 0
# kinda hacky: go back to the initial header and write the new segment count
# that includes padding segments. This header is not checksummed
@ -1674,6 +1722,16 @@ class ESP32FirmwareImage(BaseFirmwareImage):
with open(filename, 'wb') as real_file:
real_file.write(f.getvalue())
def save_flash_segment(self, f, segment, checksum=None):
""" Save the next segment to the image file, return next checksum value if provided """
segment_end_pos = f.tell() + len(segment.data) + self.SEG_HEADER_LEN
segment_len_remainder = segment_end_pos % self.IROM_ALIGN
if segment_len_remainder < 0x24:
# Work around a bug in ESP-IDF 2nd stage bootloader, that it didn't map the
# last MMU page, if an IROM/DROM segment was < 0x24 bytes over the page boundary.
segment.data += b'\x00' * (0x24 - segment_len_remainder)
return self.save_segment(f, segment, checksum)
def load_extended_header(self, load_file):
def split_byte(n):
return (n & 0x0F, (n >> 4) & 0x0F)
@ -1790,9 +1848,16 @@ class ELFFile(object):
return f.read(size)
prog_sections = [ELFSection(lookup_string(n_offs), lma, read_data(offs, size)) for (n_offs, _type, lma, size, offs) in prog_sections
if lma != 0]
if lma != 0 and size > 0]
self.sections = prog_sections
def sha256(self):
# return SHA256 hash of the input ELF file
sha256 = hashlib.sha256()
with open(self.name, 'rb') as f:
sha256.update(f.read())
return sha256.digest()
def slip_reader(port, trace_function):
"""Generator to read SLIP packets from a serial port.
@ -1991,15 +2056,15 @@ def write_mem(esp, args):
def dump_mem(esp, args):
f = open(args.filename, 'wb')
for i in range(args.size // 4):
d = esp.read_reg(args.address + (i * 4))
f.write(struct.pack(b'<I', d))
if f.tell() % 1024 == 0:
print('\r%d bytes read... (%d %%)' % (f.tell(),
f.tell() * 100 // args.size),
end=' ')
sys.stdout.flush()
with open(args.filename, 'wb') as f:
for i in range(args.size // 4):
d = esp.read_reg(args.address + (i * 4))
f.write(struct.pack(b'<I', d))
if f.tell() % 1024 == 0:
print('\r%d bytes read... (%d %%)' % (f.tell(),
f.tell() * 100 // args.size),
end=' ')
sys.stdout.flush()
print('Done!')
@ -2060,6 +2125,9 @@ def write_flash(esp, args):
% (argfile.name, argfile.tell(), address, flash_end))
argfile.seek(0)
if args.erase_all:
erase_flash(esp, args)
for address, argfile in args.addr_filename:
if args.no_stub:
print('Erasing flash...')
@ -2087,7 +2155,7 @@ def write_flash(esp, args):
sys.stdout.flush()
block = image[0:esp.FLASH_WRITE_SIZE]
if args.compress:
esp.flash_defl_block(block, seq, timeout=DEFAULT_TIMEOUT * ratio)
esp.flash_defl_block(block, seq, timeout=DEFAULT_TIMEOUT * ratio * 2)
else:
# Pad the last block
block = block + b'\xff' * (esp.FLASH_WRITE_SIZE - len(block))
@ -2165,8 +2233,9 @@ def make_image(args):
if len(args.segfile) != len(args.segaddr):
raise FatalError('Number of specified files does not match number of specified addresses')
for (seg, addr) in zip(args.segfile, args.segaddr):
data = open(seg, 'rb').read()
image.segments.append(ImageSegment(addr, data))
with open(seg, 'rb') as f:
data = f.read()
image.segments.append(ImageSegment(addr, data))
image.entrypoint = args.entrypoint
image.save(args.output)
@ -2190,6 +2259,12 @@ def elf2image(args):
image.flash_size_freq = image.ROM_LOADER.FLASH_SIZES[args.flash_size]
image.flash_size_freq += {'40m':0, '26m':1, '20m':2, '80m': 0xf}[args.flash_freq]
if args.elf_sha256_offset:
image.elf_sha256 = e.sha256()
image.elf_sha256_offset = args.elf_sha256_offset
image.verify()
if args.output is None:
args.output = image.default_output_name(args.input)
image.save(args.output)
@ -2254,7 +2329,8 @@ def read_flash(esp, args):
t = time.time() - t
print('\rRead %d bytes at 0x%x in %.1f seconds (%.1f kbit/s)...'
% (len(data), args.address, t, len(data) / t * 8 / 1000))
open(args.filename, 'wb').write(data)
with open(args.filename, 'wb') as f:
f.write(data)
def verify_flash(esp, args):
@ -2316,7 +2392,13 @@ def version(args):
#
def main():
def main(custom_commandline=None):
"""
Main function for esptool
custom_commandline - Optional override for default arguments parsing (that uses sys.argv), can be a list of custom arguments
as strings.
"""
parser = argparse.ArgumentParser(description='esptool.py v%s - ESP8266 ROM Bootloader Utility' % __version__, prog='esptool')
parser.add_argument('--chip', '-c',
@ -2413,15 +2495,18 @@ def main():
default=os.environ.get('ESPTOOL_FS', 'detect' if auto_detect else '1MB'))
add_spi_connection_arg(parent)
parser_write_flash = subparsers.add_parser(
'write_flash',
help='Write a binary blob to flash')
parser_write_flash = subparsers.add_parser('write_flash', help='Write a binary blob to flash')
parser_write_flash.add_argument('addr_filename', metavar='<address> <filename>', help='Address followed by binary filename, separated by space',
action=AddrFilenamePairAction)
parser_write_flash.add_argument('--erase-all', '-e',
help='Erase all regions of flash (not just write areas) before programming',
action="store_true")
add_spi_flash_subparsers(parser_write_flash, is_elf2image=False)
parser_write_flash.add_argument('--no-progress', '-p', help='Suppress progress output', action="store_true")
parser_write_flash.add_argument('--verify', help='Verify just-written data on flash ' +
'(mostly superfluous, data is read back during flashing)', action='store_true')
compress_args = parser_write_flash.add_mutually_exclusive_group(required=False)
compress_args.add_argument('--compress', '-z', help='Compress data in transfer (default unless --no-stub is specified)',action="store_true", default=None)
compress_args.add_argument('--no-compress', '-u', help='Disable data compression during transfer (default if --no-stub is specified)',action="store_true")
@ -2450,6 +2535,8 @@ def main():
parser_elf2image.add_argument('--output', '-o', help='Output filename prefix (for version 1 image), or filename (for version 2 single image)', type=str)
parser_elf2image.add_argument('--version', '-e', help='Output image version', choices=['1','2'], default='1')
parser_elf2image.add_argument('--secure-pad', action='store_true', help='Pad image so once signed it will end on a 64KB boundary. For ESP32 images only.')
parser_elf2image.add_argument('--elf-sha256-offset', help='If set, insert SHA256 hash (32 bytes) of the input ELF file at specified offset in the binary.',
type=arg_auto_int, default=None)
add_spi_flash_subparsers(parser_elf2image, is_elf2image=True)
@ -2521,7 +2608,7 @@ def main():
expand_file_arguments()
args = parser.parse_args()
args = parser.parse_args(custom_commandline)
print('esptool.py v%s' % __version__)
@ -2607,7 +2694,14 @@ def main():
detect_flash_size(esp, args)
esp.flash_set_parameters(flash_size_bytes(args.flash_size))
operation_func(esp, args)
try:
operation_func(esp, args)
finally:
try: # Clean up AddrFilenamePairAction files
for address, argfile in args.addr_filename:
argfile.close()
except AttributeError:
pass
# Handle post-operation behaviour (reset or other)
if operation_func == load_ram:
@ -2752,73 +2846,73 @@ class AddrFilenamePairAction(argparse.Action):
# Binary stub code (see flasher_stub dir for source & details)
ESP8266ROM.STUB_CODE = eval(zlib.decompress(base64.b64decode(b"""
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\
nORxF3HqX/8XohBRvg==\
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\
""")))
ESP32ROM.STUB_CODE = eval(zlib.decompress(base64.b64decode(b"""
eNqNWnt31LgV/yqOYfJaskeyPbZEz0IS6BBg2xIoIdDp2bFlOyFbcoDOQjgL/ezVfVnyzNDtHxNkPa/u43cf4vedZXez3LmbNDvzm94k/k9xH1oKW+XR/Eb5ptX+s/W/fn7jVEKdxsyX/i+01O2zExrFmfX/M1PD\

Binary file not shown.

View File

@ -29,36 +29,41 @@ import struct
import sys
import hashlib
import binascii
import errno
MAX_PARTITION_LENGTH = 0xC00 # 3K for partition data (96 entries) leaves 1K in a 4K sector for signature
MD5_PARTITION_BEGIN = b"\xEB\xEB" + b"\xFF" * 14 # The first 2 bytes are like magic numbers for MD5 sum
MD5_PARTITION_BEGIN = b"\xEB\xEB" + b"\xFF" * 14 # The first 2 bytes are like magic numbers for MD5 sum
PARTITION_TABLE_SIZE = 0x1000 # Size of partition table
MIN_PARTITION_SUBTYPE_APP_OTA = 0x10
NUM_PARTITION_SUBTYPE_APP_OTA = 16
__version__ = '1.2'
APP_TYPE = 0x00
DATA_TYPE = 0x01
TYPES = {
"app" : APP_TYPE,
"data" : DATA_TYPE,
"app": APP_TYPE,
"data": DATA_TYPE,
}
# Keep this map in sync with esp_partition_subtype_t enum in esp_partition.h
SUBTYPES = {
APP_TYPE : {
"factory" : 0x00,
"test" : 0x20,
APP_TYPE: {
"factory": 0x00,
"test": 0x20,
},
DATA_TYPE : {
"ota" : 0x00,
"phy" : 0x01,
"nvs" : 0x02,
"coredump" : 0x03,
"nvs_keys" : 0x04,
"esphttpd" : 0x80,
"fat" : 0x81,
"spiffs" : 0x82,
DATA_TYPE: {
"ota": 0x00,
"phy": 0x01,
"nvs": 0x02,
"coredump": 0x03,
"nvs_keys": 0x04,
"efuse": 0x05,
"esphttpd": 0x80,
"fat": 0x81,
"spiffs": 0x82,
},
}
@ -67,16 +72,19 @@ md5sum = True
secure = False
offset_part_table = 0
def status(msg):
""" Print status message to stderr """
if not quiet:
critical(msg)
def critical(msg):
""" Print critical message to stderr """
sys.stderr.write(msg)
sys.stderr.write('\n')
class PartitionTable(list):
def __init__(self):
super(PartitionTable, self).__init__(self)
@ -98,15 +106,15 @@ class PartitionTable(list):
if line.startswith("#") or len(line) == 0:
continue
try:
res.append(PartitionDefinition.from_csv(line, line_no+1))
res.append(PartitionDefinition.from_csv(line, line_no + 1))
except InputError as e:
raise InputError("Error at line %d: %s" % (line_no+1, e))
raise InputError("Error at line %d: %s" % (line_no + 1, e))
except Exception:
critical("Unexpected error parsing CSV line %d: %s" % (line_no+1, line))
critical("Unexpected error parsing CSV line %d: %s" % (line_no + 1, line))
raise
# fix up missing offsets & negative sizes
last_end = offset_part_table + PARTITION_TABLE_SIZE # first offset after partition table
last_end = offset_part_table + PARTITION_TABLE_SIZE # first offset after partition table
for e in res:
if e.offset is not None and e.offset < last_end:
if e == res[0]:
@ -145,14 +153,14 @@ class PartitionTable(list):
ptype = TYPES[ptype]
except KeyError:
try:
ptypes = int(ptype, 0)
ptype = int(ptype, 0)
except TypeError:
pass
try:
subtype = SUBTYPES[int(ptype)][subtype]
except KeyError:
try:
ptypes = int(ptype, 0)
ptype = int(ptype, 0)
except TypeError:
pass
@ -171,11 +179,11 @@ class PartitionTable(list):
# verify each partition individually
for p in self:
p.verify()
# check on duplicate name
names = [ p.name for p in self ]
duplicates = set( n for n in names if names.count(n) > 1 )
names = [p.name for p in self]
duplicates = set(n for n in names if names.count(n) > 1)
# print sorted duplicate partitions by name
if len(duplicates) != 0:
print("A list of partitions that have the same name:")
@ -183,14 +191,14 @@ class PartitionTable(list):
if len(duplicates.intersection([p.name])) != 0:
print("%s" % (p.to_csv()))
raise InputError("Partition names must be unique")
# check for overlaps
last = None
for p in sorted(self, key=lambda x:x.offset):
if p.offset < offset_part_table + PARTITION_TABLE_SIZE:
raise InputError("Partition offset 0x%x is below 0x%x" % (p.offset, offset_part_table + PARTITION_TABLE_SIZE))
if last is not None and p.offset < last.offset + last.size:
raise InputError("Partition at 0x%x overlaps 0x%x-0x%x" % (p.offset, last.offset, last.offset+last.size-1))
raise InputError("Partition at 0x%x overlaps 0x%x-0x%x" % (p.offset, last.offset, last.offset + last.size - 1))
last = p
def flash_size(self):
@ -205,17 +213,17 @@ class PartitionTable(list):
@classmethod
def from_binary(cls, b):
md5 = hashlib.md5();
md5 = hashlib.md5()
result = cls()
for o in range(0,len(b),32):
data = b[o:o+32]
data = b[o:o + 32]
if len(data) != 32:
raise InputError("Partition table length must be a multiple of 32 bytes")
if data == b'\xFF'*32:
if data == b'\xFF' * 32:
return result # got end marker
if md5sum and data[:2] == MD5_PARTITION_BEGIN[:2]: #check only the magic number part
if md5sum and data[:2] == MD5_PARTITION_BEGIN[:2]: # check only the magic number part
if data[16:] == md5.digest():
continue # the next iteration will check for the end marker
continue # the next iteration will check for the end marker
else:
raise InputError("MD5 checksums don't match! (computed: 0x%s, parsed: 0x%s)" % (md5.hexdigest(), binascii.hexlify(data[16:])))
else:
@ -227,34 +235,35 @@ class PartitionTable(list):
result = b"".join(e.to_binary() for e in self)
if md5sum:
result += MD5_PARTITION_BEGIN + hashlib.md5(result).digest()
if len(result )>= MAX_PARTITION_LENGTH:
if len(result) >= MAX_PARTITION_LENGTH:
raise InputError("Binary partition table length (%d) longer than max" % len(result))
result += b"\xFF" * (MAX_PARTITION_LENGTH - len(result)) # pad the sector, for signing
return result
def to_csv(self, simple_formatting=False):
rows = [ "# Espressif ESP32 Partition Table",
"# Name, Type, SubType, Offset, Size, Flags" ]
rows += [ x.to_csv(simple_formatting) for x in self ]
rows = ["# Espressif ESP32 Partition Table",
"# Name, Type, SubType, Offset, Size, Flags"]
rows += [x.to_csv(simple_formatting) for x in self]
return "\n".join(rows) + "\n"
class PartitionDefinition(object):
MAGIC_BYTES = b"\xAA\x50"
ALIGNMENT = {
APP_TYPE : 0x10000,
DATA_TYPE : 0x04,
APP_TYPE: 0x10000,
DATA_TYPE: 0x04,
}
# dictionary maps flag name (as used in CSV flags list, property name)
# to bit set in flags words in binary format
FLAGS = {
"encrypted" : 0
"encrypted": 0
}
# add subtypes for the 16 OTA slot values ("ota_XX, etc.")
for ota_slot in range(16):
SUBTYPES[TYPES["app"]]["ota_%d" % ota_slot] = 0x10 + ota_slot
for ota_slot in range(NUM_PARTITION_SUBTYPE_APP_OTA):
SUBTYPES[TYPES["app"]]["ota_%d" % ota_slot] = MIN_PARTITION_SUBTYPE_APP_OTA + ota_slot
def __init__(self):
self.name = ""
@ -268,7 +277,7 @@ class PartitionDefinition(object):
def from_csv(cls, line, line_no):
""" Parse a line from the CSV """
line_w_defaults = line + ",,,," # lazy way to support default fields
fields = [ f.strip() for f in line_w_defaults.split(",") ]
fields = [f.strip() for f in line_w_defaults.split(",")]
res = PartitionDefinition()
res.line_no = line_no
@ -298,7 +307,7 @@ class PartitionDefinition(object):
def maybe_hex(x):
return "0x%x" % x if x is not None else "None"
return "PartitionDefinition('%s', 0x%x, 0x%x, %s, %s)" % (self.name, self.type, self.subtype or 0,
maybe_hex(self.offset), maybe_hex(self.size))
maybe_hex(self.offset), maybe_hex(self.size))
def __str__(self):
return "Part '%s' %d/%d @ 0x%x size 0x%x" % (self.name, self.type, self.subtype, self.offset or -1, self.size or -1)
@ -325,7 +334,7 @@ class PartitionDefinition(object):
def parse_subtype(self, strval):
if strval == "":
return 0 # default
return 0 # default
return parse_int(strval, SUBTYPES.get(self.type, {}))
def parse_address(self, strval):
@ -349,12 +358,14 @@ class PartitionDefinition(object):
raise ValidationError(self, "Size field is not set")
if self.name in TYPES and TYPES.get(self.name, "") != self.type:
critical("WARNING: Partition has name '%s' which is a partition type, but does not match this partition's type (0x%x). Mistake in partition table?" % (self.name, self.type))
critical("WARNING: Partition has name '%s' which is a partition type, but does not match this partition's "
"type (0x%x). Mistake in partition table?" % (self.name, self.type))
all_subtype_names = []
for names in (t.keys() for t in SUBTYPES.values()):
all_subtype_names += names
if self.name in all_subtype_names and SUBTYPES.get(self.type, {}).get(self.name, "") != self.subtype:
critical("WARNING: Partition has name '%s' which is a partition subtype, but this partition has non-matching type 0x%x and subtype 0x%x. Mistake in partition table?" % (self.name, self.type, self.subtype))
critical("WARNING: Partition has name '%s' which is a partition subtype, but this partition has "
"non-matching type 0x%x and subtype 0x%x. Mistake in partition table?" % (self.name, self.type, self.subtype))
STRUCT_FORMAT = b"<2sBBLL16sL"
@ -365,21 +376,21 @@ class PartitionDefinition(object):
res = cls()
(magic, res.type, res.subtype, res.offset,
res.size, res.name, flags) = struct.unpack(cls.STRUCT_FORMAT, b)
if b"\x00" in res.name: # strip null byte padding from name string
if b"\x00" in res.name: # strip null byte padding from name string
res.name = res.name[:res.name.index(b"\x00")]
res.name = res.name.decode()
if magic != cls.MAGIC_BYTES:
raise InputError("Invalid magic bytes (%r) for partition definition" % magic)
for flag,bit in cls.FLAGS.items():
if flags & (1<<bit):
if flags & (1 << bit):
setattr(res, flag, True)
flags &= ~(1<<bit)
flags &= ~(1 << bit)
if flags != 0:
critical("WARNING: Partition definition had unknown flag(s) 0x%08x. Newer binary format?" % flags)
return res
def get_flags_list(self):
return [ flag for flag in self.FLAGS.keys() if getattr(self, flag) ]
return [flag for flag in self.FLAGS.keys() if getattr(self, flag)]
def to_binary(self):
flags = sum((1 << self.FLAGS[flag]) for flag in self.get_flags_list())
@ -393,14 +404,14 @@ class PartitionDefinition(object):
def to_csv(self, simple_formatting=False):
def addr_format(a, include_sizes):
if not simple_formatting and include_sizes:
for (val, suffix) in [ (0x100000, "M"), (0x400, "K") ]:
for (val, suffix) in [(0x100000, "M"), (0x400, "K")]:
if a % val == 0:
return "%d%s" % (a // val, suffix)
return "0x%x" % a
def lookup_keyword(t, keywords):
for k,v in keywords.items():
if simple_formatting == False and t == v:
if simple_formatting is False and t == v:
return k
return "%d" % t
@ -408,12 +419,12 @@ class PartitionDefinition(object):
""" colon-delimited list of flags """
return ":".join(self.get_flags_list())
return ",".join([ self.name,
lookup_keyword(self.type, TYPES),
lookup_keyword(self.subtype, SUBTYPES.get(self.type, {})),
addr_format(self.offset, False),
addr_format(self.size, True),
generate_text_flags()])
return ",".join([self.name,
lookup_keyword(self.type, TYPES),
lookup_keyword(self.subtype, SUBTYPES.get(self.type, {})),
addr_format(self.offset, False),
addr_format(self.size, True),
generate_text_flags()])
def parse_int(v, keywords={}):
@ -421,7 +432,7 @@ def parse_int(v, keywords={}):
k/m/K/M suffixes and 'keyword' value lookup.
"""
try:
for letter, multiplier in [ ("k",1024), ("m",1024*1024) ]:
for letter, multiplier in [("k", 1024), ("m", 1024 * 1024)]:
if v.lower().endswith(letter):
return parse_int(v[:-1], keywords) * multiplier
return int(v, 0)
@ -433,6 +444,7 @@ def parse_int(v, keywords={}):
except KeyError:
raise InputError("Value '%s' is not valid. Known keywords: %s" % (v, ", ".join(keywords)))
def main():
global quiet
global md5sum
@ -441,10 +453,11 @@ def main():
parser = argparse.ArgumentParser(description='ESP32 partition table utility')
parser.add_argument('--flash-size', help='Optional flash size limit, checks partition table fits in flash',
nargs='?', choices=[ '1MB', '2MB', '4MB', '8MB', '16MB' ])
nargs='?', choices=['1MB', '2MB', '4MB', '8MB', '16MB'])
parser.add_argument('--disable-md5sum', help='Disable md5 checksum for the partition table', default=False, action='store_true')
parser.add_argument('--no-verify', help="Don't verify partition table fields", action='store_true')
parser.add_argument('--verify', '-v', help="Verify partition table fields (deprecated, this behaviour is enabled by default and this flag does nothing.", action='store_true')
parser.add_argument('--verify', '-v', help="Verify partition table fields (deprecated, this behaviour is "
"enabled by default and this flag does nothing.", action='store_true')
parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true')
parser.add_argument('--offset', '-o', help='Set offset partition table', default='0x8000')
parser.add_argument('--secure', help="Require app partitions to be suitable for secure boot", action='store_true')
@ -477,9 +490,20 @@ def main():
size = size_mb * 1024 * 1024 # flash memory uses honest megabytes!
table_size = table.flash_size()
if size < table_size:
raise InputError("Partitions defined in '%s' occupy %.1fMB of flash (%d bytes) which does not fit in configured flash size %dMB. Change the flash size in menuconfig under the 'Serial Flasher Config' menu." %
raise InputError("Partitions defined in '%s' occupy %.1fMB of flash (%d bytes) which does not fit in configured "
"flash size %dMB. Change the flash size in menuconfig under the 'Serial Flasher Config' menu." %
(args.input.name, table_size / 1024.0 / 1024.0, table_size, size_mb))
# Make sure that the output directory is created
output_dir = os.path.abspath(os.path.dirname(args.output))
if not os.path.exists(output_dir):
try:
os.makedirs(output_dir)
except OSError as exc:
if exc.errno != errno.EEXIST:
raise
if input_is_binary:
output = table.to_csv()
with sys.stdout if args.output == '-' else open(args.output, 'w') as f:

View File

@ -0,0 +1,7 @@
# 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,
eeprom, data, 0x99, 0x670000,0x1000,
spiffs, data, spiffs, 0x671000,0x18F000,
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 0x330000
5 app1 app ota_1 0x340000 0x330000
6 eeprom data 0x99 0x670000 0x1000
7 spiffs data spiffs 0x671000 0x18F000

View File

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x300000,
eeprom, data, 0x99, 0x310000,0x1000,
spiffs, data, spiffs, 0x311000,0xEF000,
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 0x300000
5 eeprom data 0x99 0x310000 0x1000
6 spiffs data spiffs 0x311000 0xEF000

View File

@ -44,6 +44,7 @@ env.Append(
CCFLAGS=[
"-Os",
"-g3",
"-Wall",
"-nostdlib",
"-Wpointer-arith",
@ -105,6 +106,7 @@ env.Append(
join(FRAMEWORK_DIR, "tools", "sdk", "include", "coap"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "console"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "driver"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "efuse"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "esp-tls"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "esp32"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "esp_adc_cal"),
@ -114,6 +116,7 @@ env.Append(
join(FRAMEWORK_DIR, "tools", "sdk", "include", "esp_https_ota"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "esp_https_server"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "esp_ringbuf"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "espcoredump"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "ethernet"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "expat"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "fatfs"),
@ -151,6 +154,9 @@ env.Append(
join(FRAMEWORK_DIR, "tools", "sdk", "include", "wifi_provisioning"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "wpa_supplicant"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "xtensa-debug-module"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "esp32-camera"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "esp-face"),
join(FRAMEWORK_DIR, "tools", "sdk", "include", "fb_gfx"),
join(FRAMEWORK_DIR, "cores", env.BoardConfig().get("build.core"))
],
@ -160,7 +166,7 @@ env.Append(
],
LIBS=[
"-lgcc", "-lopenssl", "-lbtdm_app", "-lfatfs", "-lwps", "-lcoexist", "-lwear_levelling", "-lesp_http_client", "-lprotobuf-c", "-lhal", "-lnewlib", "-ldriver", "-lbootloader_support", "-lpp", "-lfreemodbus", "-lmesh", "-lsmartconfig", "-ljsmn", "-lwpa", "-lethernet", "-lphy", "-lapp_trace", "-lconsole", "-lulp", "-lwpa_supplicant", "-lfreertos", "-lbt", "-lmicro-ecc", "-lcxx", "-lxtensa-debug-module", "-ltcp_transport", "-lmdns", "-lvfs", "-lesp_ringbuf", "-lsoc", "-lcore", "-lsdmmc", "-llibsodium", "-lcoap", "-ltcpip_adapter", "-lprotocomm", "-lesp_event", "-lc_nano", "-lesp-tls", "-lasio", "-lrtc", "-lspi_flash", "-lwpa2", "-lwifi_provisioning", "-lesp32", "-lapp_update", "-lnghttp", "-lspiffs", "-lunity", "-lesp_https_server", "-lespnow", "-lnvs_flash", "-lesp_adc_cal", "-llog", "-lsmartconfig_ack", "-lexpat", "-lm", "-lmqtt", "-lc", "-lheap", "-lmbedtls", "-llwip", "-lnet80211", "-lesp_http_server", "-lpthread", "-ljson", "-lesp_https_ota", "-lstdc++"
"-lgcc", "-lopenssl", "-lbtdm_app", "-lfatfs", "-lwps", "-lcoexist", "-lwear_levelling", "-lesp_http_client", "-lprotobuf-c", "-lhal", "-lnewlib", "-ldriver", "-lbootloader_support", "-lpp", "-lfreemodbus", "-lmesh", "-lsmartconfig", "-ljsmn", "-lwpa", "-lethernet", "-lphy", "-lfrmn", "-lapp_trace", "-lfr_coefficients", "-lconsole", "-lulp", "-lwpa_supplicant", "-lfreertos", "-lbt", "-lmicro-ecc", "-lesp32-camera", "-lcxx", "-lxtensa-debug-module", "-ltcp_transport", "-lmdns", "-lvfs", "-lmtmn", "-lespcoredump", "-lesp_ringbuf", "-lsoc", "-lcore", "-lfb_gfx", "-lsdmmc", "-llibsodium", "-lcoap", "-ltcpip_adapter", "-lprotocomm", "-lesp_event", "-limage_util", "-lc_nano", "-lesp-tls", "-lasio", "-lrtc", "-lspi_flash", "-lwpa2", "-lwifi_provisioning", "-lesp32", "-lface_recognition", "-lapp_update", "-lnghttp", "-lspiffs", "-lface_detection", "-lefuse", "-lunity", "-lesp_https_server", "-lespnow", "-lnvs_flash", "-lesp_adc_cal", "-llog", "-ldl_lib", "-lsmartconfig_ack", "-lexpat", "-lfd_coefficients", "-lm", "-lmqtt", "-lc", "-lheap", "-lmbedtls", "-llwip", "-lnet80211", "-lesp_http_server", "-lpthread", "-ljson", "-lesp_https_ota", "-lstdc++"
],
LIBSOURCE_DIRS=[

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -51,7 +51,7 @@ void esp_apptrace_down_buffer_config(uint8_t *buf, uint32_t size);
*
* @param dest Indicates HW interface to send data.
* @param size Size of data to write to trace buffer.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
*
* @return non-NULL on success, otherwise NULL.
*/
@ -63,7 +63,7 @@ uint8_t *esp_apptrace_buffer_get(esp_apptrace_dest_t dest, uint32_t size, uint32
*
* @param dest Indicates HW interface to send data. Should be identical to the same parameter in call to esp_apptrace_buffer_get.
* @param ptr Address of trace buffer to release. Should be the value returned by call to esp_apptrace_buffer_get.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
*
* @return ESP_OK on success, otherwise see esp_err_t
*/
@ -75,7 +75,7 @@ esp_err_t esp_apptrace_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32
* @param dest Indicates HW interface to send data.
* @param data Address of data to write to trace buffer.
* @param size Size of data to write to trace buffer.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
*
* @return ESP_OK on success, otherwise see esp_err_t
*/
@ -85,7 +85,7 @@ esp_err_t esp_apptrace_write(esp_apptrace_dest_t dest, const void *data, uint32_
* @brief vprintf-like function to sent log messages to host via specified HW interface.
*
* @param dest Indicates HW interface to send data.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
* @param fmt Address of format string.
* @param ap List of arguments.
*
@ -107,7 +107,7 @@ int esp_apptrace_vprintf(const char *fmt, va_list ap);
* @brief Flushes remaining data in trace buffer to host.
*
* @param dest Indicates HW interface to flush data on.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
*
* @return ESP_OK on success, otherwise see esp_err_t
*/
@ -119,7 +119,7 @@ esp_err_t esp_apptrace_flush(esp_apptrace_dest_t dest, uint32_t tmo);
*
* @param dest Indicates HW interface to flush data on.
* @param min_sz Threshold for flushing data. If current filling level is above this value, data will be flushed. TRAX destinations only.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
*
* @return ESP_OK on success, otherwise see esp_err_t
*/
@ -131,31 +131,31 @@ esp_err_t esp_apptrace_flush_nolock(esp_apptrace_dest_t dest, uint32_t min_sz, u
* @param dest Indicates HW interface to read the data on.
* @param data Address of buffer to put data from trace buffer.
* @param size Pointer to store size of read data. Before call to this function pointed memory must hold requested size of data
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
*
* @return ESP_OK on success, otherwise see esp_err_t
*/
esp_err_t esp_apptrace_read(esp_apptrace_dest_t dest, void *data, uint32_t *size, uint32_t tmo);
/**
* @brief Rertrieves incoming data buffer if any.
* @brief Retrieves incoming data buffer if any.
* After data in buffer are processed esp_apptrace_down_buffer_put must be called to indicate it.
*
* @param dest Indicates HW interface to receive data.
* @param size Address to store size of available data in down buffer. Must be initializaed with requested value.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
* @param size Address to store size of available data in down buffer. Must be initialized with requested value.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
*
* @return non-NULL on success, otherwise NULL.
*/
uint8_t *esp_apptrace_down_buffer_get(esp_apptrace_dest_t dest, uint32_t *size, uint32_t tmo);
/**
* @brief Indicates that the data in down buffer are processesd.
* @brief Indicates that the data in down buffer are processed.
* This function is a counterpart of and must be preceeded by esp_apptrace_down_buffer_get.
*
* @param dest Indicates HW interface to receive data. Should be identical to the same parameter in call to esp_apptrace_down_buffer_get.
* @param ptr Address of trace buffer to release. Should be the value returned by call to esp_apptrace_down_buffer_get.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
*
* @return ESP_OK on success, otherwise see esp_err_t
*/
@ -247,7 +247,7 @@ int esp_apptrace_ftell(esp_apptrace_dest_t dest, void *stream);
/**
* @brief Indicates to the host that all file operations are completed.
* This function should be called after all file operations are finished and
* This function should be called after all file operations are finished and
* indicate to the host that it can perform cleanup operations (close open files etc.).
*
* @param dest Indicates HW interface to use.

View File

@ -20,6 +20,8 @@
#include <stddef.h>
#include "esp_err.h"
#include "esp_partition.h"
#include "esp_image_format.h"
#include "esp_flash_data_types.h"
#ifdef __cplusplus
extern "C"
@ -32,6 +34,10 @@ extern "C"
#define ESP_ERR_OTA_PARTITION_CONFLICT (ESP_ERR_OTA_BASE + 0x01) /*!< Error if request was to write or erase the current running partition */
#define ESP_ERR_OTA_SELECT_INFO_INVALID (ESP_ERR_OTA_BASE + 0x02) /*!< Error if OTA data partition contains invalid content */
#define ESP_ERR_OTA_VALIDATE_FAILED (ESP_ERR_OTA_BASE + 0x03) /*!< Error if OTA app image is invalid */
#define ESP_ERR_OTA_SMALL_SEC_VER (ESP_ERR_OTA_BASE + 0x04) /*!< Error if the firmware has a secure version less than the running firmware. */
#define ESP_ERR_OTA_ROLLBACK_FAILED (ESP_ERR_OTA_BASE + 0x05) /*!< Error if flash does not have valid firmware in passive partition and hence rollback is not possible */
#define ESP_ERR_OTA_ROLLBACK_INVALID_STATE (ESP_ERR_OTA_BASE + 0x06) /*!< Error if current active firmware is still marked in pending validation state (ESP_OTA_IMG_PENDING_VERIFY), essentially first boot of firmware image post upgrade and hence firmware upgrade is not possible */
/**
* @brief Opaque handle for an application OTA update
@ -41,6 +47,24 @@ extern "C"
*/
typedef uint32_t esp_ota_handle_t;
/**
* @brief Return esp_app_desc structure. This structure includes app version.
*
* Return description for running app.
* @return Pointer to esp_app_desc structure.
*/
const esp_app_desc_t *esp_ota_get_app_description(void);
/**
* @brief Fill the provided buffer with SHA256 of the ELF file, formatted as hexadecimal, null-terminated.
* If the buffer size is not sufficient to fit the entire SHA256 in hex plus a null terminator,
* the largest possible number of bytes will be written followed by a null.
* @param dst Destination buffer
* @param size Size of the buffer
* @return Number of bytes written to dst (including null terminator)
*/
int esp_ota_get_app_elf_sha256(char* dst, size_t size);
/**
* @brief Commence an OTA update writing to the specified partition.
@ -52,6 +76,10 @@ typedef uint32_t esp_ota_handle_t;
* On success, this function allocates memory that remains in use
* until esp_ota_end() is called with the returned handle.
*
* Note: If the rollback option is enabled and the running application has the ESP_OTA_IMG_PENDING_VERIFY state then
* it will lead to the ESP_ERR_OTA_ROLLBACK_INVALID_STATE error. Confirm the running app before to run download a new app,
* use esp_ota_mark_app_valid_cancel_rollback() function for it (this should be done as early as possible when you first download a new application).
*
* @param partition Pointer to info for partition which will receive the OTA update. Required.
* @param image_size Size of new OTA app image. Partition will be erased in order to receive this size of image. If 0 or OTA_SIZE_UNKNOWN, the entire partition is erased.
* @param out_handle On success, returns a handle which should be used for subsequent esp_ota_write() and esp_ota_end() calls.
@ -65,6 +93,7 @@ typedef uint32_t esp_ota_handle_t;
* - ESP_ERR_OTA_SELECT_INFO_INVALID: The OTA data partition contains invalid data.
* - ESP_ERR_INVALID_SIZE: Partition doesn't fit in configured flash size.
* - ESP_ERR_FLASH_OP_TIMEOUT or ESP_ERR_FLASH_OP_FAIL: Flash write failed.
* - ESP_ERR_OTA_ROLLBACK_INVALID_STATE: If the running app has not confirmed state. Before performing an update, the application must be valid.
*/
esp_err_t esp_ota_begin(const esp_partition_t* partition, size_t image_size, esp_ota_handle_t* out_handle);
@ -170,6 +199,83 @@ const esp_partition_t* esp_ota_get_running_partition(void);
*/
const esp_partition_t* esp_ota_get_next_update_partition(const esp_partition_t *start_from);
/**
* @brief Returns esp_app_desc structure for app partition. This structure includes app version.
*
* Returns a description for the requested app partition.
* @param[in] partition Pointer to app partition. (only app partition)
* @param[out] app_desc Structure of info about app.
* @return
* - ESP_OK Successful.
* - ESP_ERR_NOT_FOUND app_desc structure is not found. Magic word is incorrect.
* - ESP_ERR_NOT_SUPPORTED Partition is not application.
* - ESP_ERR_INVALID_ARG Arguments is NULL or if partition's offset exceeds partition size.
* - ESP_ERR_INVALID_SIZE Read would go out of bounds of the partition.
* - or one of error codes from lower-level flash driver.
*/
esp_err_t esp_ota_get_partition_description(const esp_partition_t *partition, esp_app_desc_t *app_desc);
/**
* @brief This function is called to indicate that the running app is working well.
*
* @return
* - ESP_OK: if successful.
*/
esp_err_t esp_ota_mark_app_valid_cancel_rollback();
/**
* @brief This function is called to roll back to the previously workable app with reboot.
*
* If rollback is successful then device will reset else API will return with error code.
* Checks applications on a flash drive that can be booted in case of rollback.
* If the flash does not have at least one app (except the running app) then rollback is not possible.
* @return
* - ESP_FAIL: if not successful.
* - ESP_ERR_OTA_ROLLBACK_FAILED: The rollback is not possible due to flash does not have any apps.
*/
esp_err_t esp_ota_mark_app_invalid_rollback_and_reboot();
/**
* @brief Returns last partition with invalid state (ESP_OTA_IMG_INVALID or ESP_OTA_IMG_ABORTED).
*
* @return partition.
*/
const esp_partition_t* esp_ota_get_last_invalid_partition();
/**
* @brief Returns state for given partition.
*
* @param[in] partition Pointer to partition.
* @param[out] ota_state state of partition (if this partition has a record in otadata).
* @return
* - ESP_OK: Successful.
* - ESP_ERR_INVALID_ARG: partition or ota_state arguments were NULL.
* - ESP_ERR_NOT_SUPPORTED: partition is not ota.
* - ESP_ERR_NOT_FOUND: Partition table does not have otadata or state was not found for given partition.
*/
esp_err_t esp_ota_get_state_partition(const esp_partition_t *partition, esp_ota_img_states_t *ota_state);
/**
* @brief Erase previous boot app partition and corresponding otadata select for this partition.
*
* When current app is marked to as valid then you can erase previous app partition.
* @return
* - ESP_OK: Successful, otherwise ESP_ERR.
*/
esp_err_t esp_ota_erase_last_boot_app_partition(void);
/**
* @brief Checks applications on the slots which can be booted in case of rollback.
*
* These applications should be valid (marked in otadata as not UNDEFINED, INVALID or ABORTED and crc is good) and be able booted,
* and secure_version of app >= secure_version of efuse (if anti-rollback is enabled).
*
* @return
* - True: Returns true if the slots have at least one app (except the running app).
* - False: The rollback is not possible.
*/
bool esp_ota_check_rollback_is_possible(void);
#ifdef __cplusplus
}
#endif

View File

@ -14,6 +14,7 @@
#pragma once
#include "esp_flash_data_types.h"
#include "esp_image_format.h"
/// Type of hold a GPIO in low state
typedef enum {
@ -23,21 +24,29 @@ typedef enum {
} esp_comm_gpio_hold_t;
/**
* @brief Calculate crc for the OTA data partition.
* @brief Calculate crc for the OTA data select.
*
* @param[in] ota_data The OTA data partition.
* @param[in] s The OTA data select.
* @return Returns crc value.
*/
uint32_t bootloader_common_ota_select_crc(const esp_ota_select_entry_t *s);
/**
* @brief Verifies the validity of the OTA data partition
* @brief Verifies the validity of the OTA data select
*
* @param[in] ota_data The OTA data partition.
* @param[in] s The OTA data select.
* @return Returns true on valid, false otherwise.
*/
bool bootloader_common_ota_select_valid(const esp_ota_select_entry_t *s);
/**
* @brief Returns true if OTADATA is not marked as bootable partition.
*
* @param[in] s The OTA data select.
* @return Returns true if OTADATA invalid, false otherwise.
*/
bool bootloader_common_ota_select_invalid(const esp_ota_select_entry_t *s);
/**
* @brief Check if the GPIO input is a long hold or a short hold.
*
@ -91,3 +100,39 @@ bool bootloader_common_label_search(const char *list, char *label);
* - ESP_FAIL: An allocation error occurred.
*/
esp_err_t bootloader_common_get_sha256_of_partition(uint32_t address, uint32_t size, int type, uint8_t *out_sha_256);
/**
* @brief Returns the number of active otadata.
*
* @param[in] two_otadata Pointer on array from two otadata structures.
*
* @return The number of active otadata (0 or 1).
* - -1: If it does not have active otadata.
*/
int bootloader_common_get_active_otadata(esp_ota_select_entry_t *two_otadata);
/**
* @brief Returns the number of active otadata.
*
* @param[in] two_otadata Pointer on array from two otadata structures.
* @param[in] valid_two_otadata Pointer on array from two bools. True means select.
* @param[in] max True - will select the maximum ota_seq number, otherwise the minimum.
*
* @return The number of active otadata (0 or 1).
* - -1: If it does not have active otadata.
*/
int bootloader_common_select_otadata(const esp_ota_select_entry_t *two_otadata, bool *valid_two_otadata, bool max);
/**
* @brief Returns esp_app_desc structure for app partition. This structure includes app version.
*
* Returns a description for the requested app partition.
* @param[in] partition App partition description.
* @param[out] app_desc Structure of info about app.
* @return
* - ESP_OK: Successful.
* - ESP_ERR_INVALID_ARG: The arguments passed are not valid.
* - ESP_ERR_NOT_FOUND: app_desc structure is not found. Magic word is incorrect.
* - ESP_FAIL: mapping is fail.
*/
esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t *partition, esp_app_desc_t *app_desc);

View File

@ -1,99 +0,0 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESP_EFUSE_H
#define _ESP_EFUSE_H
#include "soc/efuse_reg.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/* @brief Permanently update values written to the efuse write registers
*
* After updating EFUSE_BLKx_WDATAx_REG registers with new values to
* write, call this function to permanently write them to efuse.
*
* @note Setting bits in efuse is permanent, they cannot be unset.
*
* @note Due to this restriction you don't need to copy values to
* Efuse write registers from the matching read registers, bits which
* are set in the read register but unset in the matching write
* register will be unchanged when new values are burned.
*
* @note This function is not threadsafe, if calling code updates
* efuse values from multiple tasks then this is caller's
* responsibility to serialise.
*
* After burning new efuses, the read registers are updated to match
* the new efuse values.
*/
void esp_efuse_burn_new_values(void);
/* @brief Reset efuse write registers
*
* Efuse write registers are written to zero, to negate
* any changes that have been staged here.
*/
void esp_efuse_reset(void);
/* @brief Disable BASIC ROM Console via efuse
*
* By default, if booting from flash fails the ESP32 will boot a
* BASIC console in ROM.
*
* Call this function (from bootloader or app) to permanently
* disable the console on this chip.
*/
void esp_efuse_disable_basic_rom_console(void);
/* @brief Encode one or more sets of 6 byte sequences into
* 8 bytes suitable for 3/4 Coding Scheme.
*
* This function is only useful if the CODING_SCHEME efuse
* is set to value 1 for 3/4 Coding Scheme.
*
* @param[in] in_bytes Pointer to a sequence of bytes to encode for 3/4 Coding Scheme. Must have length in_bytes_len. After being written to hardware, these bytes will read back as little-endian words.
* @param[out] out_words Pointer to array of words suitable for writing to efuse write registers. Array must contain 2 words (8 bytes) for every 6 bytes in in_bytes_len. Can be a pointer to efuse write registers.
* @param in_bytes_len. Length of array pointed to by in_bytes, in bytes. Must be a multiple of 6.
*
* @return ESP_ERR_INVALID_ARG if either pointer is null or in_bytes_len is not a multiple of 6. ESP_OK otherwise.
*/
esp_err_t esp_efuse_apply_34_encoding(const uint8_t *in_bytes, uint32_t *out_words, size_t in_bytes_len);
/* @brief Write random data to efuse key block write registers
*
* @note Caller is responsible for ensuring efuse
* block is empty and not write protected, before calling.
*
* @note Behaviour depends on coding scheme: a 256-bit key is
* generated and written for Coding Scheme "None", a 192-bit key
* is generated, extended to 256-bits by the Coding Scheme,
* and then writtten for 3/4 Coding Scheme.
*
* @note This function does not burn the new values, caller should
* call esp_efuse_burn_new_values() when ready to do this.
*
* @param blk_wdata0_reg Address of the first data write register
* in the block
*/
void esp_efuse_write_random_key(uint32_t blk_wdata0_reg);
#ifdef __cplusplus
}
#endif
#endif /* __ESP_EFUSE_H */

View File

@ -89,6 +89,25 @@ typedef struct {
uint32_t data_len;
} esp_image_segment_header_t;
#define ESP_APP_DESC_MAGIC_WORD 0xABCD5432 /*!< The magic word for the esp_app_desc structure that is in DROM. */
/**
* @brief Description about application.
*/
typedef struct {
uint32_t magic_word; /*!< Magic word ESP_APP_DESC_MAGIC_WORD */
uint32_t secure_version; /*!< Secure version */
uint32_t reserv1[2]; /*!< --- */
char version[32]; /*!< Application version */
char project_name[32]; /*!< Project name */
char time[16]; /*!< Compile time */
char date[16]; /*!< Compile date*/
char idf_ver[32]; /*!< Version IDF */
uint8_t app_elf_sha256[32]; /*!< sha256 of elf file */
uint32_t reserv2[20]; /*!< --- */
} esp_app_desc_t;
_Static_assert(sizeof(esp_app_desc_t) == 256, "esp_app_desc_t should be 256 bytes");
#define ESP_IMAGE_MAX_SEGMENTS 16
/* Structure to hold on-flash image metadata */

View File

@ -326,8 +326,12 @@ bool esp_vhci_host_check_send_available(void);
/** @brief esp_vhci_host_send_packet
* host send packet to controller
*
* Should not call this function from within a critical section
* or when the scheduler is suspended.
*
* @param data the packet point
*,@param len the packet length
* @param len the packet length
*/
void esp_vhci_host_send_packet(uint8_t *data, uint16_t len);
@ -405,7 +409,6 @@ esp_err_t esp_bt_mem_release(esp_bt_mode_t mode);
*
* For ORIG mode:
* Bluetooth modem sleep is enabled in controller start up by default if CONFIG_BTDM_CONTROLLER_MODEM_SLEEP is set and "ORIG mode" is selected. In ORIG modem sleep mode, bluetooth controller will switch off some components and pause to work every now and then, if there is no event to process; and wakeup according to the scheduled interval and resume the work. It can also wakeup earlier upon external request using function "esp_bt_controller_wakeup_request".
* Note that currently there is problem in the combination use of bluetooth modem sleep and Dynamic Frequency Scaling(DFS). So do not enable DFS if bluetooth modem sleep is in use.
*
* @return
* - ESP_OK : success
@ -454,11 +457,11 @@ void esp_bt_controller_wakeup_request(void);
/**
* @brief Manually clear scan duplicate list
*
*
* Note that scan duplicate list will be automatically cleared when the maximum amount of device in the filter is reached
* the amount of device in the filter can be configured in menuconfig.
*
*
*
*
* @return
* - ESP_OK : success
* - other : failed

View File

@ -1140,7 +1140,7 @@ esp_err_t esp_ble_passkey_reply(esp_bd_addr_t bd_addr, bool accept, uint32_t pas
/**
* @brief Reply the confirm value to the peer device in the legacy connection stage.
* @brief Reply the confirm value to the peer device in the secure connection stage.
*
* @param[in] bd_addr : BD address of the peer device
* @param[in] accept : numbers to compare are the same or different.

View File

@ -58,11 +58,12 @@
#define CONFIG_MBEDTLS_ECDH_C 1
#define CONFIG_SPIRAM_USE_CAPS_ALLOC 1
#define CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE 1
#define CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM 4
#define CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM 8
#define CONFIG_MBEDTLS_SSL_ALPN 1
#define CONFIG_MBEDTLS_PEM_WRITE_C 1
#define CONFIG_BT_SPP_ENABLED 1
#define CONFIG_BT_RESERVE_DRAM 0xdb5c
#define CONFIG_APP_COMPILE_TIME_DATE 1
#define CONFIG_CXX_EXCEPTIONS 1
#define CONFIG_FATFS_FS_LOCK 0
#define CONFIG_IP_LOST_TIMER_INTERVAL 120
@ -75,17 +76,19 @@
#define CONFIG_CONSOLE_UART_BAUDRATE 115200
#define CONFIG_SPIRAM_SUPPORT 1
#define CONFIG_LWIP_MAX_SOCKETS 10
#define CONFIG_APP_ROLLBACK_ENABLE 1
#define CONFIG_LWIP_NETIF_LOOPBACK 1
#define CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT "pthread"
#define CONFIG_EMAC_TASK_PRIORITY 20
#define CONFIG_TIMER_TASK_STACK_DEPTH 2048
#define CONFIG_TCP_MSS 1436
#define CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED 1
#define CONFIG_BTDM_CONTROLLER_MODE_BTDM 1
#define CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF 3
#define CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4 1
#define CONFIG_TCPIP_TASK_AFFINITY_CPU0 1
#define CONFIG_FATFS_CODEPAGE 850
#define CONFIG_ULP_COPROC_RESERVE_MEM 512
#define CONFIG_MB_UART_RXD 34
#define CONFIG_LWIP_MAX_UDP_PCBS 16
#define CONFIG_ESPTOOLPY_BAUD 921600
#define CONFIG_INT_WDT_CHECK_CPU1 1
@ -120,8 +123,10 @@
#define CONFIG_SCAN_DUPLICATE_BY_DEVICE_ADDR 1
#define CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER 1
#define CONFIG_MB_SERIAL_TASK_STACK_SIZE 2048
#define CONFIG_MBEDTLS_PSK_MODES 1
#define CONFIG_GATTS_SEND_SERVICE_CHANGE_AUTO 1
#define CONFIG_LWIP_DHCPS_LEASE_UNIT 60
#define CONFIG_EFUSE_MAX_BLK_LEN 192
#define CONFIG_SPIFFS_USE_MAGIC 1
#define CONFIG_TCPIP_TASK_STACK_SIZE 2560
#define CONFIG_BLUEDROID_PINNED_TO_CORE_0 1
@ -164,11 +169,11 @@
#define CONFIG_BTDM_LPCLK_SEL_MAIN_XTAL 1
#define CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED 1
#define CONFIG_LIBSODIUM_USE_MBEDTLS_SHA 1
#define CONFIG_SW_COEXIST_PREFERENCE_WIFI 1
#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_PSK 1
#define CONFIG_DMA_RX_BUF_NUM 10
#define CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED 1
#define CONFIG_MBEDTLS_KEY_EXCHANGE_PSK 1
#define CONFIG_TCP_SYNMAXRTX 6
#define CONFIG_MB_UART_RTS 32
#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA 1
#define CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF 0
#define CONFIG_HEAP_POISONING_LIGHT 1
@ -186,19 +191,24 @@
#define CONFIG_MBEDTLS_SSL_PROTO_TLS1_1 1
#define CONFIG_LWIP_SO_REUSE_RXTOALL 1
#define CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT 20
#define CONFIG_ESP32_WIFI_MGMT_SBUF_NUM 32
#define CONFIG_PARTITION_TABLE_SINGLE_APP 1
#define CONFIG_XTENSA_IMPL 1
#define CONFIG_UNITY_ENABLE_FLOAT 1
#define CONFIG_ESP32_WIFI_RX_BA_WIN 6
#define CONFIG_ESP32_WIFI_RX_BA_WIN 16
#define CONFIG_MBEDTLS_X509_CSR_PARSE_C 1
#define CONFIG_SPIFFS_USE_MTIME 1
#define CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN 0
#define CONFIG_LWIP_DHCP_RESTORE_LAST_IP 1
#define CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN 2
#define CONFIG_PICO_PSRAM_CS_IO 10
#define CONFIG_EMAC_TASK_STACK_SIZE 3072
#define CONFIG_MB_QUEUE_LENGTH 20
#define CONFIG_SW_COEXIST_PREFERENCE_VALUE 0
#define CONFIG_SW_COEXIST_PREFERENCE_VALUE 2
#define CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA 1
#define CONFIG_OV2640_SUPPORT 1
#define CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER 1
#define CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK 1
#define CONFIG_PPP_SUPPORT 1
#define CONFIG_SPIRAM_SPEED_40M 1
#define CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE 2048
@ -228,6 +238,7 @@
#define CONFIG_LOG_BOOTLOADER_LEVEL 0
#define CONFIG_MBEDTLS_TLS_ENABLED 1
#define CONFIG_LWIP_MAX_RAW_PCBS 16
#define CONFIG_BTU_TASK_STACK_SIZE 4096
#define CONFIG_SMP_ENABLE 1
#define CONFIG_SPIRAM_SIZE -1
#define CONFIG_MBEDTLS_SSL_SESSION_TICKETS 1
@ -259,15 +270,18 @@
#define CONFIG_FREERTOS_INTERRUPT_BACKTRACE 1
#define CONFIG_WL_SECTOR_SIZE 4096
#define CONFIG_ESP32_DEBUG_OCDAWARE 1
#define CONFIG_MB_UART_TXD 33
#define CONFIG_MQTT_TRANSPORT_WEBSOCKET 1
#define CONFIG_TIMER_TASK_PRIORITY 1
#define CONFIG_PPP_PAP_SUPPORT 1
#define CONFIG_MBEDTLS_TLS_CLIENT 1
#define CONFIG_BTDM_CONTROLLER_HCI_MODE_VHCI 1
#define CONFIG_BT_ENABLED 1
#define CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY 1
#define CONFIG_BT_SSP_ENABLED 1
#define CONFIG_SW_COEXIST_PREFERENCE_BALANCE 1
#define CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED 1
#define CONFIG_MONITOR_BAUD 115200
#define CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT -1
#define CONFIG_ESP32_DEBUG_STUBS_ENABLE 1
#define CONFIG_TCPIP_LWIP 1
#define CONFIG_WIFI_LWIP_ALLOCATION_FROM_SPIRAM_FIRST 1
@ -278,6 +292,7 @@
#define CONFIG_MBEDTLS_HAVE_TIME 1
#define CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY 1
#define CONFIG_TCP_QUEUE_OOSEQ 1
#define CONFIG_FATFS_ALLOC_PREFER_EXTRAM 1
#define CONFIG_GATTS_ENABLE 1
#define CONFIG_CXX_EXCEPTIONS_EMG_POOL_SIZE 0
#define CONFIG_ADC_CAL_EFUSE_VREF_ENABLE 1
@ -287,12 +302,14 @@
#define CONFIG_SUPPORT_TERMIOS 1
#define CONFIG_CLASSIC_BT_ENABLED 1
#define CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK 1
#define CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_PSK 1
#define CONFIG_OPENSSL_ASSERT_DO_NOTHING 1
#define CONFIG_IDF_TARGET "esp32"
#define CONFIG_WL_SECTOR_SIZE_4096 1
#define CONFIG_OPTIMIZATION_LEVEL_DEBUG 1
#define CONFIG_FREERTOS_NO_AFFINITY 0x7FFFFFFF
#define CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED 1
#define CONFIG_HTTPD_ERR_RESP_NO_DELAY 1
#define CONFIG_MB_TIMER_INDEX 0
#define CONFIG_SCAN_DUPLICATE_TYPE 0
#define CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED 1
@ -323,9 +340,10 @@
#define CONFIG_MONITOR_BAUD_OTHER_VAL 115200
#define CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF 1
#define CONFIG_ESPTOOLPY_PORT "/dev/cu.usbserial-DO00EAB0"
#define CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS 1
#define CONFIG_TASK_WDT_PANIC 1
#define CONFIG_UNITY_ENABLE_DOUBLE 1
#define CONFIG_BLUEDROID_PINNED_TO_CORE 0
#define CONFIG_BTDM_MODEM_SLEEP_MODE_ORIG 1
#define CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL_ERROR 1
#define CONFIG_ESP32_WIFI_IRAM_OPT 1
#define CONFIG_FATFS_API_ENCODING_ANSI_OEM 1

View File

@ -19,6 +19,7 @@
extern "C" {
#endif
#include "freertos/FreeRTOS.h"
#include "esp_types.h"
#include "esp_intr.h"
#include "esp_err.h"
@ -105,7 +106,7 @@ extern "C" {
#define CAN_EXTD_ID_MASK 0x1FFFFFFF /**< Bit mask for 29 bit Extended Frame Format ID */
#define CAN_STD_ID_MASK 0x7FF /**< Bit mask for 11 bit Standard Frame Format ID */
#define CAN_MAX_DATA_LEN 8 /**< Maximum number of data bytes in a CAN2.0B frame */
#define CAN_IO_UNUSED (-1) /**< Marks GPIO as unused in CAN configuration */
#define CAN_IO_UNUSED ((gpio_num_t) -1) /**< Marks GPIO as unused in CAN configuration */
/** @endcond */
/* ----------------------- Enum and Struct Definitions ---------------------- */
@ -392,6 +393,34 @@ esp_err_t can_initiate_recovery();
*/
esp_err_t can_get_status_info(can_status_info_t *status_info);
/**
* @brief Clear the transmit queue
*
* This function will clear the transmit queue of all messages.
*
* @note The transmit queue is automatically cleared when can_stop() or
* can_initiate_recovery() is called.
*
* @return
* - ESP_OK: Transmit queue cleared
* - ESP_ERR_INVALID_STATE: CAN driver is not installed or TX queue is disabled
*/
esp_err_t can_clear_transmit_queue();
/**
* @brief Clear the receive queue
*
* This function will clear the receive queue of all messages.
*
* @note The receive queue is automatically cleared when can_start() is
* called.
*
* @return
* - ESP_OK: Transmit queue cleared
* - ESP_ERR_INVALID_STATE: CAN driver is not installed
*/
esp_err_t can_clear_receive_queue();
#ifdef __cplusplus
}
#endif

View File

@ -537,13 +537,17 @@ esp_err_t gpio_set_drive_capability(gpio_num_t gpio_num, gpio_drive_cap_t streng
esp_err_t gpio_get_drive_capability(gpio_num_t gpio_num, gpio_drive_cap_t* strength);
/**
* @brief Set gpio pad hold function.
* @brief Enable gpio pad hold function.
*
* The gpio pad hold function works in both input and output modes, but must be output-capable gpios.
* If pad hold enabled:
* in output mode: the output level of the pad will be force locked and can not be changed.
* in input mode: the input value read will not change, regardless the changes of input signal.
*
* The state of digital gpio cannot be held during Deep-sleep, and it will resume the hold function
* when the chip wakes up from Deep-sleep. If the digital gpio also needs to be held during Deep-sleep,
* `gpio_deep_sleep_hold_en` should also be called.
*
* Power down or call gpio_hold_dis will disable this function.
*
* @param gpio_num GPIO number, only support output-capable GPIOs
@ -555,7 +559,15 @@ esp_err_t gpio_get_drive_capability(gpio_num_t gpio_num, gpio_drive_cap_t* stren
esp_err_t gpio_hold_en(gpio_num_t gpio_num);
/**
* @brief Unset gpio pad hold function.
* @brief Disable gpio pad hold function.
*
* When the chip is woken up from Deep-sleep, the gpio will be set to the default mode, so, the gpio will output
* the default level if this function is called. If you dont't want the level changes, the gpio should be configured to
* a known state before this function is called.
* e.g.
* If you hold gpio18 high during Deep-sleep, after the chip is woken up and `gpio_hold_dis` is called,
* gpio18 will output low level(because gpio18 is input mode by default). If you don't want this behavior,
* you should configure gpio18 as output mode and set it to hight level before calling `gpio_hold_dis`.
*
* @param gpio_num GPIO number, only support output-capable GPIOs
*
@ -563,7 +575,24 @@ esp_err_t gpio_hold_en(gpio_num_t gpio_num);
* - ESP_OK Success
* - ESP_ERR_NOT_SUPPORTED Not support pad hold function
*/
esp_err_t gpio_hold_dis(gpio_num_t gpio_num);
esp_err_t gpio_hold_dis(gpio_num_t gpio_num);
/**
* @brief Enable all digital gpio pad hold function during Deep-sleep.
*
* When the chip is in Deep-sleep mode, all digital gpio will hold the state before sleep, and when the chip is woken up,
* the status of digital gpio will not be held. Note that the pad hold feature only works when the chip is in Deep-sleep mode,
* when not in sleep mode, the digital gpio state can be changed even you have called this function.
*
* Power down or call gpio_hold_dis will disable this function, otherwise, the digital gpio hold feature works as long as the chip enter Deep-sleep.
*/
void gpio_deep_sleep_hold_en(void);
/**
* @brief Disable all digital gpio pad hold function during Deep-sleep.
*
*/
void gpio_deep_sleep_hold_dis(void);
/**
* @brief Set pad input to a peripheral signal through the IOMUX.

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