Compare commits

...

63 Commits

Author SHA1 Message Date
30b3eebabc * merge only annotated tag messages into release notes (#1683) 2018-07-28 10:28:04 +03:00
3222e6490a add LOLIN D32 & D32 PRO Board support (#1688) 2018-07-28 10:27:26 +03:00
2fba81223e Added instructions for installation with boards manager (#1630)
* Added instructions for installation with boards manager (stolen directly from esp8266)

* changed to production link instead of dev

* Added to main README. Made mods to images as requested.

* Added links for development package
2018-07-26 08:10:46 +02:00
e51f7a5b87 fix compilation errors in idf 2018-07-25 22:39:32 +02:00
7d2560cbbf roll back the while loop in _parseForm 2018-07-25 20:59:56 +02:00
17065dfd3a Added a define to format the spiffs in SPIFFS_Test.ino (#1662)
* Added a define to format the spiffs in SPIFFS_Test.ino

* Uncommented the define

* Matched define names
2018-07-25 18:44:37 +02:00
2f5b3c0c56 Functions _uploadReadByte and _parseForm were modified in order to (#1677)
speed up uploading data. Now there is no need to call time consuming
client.connected() method.
2018-07-25 17:37:15 +02:00
1fe3ee87b6 Feature/selective compilation (#1671)
* Selective compilation

* Optimized component.mk

* Autoconnect WiFi now forces WiFi
2018-07-25 13:02:37 +02:00
328523f5e3 Memory leak (#1672)
When a package of size 0 arrives, "buf" is created, but never released. (Sorry, that was my mistake in the last patch)
2018-07-25 12:56:41 +02:00
Bin
7761ebd9f2 Add M5Stack-FIRE board (#1647)
* Add M5Stack-FIRE board

* updated m5stack-fire boards.txt

* remove pins 16 and 17
2018-07-25 12:56:04 +02:00
f9a382ab9f fix some compilation error and warnings in i2c 2018-07-24 22:06:50 +02:00
d854dc1bf6 Create WiFiClientEnterprise.ino (#1640)
Sketch for ESP32 boards that allow them to connect to WPA/WPA2 Enterprise Networks.
2018-07-24 19:57:57 +02:00
f1f8d7e306 Packet with zero data length (#1659)
If you receive a package with a data length of zero, parsePacket returns 0, but rx_buffer will exist. So if another parsePacket with no read access returns to zeros, there is still data that can be read. This example would not work: https://www.arduino.cc/en/Reference/EthernetUDPParsePacket

Also I added a check if rx_buffer exit when you try to flush it.
2018-07-24 19:52:42 +02:00
da798c7db0 Add TTGO LoRa32 with OLED Version 1.x Board (#1663)
* Add ttgo-lora32-v1 folder to variants folder

* Add ttgo-lora32-v1 info to boards.txt

* Add defs to pins_arduino.h for I2C OLED and SPI LoRa radio pinouts as per @stickbreaker
2018-07-24 19:49:38 +02:00
8d7fb58672 Fix for spurious interrupts during I2C communications (#1665)
This version no longer needs an interrupt for each byte transferred. It only needs interrupts for START, STOP, FIFO empty/Full or error conditions.  This dramatically reduces the interrupt overhead.  I think the prior version was causing an interrupt overload condition where the ISR was not able to process every interrupt as they happened.
2018-07-24 19:43:45 +02:00
2fda054bea [OTA Timeout] Added ability set OTA timeout in the OTA client (#1669) 2018-07-24 19:40:18 +02:00
Luc
e157ec06a7 expose post args during upload (#1650) 2018-07-17 10:58:03 +02:00
05d72f963d fix WiFi STA going into loop in some cases of disconnect 2018-07-16 22:50:52 +02:00
b14f82b65f Release notes formatting update (#1634) 2018-07-16 20:47:30 +02:00
c830511f01 EEPROM library: Move #include of Arduino.h to header file (#1641)
EEPROM.h uses data types which are declared through Arduino.h but that file does not contain an #include directive for Arduino.h. This does not cause any problems when the EEPROM library is #included from a .ino file because the Arduino IDE automatically adds an #include directive for Arduino.h but this is not the case for .cpp files. If a .cpp file has an #include directive for EEPROM.h that does not follow an #include directive for Arduino.h then compilation fails:

E:\arduino\hardware\espressif\esp32\libraries\EEPROM/EEPROM.h:91:5: error: 'float_t' does not name a type

     float_t readFloat(int address);

     ^

E:\arduino\hardware\espressif\esp32\libraries\EEPROM/EEPROM.h:92:5: error: 'double_t' does not name a type

     double_t readDouble(int address);

     ^

E:\arduino\hardware\espressif\esp32\libraries\EEPROM/EEPROM.h:95:5: error: 'String' does not name a type

     String readString(int address);

     ^

E:\arduino\hardware\espressif\esp32\libraries\EEPROM/EEPROM.h:110:36: error: 'float_t' has not been declared

     size_t writeFloat(int address, float_t value);

                                    ^

E:\arduino\hardware\espressif\esp32\libraries\EEPROM/EEPROM.h:111:37: error: 'double_t' has not been declared

     size_t writeDouble(int address, double_t value);

                                     ^

E:\arduino\hardware\espressif\esp32\libraries\EEPROM/EEPROM.h:114:37: error: 'String' has not been declared

     size_t writeString(int address, String value);
2018-07-16 20:44:36 +02:00
cbd4dc53a6 Add ALKS board variant (#1643)
* Initial support for ALKS variant
2018-07-16 20:43:35 +02:00
44f5a4dbc8 Fix Client returning disconnected because of VFS errors 2018-07-16 20:08:27 +02:00
e63aa40650 Enable PSRAM builds when used as IDF component 2018-07-15 10:20:01 +02:00
28a410dd50 Spurious Interrupts Temporary fix 20180711 (#1625)
the 'eject' ERROR is and indication of an interrupt triggering without an source.  I am working to eliminate these serviceable interrupt.  This update increase stability on a HelTek Wifi Lora 32 board. with a SSD1306 OLED.  This update fixes a glaring error in the interrupt allocation code, the Interrupt mask was wrong.  I also dynamically adjust the FiFo thresholds based on Bus clockrate. The change to FiFo thresholds has reduced the number for 'eject' events.  I also change 'eject' from and ERROR to DEBUG.  An 'eject' event does not compromise i2c transmissions. It happens after a transaction has completed. 

Chuck.
2018-07-12 15:18:26 +02:00
ddfeae90d0 Fix AsyncUDP server exception 2018-07-11 20:46:54 +02:00
ff90778173 Fix HTTP client returning disconnected when there is still data avalable 2018-07-10 21:06:20 +02:00
4e9d1ee237 Fix connected to be wrongly reported in WiFiClient 2018-07-10 21:05:44 +02:00
c1a94b5326 Fix wrong event description 2018-07-10 16:13:34 +02:00
3e160587f3 Fix WiFi Client not properly reporting connected state 2018-07-10 15:01:40 +02:00
79010b6498 Add XinaBox CW02 to supported boards (#1620)
* Create pins_arduino.h

* Update boards.txt

* Update pins_arduino.h
2018-07-10 13:43:21 +02:00
9925772db0 * update 'version' in platform.txt (#1619) 2018-07-10 11:26:19 +02:00
c77aed4ac4 Allow using argument with attachInterrupt (#1535)
* Allow using argument with attachInterrupt

* formatting

replace tabs with spaces

* fix bug more then 1 interrupt

* leftover

* add example

* make attachInterruptArg public

* update example

* leftover
2018-07-07 11:26:58 +02:00
901a341949 BluetoothSerial: set COD to be compatible with macOS (#1304) (#1556) 2018-07-07 11:25:10 +02:00
9f6d0d2958 EEPROM.readstring was returning an extra character (#1609) 2018-07-07 10:19:44 +02:00
9efecc1be0 Implement RX buffer for WiFi client to speed up small reads 2018-07-05 22:31:58 +02:00
b0c6991bcf Small adjustments to the web server 2018-07-05 22:31:19 +02:00
8afdd71b3a Add missing event string to WiFi events 2018-07-05 22:30:54 +02:00
871dd183d8 Print to debug the IP address obtained by DHCP 2018-07-05 16:04:07 +02:00
05111bbde7 fix case where library source subfolders are not compiled when used as component 2018-07-05 14:27:17 +02:00
bad53905e8 Prevent exceptions in WiFi if not yet started 2018-07-05 12:28:15 +02:00
95b87545e7 Make Stream functions if File to not wait for timeout
Fixes: https://github.com/espressif/arduino-esp32/issues/1597
2018-07-05 11:51:58 +02:00
9f8f05735b * relnotes handling update (#1592)
* script exec fails on curl error
2018-07-04 15:46:46 +02:00
a835bb26c4 Add missing flag to fix psram issues
Thanks @igrr
2018-07-04 12:11:25 +02:00
5e46c9bae6 Add Wrover Support and Option to enable SPIRAM 2018-07-03 23:03:50 +02:00
659c8ad528 Fix TelnetToSerial sketch 2018-07-03 21:51:24 +02:00
2fe965259a "fix" SPI 2018-07-03 21:23:04 +02:00
0161e28614 Added OTAWebUpdater Doc (#1583) 2018-07-03 20:43:18 +02:00
4e5cbdaa7f Add declarations for all Serial, SPI and Wire buses 2018-07-03 20:41:03 +02:00
12ca9e8b52 Port UART reset fix from ESP-IDF (#1408) 2018-07-03 17:54:08 +02:00
8b01b9e187 Change esptool version notation 2018-07-03 14:50:14 +02:00
c4c946a83d Broke HTTP_Method out into a separate library for reuse in ESPAsyncWebServer (#1562) 2018-07-02 18:24:08 +02:00
3967beb4fb Added WiPy 3.0 board (#1572) 2018-07-02 18:23:06 +02:00
6411ac4e3c Remove confusing Debug output. (#1574)
If Core Debug Level is at DEBUG, a confusing debug message will be emitted if the I2C transaction takes longer complete than the  calculated minimum time.  This original debug message was just to prove that this new i2c code could correctly handle SCL stretching or interrupt latency issues. This delay is not a problem, or an error.  Usually it is caused by a higher priory interrupt starving the i2c ISR.  Usually WiFi is the culprit.  As long of this delay is within the configured timeout (by default 50ms, or can be set with Wire.setTimeOut(milliseconds);) no problem will occur and the transaction will successfully complete.
Chuck.
2018-07-02 18:22:05 +02:00
184bb069f2 Fix io16 io17 and PSRAM support (#1564)
* Add PSRAM init and malloc funtions

* Rebuild IDF libs
2018-06-30 23:06:50 +02:00
b855eb23a7 * arduino-esp32 release mgmt. update (#1557) 2018-06-29 00:54:26 +02:00
eb4e891344 Update build.sh 2018-06-28 23:45:52 +02:00
47421b869f Added OTAWebupdated (#1544)
* added OTAWebUpdater

* added OTAWebUpdater

* Updated OTAWebUpdater
2018-06-28 21:19:22 +02:00
a8ccbd40a4 Update esptool to be compatible with the packager (#1554) 2018-06-28 21:07:59 +02:00
58bdebc565 * release deployment comprehensive update (#1548) 2018-06-28 13:58:01 +02:00
ed953a0d2e BluetoothSerial: check return value and return number of bytes written (#1538) 2018-06-27 23:00:31 +02:00
93566a4fad fix PR tests 2018-06-27 22:21:13 +02:00
873876d94c Fix peek, read and available logic in WiFiClientSecure 2018-06-27 22:09:21 +02:00
058645264c Adjust RAM size and calculator 2018-06-27 21:01:31 +02:00
104 changed files with 2672 additions and 537 deletions

View File

@ -9,6 +9,7 @@ set(CORE_SRCS
cores/esp32/esp32-hal-ledc.c
cores/esp32/esp32-hal-matrix.c
cores/esp32/esp32-hal-misc.c
cores/esp32/esp32-hal-psram.c
cores/esp32/esp32-hal-sigmadelta.c
cores/esp32/esp32-hal-spi.c
cores/esp32/esp32-hal-time.c

View File

@ -106,8 +106,147 @@ config AUTOCONNECT_WIFI
bool "Autoconnect WiFi on boot"
default "n"
depends on AUTOSTART_ARDUINO
select ARDUINO_SELECTIVE_WiFi
help
If enabled, WiFi will connect to the last used SSID (if station was enabled),
else connection will be started only after calling WiFi.begin(ssid, password)
config ARDUINO_SELECTIVE_COMPILATION
bool "Include only specific Arduino libraries"
default n
config ARDUINO_SELECTIVE_ArduinoOTA
bool "Enable ArduinoOTA"
depends on ARDUINO_SELECTIVE_COMPILATION
select ARDUINO_SELECTIVE_WiFi
select ARDUINO_SELECTIVE_ESPmDNS
default y
config ARDUINO_SELECTIVE_AsyncUDP
bool "Enable AsyncUDP"
depends on ARDUINO_SELECTIVE_COMPILATION
default y
config ARDUINO_SELECTIVE_AzureIoT
bool "Enable AzureIoT"
depends on ARDUINO_SELECTIVE_COMPILATION
select ARDUINO_SELECTIVE_HTTPClient
default y
config ARDUINO_SELECTIVE_BLE
bool "Enable BLE"
depends on ARDUINO_SELECTIVE_COMPILATION
default y
config ARDUINO_SELECTIVE_BluetoothSerial
bool "Enable BluetoothSerial"
depends on ARDUINO_SELECTIVE_COMPILATION
default y
config ARDUINO_SELECTIVE_DNSServer
bool "Enable DNSServer"
depends on ARDUINO_SELECTIVE_COMPILATION
select ARDUINO_SELECTIVE_WiFi
default y
config ARDUINO_SELECTIVE_EEPROM
bool "Enable EEPROM"
depends on ARDUINO_SELECTIVE_COMPILATION
default y
config ARDUINO_SELECTIVE_ESP32
bool "Enable ESP32"
depends on ARDUINO_SELECTIVE_COMPILATION
default y
config ARDUINO_SELECTIVE_ESPmDNS
bool "Enable ESPmDNS"
depends on ARDUINO_SELECTIVE_COMPILATION
select ARDUINO_SELECTIVE_WiFi
default y
config ARDUINO_SELECTIVE_FS
bool "Enable FS"
depends on ARDUINO_SELECTIVE_COMPILATION
default y
config ARDUINO_SELECTIVE_HTTPClient
bool "Enable HTTPClient"
depends on ARDUINO_SELECTIVE_COMPILATION
select ARDUINO_SELECTIVE_WiFi
select ARDUINO_SELECTIVE_WiFiClientSecure
default y
config ARDUINO_SELECTIVE_NetBIOS
bool "Enable NetBIOS"
depends on ARDUINO_SELECTIVE_COMPILATION
select ARDUINO_SELECTIVE_WiFi
default y
config ARDUINO_SELECTIVE_Preferences
bool "Enable Preferences"
depends on ARDUINO_SELECTIVE_COMPILATION
default y
config ARDUINO_SELECTIVE_SD
bool "Enable SD"
depends on ARDUINO_SELECTIVE_COMPILATION
select ARDUINO_SELECTIVE_FS
default y
config ARDUINO_SELECTIVE_SD_MMC
bool "Enable SD_MMC"
depends on ARDUINO_SELECTIVE_COMPILATION
select ARDUINO_SELECTIVE_FS
default y
config ARDUINO_SELECTIVE_SimpleBLE
bool "Enable SimpleBLE"
depends on ARDUINO_SELECTIVE_COMPILATION
default y
config ARDUINO_SELECTIVE_SPI
bool "Enable SPI"
depends on ARDUINO_SELECTIVE_COMPILATION
default y
config ARDUINO_SELECTIVE_SPIFFS
bool "Enable SPIFFS"
depends on ARDUINO_SELECTIVE_COMPILATION
select ARDUINO_SELECTIVE_FS
default y
config ARDUINO_SELECTIVE_Ticker
bool "Enable Ticker"
depends on ARDUINO_SELECTIVE_COMPILATION
default y
config ARDUINO_SELECTIVE_Update
bool "Enable Update"
depends on ARDUINO_SELECTIVE_COMPILATION
default y
config ARDUINO_SELECTIVE_WebServer
bool "Enable WebServer"
depends on ARDUINO_SELECTIVE_COMPILATION
default y
select ARDUINO_SELECTIVE_FS
config ARDUINO_SELECTIVE_WiFi
bool "Enable WiFi"
depends on ARDUINO_SELECTIVE_COMPILATION
default y
config ARDUINO_SELECTIVE_WiFiClientSecure
bool "Enable WiFiClientSecure"
depends on ARDUINO_SELECTIVE_COMPILATION
select ARDUINO_SELECTIVE_WiFi
default y
config ARDUINO_SELECTIVE_Wire
bool "Enable Wire"
depends on ARDUINO_SELECTIVE_COMPILATION
default y
endmenu

View File

@ -9,7 +9,7 @@ endif
BOOT_APP_BIN_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(BOOT_APP_BIN_OFFSET) $(BOOT_APP_BIN_PATH)
ESPTOOL_ALL_FLASH_ARGS += $(BOOT_APP_BIN_OFFSET) $(BOOT_APP_BIN_PATH)
CPPFLAGS += -DARDUINO=10800 -DESP32=1 -DARDUINO_ARCH_ESP32=1
CPPFLAGS += -DARDUINO=10800 -DESP32=1 -DARDUINO_ARCH_ESP32=1 -DBOARD_HAS_PSRAM
boot-app0:
@echo "Rebooting to APP0"

View File

@ -19,7 +19,11 @@ Most of the framework is implemented. Most noticable is the missing analogWrite.
## Installation Instructions
- Using Arduino IDE
#### [Latest release ![Release Version](https://img.shields.io/github/release/espressif/arduino-esp32/all.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/)
- Using Arduino IDE Boards Manager (preferred)
+ [Instructions for Boards Manager](docs/arduino-ide/boards_manager.md)
- Using Arduino IDE with the development repository
+ [Instructions for Windows](docs/arduino-ide/windows.md)
+ [Instructions for Mac](docs/arduino-ide/mac.md)
+ [Instructions for Debian/Ubuntu Linux](docs/arduino-ide/debian_ubuntu.md)
@ -28,6 +32,7 @@ Most of the framework is implemented. Most noticable is the missing analogWrite.
- [Using PlatformIO](docs/platformio.md)
- [Building with make](docs/make.md)
- [Using as ESP-IDF component](docs/esp-idf_component.md)
- [Using OTAWebUpdater](docs/OTAWebUpdate/OTAWebUpdate.md)
#### Decoding exceptions

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,6 @@
ARDUINO_CORE_LIBS := $(patsubst $(COMPONENT_PATH)/%,%,$(sort $(dir $(wildcard $(COMPONENT_PATH)/libraries/*/*/))))
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)))
COMPONENT_ADD_INCLUDEDIRS := cores/esp32 variants/esp32 $(ARDUINO_CORE_LIBS)
COMPONENT_PRIV_INCLUDEDIRS := cores/esp32/libb64

View File

@ -7,6 +7,8 @@
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
HardwareSerial Serial(0);
HardwareSerial Serial1(1);
HardwareSerial Serial2(2);
#endif
HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL) {}

View File

@ -79,6 +79,8 @@ protected:
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
extern HardwareSerial Serial;
extern HardwareSerial Serial1;
extern HardwareSerial Serial2;
#endif
#endif

View File

@ -70,7 +70,12 @@ const DRAM_ATTR esp32_gpioMux_t esp32_gpioMux[GPIO_PIN_COUNT]={
};
typedef void (*voidFuncPtr)(void);
static voidFuncPtr __pinInterruptHandlers[GPIO_PIN_COUNT] = {0,};
typedef void (*voidFuncPtrArg)(void*);
typedef struct {
voidFuncPtr fn;
void* arg;
} InterruptHandle_t;
static InterruptHandle_t __pinInterruptHandlers[GPIO_PIN_COUNT] = {0,};
#include "driver/rtc_io.h"
@ -193,7 +198,7 @@ extern int IRAM_ATTR __digitalRead(uint8_t pin)
static intr_handle_t gpio_intr_handle = NULL;
static void IRAM_ATTR __onPinInterrupt(void *arg)
static void IRAM_ATTR __onPinInterrupt()
{
uint32_t gpio_intr_status_l=0;
uint32_t gpio_intr_status_h=0;
@ -207,8 +212,12 @@ static void IRAM_ATTR __onPinInterrupt(void *arg)
if(gpio_intr_status_l) {
do {
if(gpio_intr_status_l & ((uint32_t)1 << pin)) {
if(__pinInterruptHandlers[pin]) {
__pinInterruptHandlers[pin]();
if(__pinInterruptHandlers[pin].fn) {
if(__pinInterruptHandlers[pin].arg){
((voidFuncPtrArg)__pinInterruptHandlers[pin].fn)(__pinInterruptHandlers[pin].arg);
} else {
__pinInterruptHandlers[pin].fn();
}
}
}
} while(++pin<32);
@ -217,15 +226,19 @@ static void IRAM_ATTR __onPinInterrupt(void *arg)
pin=32;
do {
if(gpio_intr_status_h & ((uint32_t)1 << (pin - 32))) {
if(__pinInterruptHandlers[pin]) {
__pinInterruptHandlers[pin]();
if(__pinInterruptHandlers[pin].fn) {
if(__pinInterruptHandlers[pin].arg){
((voidFuncPtrArg)__pinInterruptHandlers[pin].fn)(__pinInterruptHandlers[pin].arg);
} else {
__pinInterruptHandlers[pin].fn();
}
}
}
} while(++pin<GPIO_PIN_COUNT);
}
}
extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int intr_type)
extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type)
{
static bool interrupt_initialized = false;
@ -233,7 +246,8 @@ extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int intr_type)
interrupt_initialized = true;
esp_intr_alloc(ETS_GPIO_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, __onPinInterrupt, NULL, &gpio_intr_handle);
}
__pinInterruptHandlers[pin] = userFunc;
__pinInterruptHandlers[pin].fn = (voidFuncPtr)userFunc;
__pinInterruptHandlers[pin].arg = arg;
esp_intr_disable(gpio_intr_handle);
if(esp_intr_get_cpu(gpio_intr_handle)) { //APP_CPU
GPIO.pin[pin].int_ena = 1;
@ -244,10 +258,15 @@ extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int intr_type)
esp_intr_enable(gpio_intr_handle);
}
extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int intr_type) {
__attachInterruptArg(pin, (voidFuncPtrArg)userFunc, NULL, intr_type);
}
extern void __detachInterrupt(uint8_t pin)
{
esp_intr_disable(gpio_intr_handle);
__pinInterruptHandlers[pin] = NULL;
__pinInterruptHandlers[pin].fn = NULL;
__pinInterruptHandlers[pin].arg = NULL;
GPIO.pin[pin].int_ena = 0;
GPIO.pin[pin].int_type = 0;
esp_intr_enable(gpio_intr_handle);
@ -258,5 +277,6 @@ extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pi
extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite")));
extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead")));
extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt")));
extern void attachInterruptArg(uint8_t pin, voidFuncPtr handler, void * arg, int mode) __attribute__ ((weak, alias("__attachInterruptArg")));
extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt")));

View File

@ -79,6 +79,7 @@ void digitalWrite(uint8_t pin, uint8_t val);
int digitalRead(uint8_t pin);
void attachInterrupt(uint8_t pin, void (*)(void), int mode);
void attachInterruptArg(uint8_t pin, void (*)(void), void * arg, int mode);
void detachInterrupt(uint8_t pin);
#ifdef __cplusplus

View File

@ -33,6 +33,22 @@
#define DR_REG_I2C_EXT_BASE_FIXED 0x60013000
#define DR_REG_I2C1_EXT_BASE_FIXED 0x60027000
/* Stickbreaker ISR mode debug support
ENABLE_I2C_DEBUG_BUFFER
Enable debug interrupt history buffer, setting this define will result in 1544 bytes of RAM
being used whenever CORE_DEBUG_LEVEL is higher than WARNING. Unless you are debugging
a problem in the I2C subsystem I would recommend you leave it commented out.
*/
//#define ENABLE_I2C_DEBUG_BUFFER
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) && (defined ENABLE_I2C_DEBUG_BUFFER)
#define INTBUFFMAX 64
static uint32_t intBuff[INTBUFFMAX][3][2];
static uint32_t intPos[2]= {0,0};
#endif
// start from tools/sdk/include/soc/soc/i2c_struct.h
typedef union {
@ -65,6 +81,17 @@ typedef union {
uint32_t val;
} I2C_FIFO_CONF_t;
typedef union {
struct {
uint32_t rx_fifo_start_addr: 5; /*This is the offset address of the last receiving data as described in nonfifo_rx_thres_register.*/
uint32_t rx_fifo_end_addr: 5; /*This is the offset address of the first receiving data as described in nonfifo_rx_thres_register.*/
uint32_t tx_fifo_start_addr: 5; /*This is the offset address of the first sending data as described in nonfifo_tx_thres register.*/
uint32_t tx_fifo_end_addr: 5; /*This is the offset address of the last sending data as described in nonfifo_tx_thres register.*/
uint32_t reserved20: 12;
};
uint32_t val;
} I2C_FIFO_ST_t;
// end from tools/sdk/include/soc/soc/i2c_struct.h
// sync between dispatch(i2cProcQueue) and worker(i2c_isr_handler_default)
@ -130,9 +157,7 @@ typedef struct {
uint8_t *data; // datapointer for read/write buffer
uint16_t length; // size of data buffer
uint16_t position; // current position for next char in buffer (<length)
uint16_t cmdBytesNeeded; // used to control number of I2C_COMMAND_t blocks added to queu
uint16_t queueLength; // number of data bytes needing moved, used to control
// current queuePos for fifo fills
uint16_t cmdBytesNeeded; // used to control number of I2C_COMMAND_t blocks added to queue
I2C_DATA_CTRL_t ctrl;
EventGroupHandle_t queueEvent; // optional user supplied for Async feedback EventBits
} I2C_DATA_QUEUE_t;
@ -152,9 +177,10 @@ struct i2c_struct_t {
// maybe use it to trigger callback for OnRequest()
intr_handle_t intr_handle; /*!< I2C interrupt handle*/
I2C_DATA_QUEUE_t * dq;
uint16_t queueCount;
uint16_t queuePos;
uint16_t byteCnt;
uint16_t queueCount; // number of dq entries in queue.
uint16_t queuePos; // current queue that still has or needs data (out/in)
uint16_t errorByteCnt; // count of bytes moved (both in and out)
uint16_t errorQueue; // errorByteCnt is in this queue,(for error locus)
uint32_t exitCode;
};
@ -179,8 +205,8 @@ static i2c_t _i2c_bus_array[2] = {
#define I2C_MUTEX_UNLOCK() xSemaphoreGive(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},
{(volatile i2c_dev_t *)(DR_REG_I2C1_EXT_BASE_FIXED), NULL, 1, -1, -1,I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0,0}
{(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},
{(volatile i2c_dev_t *)(DR_REG_I2C1_EXT_BASE_FIXED), NULL, 1, -1, -1,I2C_NONE,I2C_NONE,I2C_ERROR_OK,NULL,NULL,NULL,0,0,0,0,0}
};
#endif
@ -204,13 +230,6 @@ static void IRAM_ATTR i2cSetCmd(i2c_t * i2c, uint8_t index, uint8_t op_code, uin
i2c->dev->command[index].val = cmd.val;
}
/* Stickbreaker ISR mode debug support
*/
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
#define INTBUFFMAX 64
static uint32_t intBuff[INTBUFFMAX][3][2];
static uint32_t intPos[2]= {0,0};
#endif
/* Stickbreaker ISR mode debug support
*/
@ -236,8 +255,7 @@ void IRAM_ATTR dumpCmdQueue(i2c_t *i2c)
*/
static void IRAM_ATTR fillCmdQueue(i2c_t * i2c, bool INTS)
{
/* this function is call on initial i2cProcQueue()
or when a I2C_END_DETECT_INT occures
/* this function is called on initial i2cProcQueue() or when a I2C_END_DETECT_INT occurs
*/
uint16_t cmdIdx = 0;
uint16_t qp = i2c->queuePos;
@ -261,14 +279,14 @@ static void IRAM_ATTR fillCmdQueue(i2c_t * i2c, bool INTS)
I2C_DATA_QUEUE_t *tdq=&i2c->dq[qp]; // simpler coding
if((!tdq->ctrl.startCmdSent) && (cmdIdx < 14)) { // has this dq element's START command been added?
// <14 testing if ReSTART END is causeing the Timeout
// (cmdIdx<14) because a START op cannot directly precede an END op, else a time out cascade occurs
i2cSetCmd(i2c, cmdIdx++, I2C_CMD_RSTART, 0, false, false, false);
tdq->ctrl.startCmdSent=1;
done = (cmdIdx>14);
}
//CMD WRITE ADDRESS
if((!done)&&(tdq->ctrl.startCmdSent)) { // have to leave room for continue, and START must have been sent!
if((!done)&&(tdq->ctrl.startCmdSent)) { // have to leave room for continue(END), and START must have been sent!
if(!tdq->ctrl.addrCmdSent) {
i2cSetCmd(i2c, cmdIdx++, I2C_CMD_WRITE, tdq->ctrl.addrReq, false, false, true); //load address in cmdlist, validate (low) ack
tdq->ctrl.addrCmdSent=1;
@ -282,26 +300,24 @@ static void IRAM_ATTR fillCmdQueue(i2c_t * i2c, bool INTS)
If END is used, when refilling the cmd[] next time, no entries from END to [15] can be used.
AND the cmd[] must be filled starting at [0] with commands. Either fill all 15 [0]..[14] and leave the
END in [15] or include a STOP in one of the positions [0]..[14]. Any entries after a STOP are IGNORED byte the StateMachine.
END in [15] or include a STOP in one of the positions [0]..[14]. Any entries after a STOP are IGNORED by the StateMachine.
The END operation does not complete until ctr->trans_start=1 has been issued.
So, only refill from [0]..[14], leave [15] for a continuation if necessary.
As a corrilary, once END exists in [15], you do not need to overwrite it for the
So, only refill from [0]..[14], leave [15] for a continuation(END) if necessary.
As a corollary, once END exists in [15], you do not need to overwrite it for the
next continuation. It is never modified. But, I update it every time because it might
actually be the first time!
23NOV17 START cannot proceed END. if START is in[14], END cannot be in [15].
so, AND if END is moved to [14], [14] and [15] can nolonger be use for anything other than END.
So, if END is moved to [14], [14] and [15] can no longer be used for anything other than END.
If a START is found in [14] then a prior READ or WRITE must be expanded so that there is no START element in [14].
*/
if((!done)&&(tdq->ctrl.addrCmdSent)) { //room in command[] for at least One data (read/Write) cmd
uint8_t blkSize=0; // max is 255? does numBytes =0 actually mean 256? haven't tried it.
//log_e("needed=%2d index=%d",*neededRead,cmdIdx);
uint8_t blkSize=0; // max is 255
while(( tdq->cmdBytesNeeded > tdq->ctrl.mode )&&(!done )) { // more bytes needed and room in cmd queue, leave room for END
blkSize = (tdq->cmdBytesNeeded > 255)?255:(tdq->cmdBytesNeeded - tdq->ctrl.mode); // Last read cmd needs different ACK setting, so leave 1 byte remainer on reads
tdq->cmdBytesNeeded -= blkSize; //
blkSize = (tdq->cmdBytesNeeded > 255)?255:(tdq->cmdBytesNeeded - tdq->ctrl.mode); // Last read cmd needs different ACK setting, so leave 1 byte remainder on reads
tdq->cmdBytesNeeded -= blkSize;
if(tdq->ctrl.mode==1) { //read mode
i2cSetCmd(i2c, (cmdIdx)++, I2C_CMD_READ, blkSize,false,false,false); // read cmd, this can't be the last read.
ena_rx=true; // need to enable rxFifo IRQ
@ -341,20 +357,10 @@ static void IRAM_ATTR fillCmdQueue(i2c_t * i2c, bool INTS)
done = false; // reuse it
uint16_t i = 13; // start working back until a READ/WRITE has >1 numBytes
cmdIdx =15;
// log_e("before Stretch");
// dumpCmdQueue(i2c);
while(!done) {
i2c->dev->command[i+1].val = i2c->dev->command[i].val; // push it down
if (((i2c->dev->command[i].op_code == 1)||(i2c->dev->command[i].op_code==2))) {
/* just try a num_bytes =0;
&&(i2c->dev->command[i].byte_num>1)){ // found the one to expand
i2c->dev->command[i+1].byte_num =1;
// the -= in the following statment caused unintential consequences.
// The op_code field value changed from 2 to 4, so the manual cludge was needed
// i2c->dev->command[i].byte_num -= 1;
uint32_t temp = i2c->dev->command[i].val;
temp = (temp&0xFFFFFF00) | ((temp & 0xFF)-1);
i2c->dev->command[i].val = temp;
/* add a dummy read/write cmd[] with num_bytes set to zero,just a place holder in the cmd[]list
*/
i2c->dev->command[i].byte_num = 0;
done = true;
@ -369,18 +375,15 @@ static void IRAM_ATTR fillCmdQueue(i2c_t * i2c, bool INTS)
}
}
}
// log_e("after Stretch");
// dumpCmdQueue(i2c);
}
if(cmdIdx==15) { //need continuation, even if STOP is in 14, it will not matter
// cmd buffer is almost full, Add END as a continuation feature
// log_e("END at %d, left=%d",cmdIdx,neededRead);
i2cSetCmd(i2c, (cmdIdx)++,I2C_CMD_END, 0,false,false,false);
i2c->dev->int_ena.end_detect=1; //maybe?
i2c->dev->int_clr.end_detect=1; //maybe?
i2c->dev->int_ena.end_detect=1;
i2c->dev->int_clr.end_detect=1;
done = true;
}
@ -389,7 +392,6 @@ static void IRAM_ATTR fillCmdQueue(i2c_t * i2c, bool INTS)
qp++;
if(qp < i2c->queueCount) {
tdq = &i2c->dq[qp];
// log_e("inc to next queue=%d",qp);
} else {
done = true;
}
@ -397,7 +399,7 @@ static void IRAM_ATTR fillCmdQueue(i2c_t * i2c, bool INTS)
}
}// while(!done)
if(INTS) { // don't want to prematurely enable fifo ints until ISR is ready to handle it.
if(INTS) { // don't want to prematurely enable fifo ints until ISR is ready to handle them.
if(ena_rx) {
i2c->dev->int_ena.rx_fifo_full = 1;
}
@ -411,18 +413,7 @@ static void IRAM_ATTR fillCmdQueue(i2c_t * i2c, bool INTS)
*/
static void IRAM_ATTR fillTxFifo(i2c_t * i2c)
{
/* need to test overlapping RX->TX fifo operations,
Currently, this function attempts to queue all possible tx elements into the Fifo.
What happens when WRITE 10, READ 20, Write 10?
(Write Addr, Write 10),(Write addr, Read 20) (Write addr, Write 10).
I know everything will work up to the End of the Read 20, but I am unsure
what will happen to the third command, will the Read 20 overwrite the previously
queued (write addr, write 10) of the Third command? I need to test!
*/
/*11/15/2017 will assume that I cannot queue tx after a READ until READ completes
11/23/2017 Seems to be a TX fifo problem, the SM sends 0x40 for last rxbyte, I
enable txEmpty, filltx fires, but the SM has already sent a bogus byte out the BUS.
I am going so see if I can overlap Tx/Rx/Tx in the fifo
/*
12/01/2017 The Fifo's are independent, 32 bytes of tx and 32 bytes of Rx.
overlap is not an issue, just keep them full/empty the status_reg.xx_fifo_cnt
tells the truth. And the INT's fire correctly
@ -476,7 +467,7 @@ static void IRAM_ATTR fillTxFifo(i2c_t * i2c)
}
}
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) && (defined ENABLE_I2C_DEBUG_BUFFER)
// update debug buffer tx counts
cnt += intBuff[intPos[i2c->num]][1][i2c->num]>>16;
@ -489,8 +480,9 @@ static void IRAM_ATTR fillTxFifo(i2c_t * i2c)
}
}
if(!full || (a >= i2c->queueCount)) { // disable IRQ, the next dq will re-enable it
i2c->dev->int_ena.tx_fifo_empty=0;
if(a >= i2c->queueCount ) { // disable IRQ, the next dq will re-enable it
// (a >= i2c->queueCount) means no more data is available
i2c->dev->int_ena.tx_fifo_empty= 0;
}
i2c->dev->int_clr.tx_fifo_empty=1;
@ -501,40 +493,46 @@ static void IRAM_ATTR fillTxFifo(i2c_t * i2c)
static void IRAM_ATTR emptyRxFifo(i2c_t * i2c)
{
uint32_t d, cnt=0, moveCnt;
I2C_DATA_QUEUE_t *tdq =&i2c->dq[i2c->queuePos];
moveCnt = i2c->dev->status_reg.rx_fifo_cnt;//no need to check the reg until this many are read
if(moveCnt > (tdq->length - tdq->position)) { //makesure they go in this dq
while((moveCnt > 0)&&(i2c->queuePos < i2c->queueCount)){ // data to move
I2C_DATA_QUEUE_t *tdq =&i2c->dq[i2c->queuePos]; //short cut
if(tdq->ctrl.mode == 1){ // read command
if(moveCnt > (tdq->length - tdq->position)) { //make sure they go in this dq
// part of these reads go into the next dq
moveCnt = (tdq->length - tdq->position);
}
if(tdq->ctrl.mode==1) { // read
while(moveCnt > 0) {
} else {// error
log_e("RxEmpty(%d) call on TxBuffer? dq=%d",moveCnt,i2c->queuePos);
return;
}
while(moveCnt > 0) {
d = i2c->dev->fifo_data.val;
moveCnt--;
cnt++;
tdq->data[tdq->position++] = (d&0xFF);
}
if(tdq->position >= tdq->length ){ // inc queuePos until next READ command or end of queue
i2c->queuePos++;
while((i2c->queuePos < i2c->queueCount)&&(i2c->dq[i2c->queuePos].ctrl.mode !=1)){
i2c->queuePos++;
}
if(i2c->queuePos < i2c->queueCount){ // found new place to store rx data
tdq = &i2c->dq[i2c->queuePos]; // update shortcut
// see if any more chars showed up while empting Fifo.
moveCnt = i2c->dev->status_reg.rx_fifo_cnt;
if(moveCnt > (tdq->length - tdq->position)) { //makesure they go in this dq
if(moveCnt > (tdq->length - tdq->position)) { //make sure they go in this dq
// part of these reads go into the next dq
moveCnt = (tdq->length - tdq->position);
}
}
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
}
}
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)&& (defined ENABLE_I2C_DEBUG_BUFFER)
// update Debug rxCount
cnt += (intBuff[intPos[i2c->num]][1][i2c->num])&&0xffFF;
intBuff[intPos[i2c->num]][1][i2c->num] = (intBuff[intPos[i2c->num]][1][i2c->num]&0xFFFF0000)|cnt;
#endif
} else {
log_e("RxEmpty(%d) call on TxBuffer? dq=%d",moveCnt,i2c->queuePos);
// dumpI2c(i2c);
}
//log_e("emptied %d",*index);
}
static void IRAM_ATTR i2cIsrExit(i2c_t * i2c,const uint32_t eventCode,bool Fatal)
{
@ -559,19 +557,17 @@ static void IRAM_ATTR i2cIsrExit(i2c_t * i2c,const uint32_t eventCode,bool Fatal
i2c->error = I2C_ERROR;
}
uint32_t exitCode = EVENT_DONE | eventCode |(Fatal?EVENT_ERROR:0);
if(i2c->dq[i2c->queuePos].ctrl.mode == 1) {
if((i2c->queuePos < i2c->queueCount) && (i2c->dq[i2c->queuePos].ctrl.mode == 1)) {
emptyRxFifo(i2c); // grab last few characters
}
i2c->dev->int_ena.val = 0; // shutdown interrupts
i2c->dev->int_clr.val = 0x1FFFF;
i2c->dev->int_ena.val = 0; // shut down interrupts
i2c->dev->int_clr.val = 0x1FFF;
i2c->stage = I2C_DONE;
i2c->exitCode = exitCode; //true eventcode
portBASE_TYPE HPTaskAwoken = pdFALSE,xResult;
// try to notify Dispatch we are done,
// else the 50ms timeout will recover the APP, just alittle slower
// else the 50ms time out will recover the APP, just a little slower
HPTaskAwoken = pdFALSE;
xResult = xEventGroupSetBitsFromISR(i2c->i2c_event, exitCode, &HPTaskAwoken);
if(xResult == pdPASS) {
@ -582,22 +578,79 @@ static void IRAM_ATTR i2cIsrExit(i2c_t * i2c,const uint32_t eventCode,bool Fatal
}
}
/* i2c_update_error_byte_cnt 07/18/2018
Only called after an error has occurred, so, most of the time this function is never used.
This function obliterates the need to interrupt monitor each byte transferred, at high bitrates
the byte interrupts were overwhelming the OS. Spurious Interrupts were being generated.
it update errorByteCnt, errorQueue.
*/
static void IRAM_ATTR i2c_update_error_byte_cnt(i2c_t * i2c)
{
uint16_t a=0; // start at top of DQ, count how many bytes added to tx fifo, and received from rx_fifo.
uint16_t bc = 0;
I2C_DATA_QUEUE_t *tdq;
i2c->errorByteCnt = 0;
while( a < i2c->queueCount){ // add up all bytes loaded into fifo's
tdq = &i2c->dq[a];
i2c->errorByteCnt += tdq->ctrl.addrSent;
i2c->errorByteCnt += tdq->position;
a++;
}
// log_v("errorByteCnt=%d",i2c->errorByteCnt);
// now errorByteCnt contains total bytes moved into and out of FIFO's
// but, there may still be bytes waiting in Fifo's
i2c->errorByteCnt -= i2c->dev->status_reg.tx_fifo_cnt; // waiting to go out;
i2c->errorByteCnt += i2c->dev->status_reg.rx_fifo_cnt; // already received
// now walk thru DQ again, find which byte is 'current'
bool done = false;
bc = i2c->errorByteCnt;
i2c->errorQueue = 0;
while(( i2c->errorQueue < i2c->queueCount)&&( !done )){
tdq = &i2c->dq[i2c->errorQueue];
if(bc>0){ // not found yet
if( tdq->ctrl.addrSent >= bc){ // in address
done = true;
continue;
} else {
bc -= tdq->ctrl.addrSent;
if( tdq->position >= bc) { // data nak
done = true;
continue;
} else { // count down
bc -= tdq->position;
}
}
} else {
done= true;
continue;
}
i2c->errorQueue++;
}
// log_v("errorByteCnt=%d errorQueue=%d",i2c->errorByteCnt,i2c->errorQueue);
i2c->errorByteCnt = bc;
}
static void IRAM_ATTR i2c_isr_handler_default(void* arg)
{
i2c_t* p_i2c = (i2c_t*) arg; // recover data
uint32_t activeInt = p_i2c->dev->int_status.val&0x1FFF;
uint32_t activeInt = p_i2c->dev->int_status.val&0x7FF;
//portBASE_TYPE HPTaskAwoken = pdFALSE,xResult;
if(p_i2c->stage==I2C_DONE) { //get Out
log_e("eject int=%p, ena=%p",activeInt,p_i2c->dev->int_ena.val);
if(p_i2c->stage==I2C_DONE) { //get Out, can't service, not configured
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
uint32_t raw = p_i2c->dev->int_raw.val;
#endif
p_i2c->dev->int_ena.val = 0;
p_i2c->dev->int_clr.val = activeInt; //0x1FFF;
p_i2c->dev->int_clr.val = 0x1FFF;
log_v("eject raw=%p, int=%p",raw,activeInt);
return;
}else if(!activeInt){ //spurious interrupt, possibly bus relate 20180711
log_v("r=0x%x s=0x%x %d",p_i2c->dev->int_raw.val,p_i2c->dev->int_status.val,p_i2c->stage);
}
while (activeInt != 0) { // Ordering of 'if(activeInt)' statements is important, don't change
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) && (defined ENABLE_I2C_DEBUG_BUFFER)
if(activeInt==(intBuff[intPos[p_i2c->num]][0][p_i2c->num]&0x1fff)) {
intBuff[intPos[p_i2c->num]][0][p_i2c->num] = (((intBuff[intPos[p_i2c->num]][0][p_i2c->num]>>16)+1)<<16)|activeInt;
} else {
@ -610,10 +663,8 @@ static void IRAM_ATTR i2c_isr_handler_default(void* arg)
intBuff[intPos[p_i2c->num]][2][p_i2c->num] = xTaskGetTickCountFromISR(); // when IRQ fired
#endif
//uint32_t oldInt =activeInt;
if (activeInt & I2C_TRANS_START_INT_ST_M) {
// p_i2c->byteCnt=0;
if(p_i2c->stage==I2C_STARTUP) {
p_i2c->stage=I2C_RUNNING;
}
@ -636,40 +687,14 @@ static void IRAM_ATTR i2c_isr_handler_default(void* arg)
activeInt &=~I2C_RXFIFO_FULL_INT_ST;
}
if(activeInt & I2C_MASTER_TRAN_COMP_INT_ST) { // each byte the master sends/recv
p_i2c->dev->int_clr.master_tran_comp = 1;
p_i2c->byteCnt++;
if(p_i2c->byteCnt > p_i2c->dq[p_i2c->queuePos].queueLength) { // simulate Trans_start
p_i2c->byteCnt -= p_i2c->dq[p_i2c->queuePos].queueLength;
if(p_i2c->dq[p_i2c->queuePos].ctrl.mode==1) { // grab last characters for this dq
emptyRxFifo(p_i2c);
p_i2c->dev->int_clr.rx_fifo_full=1;
p_i2c->dev->int_ena.rx_fifo_full=1;
}
p_i2c->queuePos++; //inc to next dq
if(p_i2c->queuePos < p_i2c->queueCount) { // load next dq address field + data
p_i2c->dev->int_ena.tx_fifo_empty=1;
}
}
activeInt &=~I2C_MASTER_TRAN_COMP_INT_ST;
}
if (activeInt & I2C_ACK_ERR_INT_ST_M) {//fatal error, abort i2c service
if (p_i2c->mode == I2C_MASTER) {
// log_e("AcK Err byteCnt=%d, queuepos=%d",p_i2c->byteCnt,p_i2c->queuePos);
if(p_i2c->byteCnt==1) {
i2cIsrExit(p_i2c,EVENT_ERROR_NAK,true);
} else if((p_i2c->byteCnt == 2) && (p_i2c->dq[p_i2c->queuePos].ctrl.addrReq == 2)) {
i2c_update_error_byte_cnt(p_i2c); // calc which byte caused ack Error, check if address or data
log_v("AcK Err errorByteCnt=%d, errorQueue=%d queuepos=%d",p_i2c->errorByteCnt,p_i2c->errorQueue, p_i2c->queuePos);
if(p_i2c->errorByteCnt <= p_i2c->dq[p_i2c->errorQueue].ctrl.addrReq) { // address
i2cIsrExit(p_i2c,EVENT_ERROR_NAK,true);
} else {
i2cIsrExit(p_i2c,EVENT_ERROR_DATA_NAK,true);
i2cIsrExit(p_i2c,EVENT_ERROR_DATA_NAK,true); //data
}
}
return;
@ -680,9 +705,15 @@ static void IRAM_ATTR i2c_isr_handler_default(void* arg)
// the Statemachine only has a 13.1ms max timout, some Devices >500ms
p_i2c->dev->int_clr.time_out =1;
activeInt &=~I2C_TIME_OUT_INT_ST;
// since a timeout occurred, capture the rxFifo data
emptyRxFifo(p_i2c);
p_i2c->dev->int_clr.rx_fifo_full=1;
p_i2c->dev->int_ena.rx_fifo_full=1; //why?
}
if (activeInt & I2C_TRANS_COMPLETE_INT_ST_M) {
p_i2c->dev->int_clr.trans_complete = 1;
i2cIsrExit(p_i2c,EVENT_DONE,false);
return; // no more work to do
/*
@ -729,7 +760,7 @@ functional with Silicon date=0x16042000
static i2c_err_t i2cAddQueue(i2c_t * i2c,uint8_t mode, uint16_t i2cDeviceAddr, uint8_t *dataPtr, uint16_t dataLen,bool sendStop, EventGroupHandle_t event)
{
// need to grab a MUTEX for exclusive Queue,
// what out if ISR is running?
// what about if ISR is running?
if(i2c==NULL) {
return I2C_ERROR_DEV;
@ -745,7 +776,6 @@ static i2c_err_t i2cAddQueue(i2c_t * i2c,uint8_t mode, uint16_t i2cDeviceAddr, u
dqx.ctrl.mode = mode;
dqx.ctrl.stop= sendStop;
dqx.ctrl.addrReq = ((i2cDeviceAddr&0xFC00)==0x7800)?2:1; // 10bit or 7bit address
dqx.queueLength = dataLen + dqx.ctrl.addrReq;
dqx.queueEvent = event;
if(event) { // an eventGroup exist, so, initialize it
@ -788,7 +818,7 @@ i2c_err_t i2cAddQueueRead(i2c_t * i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr,
// readBit.
// this might cause an internal register pointer problem with 10bit
// devices, But, Don't have any to test agains.
// devices, But, Don't have any to test against.
// this is the Industry Standard specification.
if((i2cDeviceAddr &0xFC00)==0x7800) { // ten bit read
@ -839,7 +869,7 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
*/
i2c->stage = I2C_DONE; // until ready
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) && (defined ENABLE_I2C_DEBUG_BUFFER)
for(uint16_t i=0; i<INTBUFFMAX; i++) {
intBuff[i][0][i2c->num] = 0;
intBuff[i][1][i2c->num] = 0;
@ -863,30 +893,14 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
i2c_err_t reason = I2C_ERROR_OK;
i2c->mode = I2C_MASTER;
i2c->dev->ctr.trans_start=0; // Pause Machine
i2c->dev->timeout.tout = 0xFFFFF; // max 13ms
I2C_FIFO_CONF_t f;
f.val = i2c->dev->fifo_conf.val;
f.rx_fifo_rst = 1; // fifo in reset
f.tx_fifo_rst = 1; // fifo in reset
f.nonfifo_en = 0; // use fifo mode
// need to adjust threshold based on I2C clock rate, at 100k, 30 usually works,
// sometimes the emptyRx() actually moves 31 bytes
// it hasn't overflowed yet, I cannot tell if the new byte is added while
// emptyRX() is executing or before?
f.rx_fifo_full_thrhd = 30; // 30 bytes before INT is issued
f.fifo_addr_cfg_en = 0; // no directed access
i2c->dev->fifo_conf.val = f.val; // post them all
i2c->dev->int_clr.val = 0x1FFF; // kill them All!
f.rx_fifo_rst = 0; // release fifo
f.tx_fifo_rst = 0;
i2c->dev->fifo_conf.val = f.val; // post them all
i2c->dev->int_clr.val = 0xFFFFFFFF; // kill them All!
i2c->dev->ctr.ms_mode = 1; // master!
i2c->queuePos=0;
i2c->byteCnt=0;
i2c->errorByteCnt=0;
i2c->errorQueue = 0;
uint32_t totalBytes=0; // total number of bytes to be Moved!
// convert address field to required I2C format
while(i2c->queuePos < i2c->queueCount) { // need to push these address modes upstream, to AddQueue
@ -901,26 +915,48 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
|tdq->ctrl.mode;
}
tdq->ctrl.addr = taddr; // all fixed with R/W bit
totalBytes += tdq->queueLength; // total number of byte to be moved!
totalBytes += tdq->length + tdq->ctrl.addrReq; // total number of byte to be moved!
}
i2c->queuePos=0;
fillCmdQueue(i2c,false); // don't enable Tx/RX irq's
// start adding command[], END irq will keep it full
//Data Fifo will be filled after trans_start is issued
i2c->exitCode=0;
I2C_FIFO_CONF_t f;
f.val = i2c->dev->fifo_conf.val;
f.rx_fifo_rst = 1; // fifo in reset
f.tx_fifo_rst = 1; // fifo in reset
f.nonfifo_en = 0; // use fifo mode
f.nonfifo_tx_thres = 31;
// need to adjust threshold based on I2C clock rate, at 100k, 30 usually works,
// sometimes the emptyRx() actually moves 31 bytes
// it hasn't overflowed yet, I cannot tell if the new byte is added while
// emptyRX() is executing or before?
// let i2cSetFrequency() set thrhds
// f.rx_fifo_full_thrhd = 30; // 30 bytes before INT is issued
// f.tx_fifo_empty_thrhd = 0;
f.fifo_addr_cfg_en = 0; // no directed access
i2c->dev->fifo_conf.val = f.val; // post them all
f.rx_fifo_rst = 0; // release fifo
f.tx_fifo_rst = 0;
i2c->dev->fifo_conf.val = f.val; // post them all
i2c->stage = I2C_STARTUP; // everything configured, now start the I2C StateMachine, and
// As soon as interrupts are enabled, the ISR will start handling them.
// it should receive a TXFIFO_EMPTY immediately, even before it
// receives the TRANS_START
i2c->dev->int_ena.val =
I2C_ACK_ERR_INT_ENA | // (BIT(10)) Causes Fatal Error Exit
I2C_TRANS_START_INT_ENA | // (BIT(9)) Triggered by trans_start=1, initial,END
I2C_TIME_OUT_INT_ENA | //(BIT(8)) Trigger by SLAVE SCL stretching, NOT an ERROR
I2C_TRANS_COMPLETE_INT_ENA | // (BIT(7)) triggered by STOP, successful exit
I2C_MASTER_TRAN_COMP_INT_ENA | // (BIT(6)) counts each byte xfer'd, inc's queuePos
// I2C_MASTER_TRAN_COMP_INT_ENA | // (BIT(6)) counts each byte xfer'd, inc's queuePos
I2C_ARBITRATION_LOST_INT_ENA | // (BIT(5)) cause fatal error exit
I2C_SLAVE_TRAN_COMP_INT_ENA | // (BIT(4)) unhandled
I2C_END_DETECT_INT_ENA | // (BIT(3)) refills cmd[] list
@ -936,9 +972,9 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
ESP_INTR_FLAG_LOWMED; //< Low and medium prio interrupts. These can be handled in C.
if(i2c->num) {
ret = esp_intr_alloc_intrstatus(ETS_I2C_EXT1_INTR_SOURCE, flags, (uint32_t)&i2c->dev->int_status.val, 0x1FFF, &i2c_isr_handler_default,i2c, &i2c->intr_handle);
ret = esp_intr_alloc_intrstatus(ETS_I2C_EXT1_INTR_SOURCE, flags, (uint32_t)&i2c->dev->int_status.val, 0x7FF, &i2c_isr_handler_default,i2c, &i2c->intr_handle);
} else {
ret = esp_intr_alloc_intrstatus(ETS_I2C_EXT0_INTR_SOURCE, flags, (uint32_t)&i2c->dev->int_status.val, 0x1FFF, &i2c_isr_handler_default,i2c, &i2c->intr_handle);
ret = esp_intr_alloc_intrstatus(ETS_I2C_EXT0_INTR_SOURCE, flags, (uint32_t)&i2c->dev->int_status.val, 0x7FF, &i2c_isr_handler_default,i2c, &i2c->intr_handle);
}
if(ret!=ESP_OK) {
@ -950,28 +986,26 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
//hang until it completes.
// how many ticks should it take to transfer totalBytes thru the I2C hardware,
// add user supplied timeOutMillis to Calc Value
// how many ticks should it take to transfer totalBytes through the I2C hardware,
// add user supplied timeOutMillis to Calculated Value
portTickType ticksTimeOut = ((totalBytes*10*1000)/(i2cGetFrequency(i2c))+timeOutMillis)/portTICK_PERIOD_MS;
//log_e("before startup @tick=%d will wait=%d",xTaskGetTickCount(),ticksTimeOut);
i2c->dev->ctr.trans_start=1; // go for it
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
portTickType tBefore=xTaskGetTickCount();
#endif
uint32_t eBits = xEventGroupWaitBits(i2c->i2c_event,EVENT_DONE,pdFALSE,pdTRUE,ticksTimeOut);
// wait for ISR to complete the transfer, or until timeOut in case of bus fault, hardware problem
//log_e("after WaitBits=%x @tick=%d",eBits,xTaskGetTickCount());
uint32_t eBits = xEventGroupWaitBits(i2c->i2c_event,EVENT_DONE,pdFALSE,pdTRUE,ticksTimeOut);
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
portTickType tAfter=xTaskGetTickCount();
#endif
uint32_t b;
// if xEventGroupSetBitsFromISR() failed, the ISR could have succeeded but never been
// able to mark the success
@ -979,26 +1013,18 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
// log_e("EventGroup Failed:%p!=%p",eBits,i2c->exitCode);
eBits=i2c->exitCode;
}
if((eBits&EVENT_ERROR)||(!(eBits & EVENT_DONE))){ // need accurate errorByteCnt for debug
i2c_update_error_byte_cnt(i2c);
}
if(!(eBits==EVENT_DONE)&&(eBits&~(EVENT_ERROR_NAK|EVENT_ERROR_DATA_NAK|EVENT_ERROR|EVENT_DONE))) { // not only Done, therefore error, exclude ADDR NAK, DATA_NAK
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
i2cDumpI2c(i2c);
i2cDumpInts(i2c->num);
#else
log_n("I2C exitCode=0x%x",eBits);
#endif
}
if(eBits&EVENT_DONE) { // no gross timeout
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
uint32_t expected =(totalBytes*10*1000)/i2cGetFrequency(i2c);
if((tAfter-tBefore)>(expected+1)) { //used some of the timeout Period
// expected can be zero due to small packets
log_e("TimeoutRecovery: expected=%ums, actual=%ums",expected,(tAfter-tBefore));
i2cDumpI2c(i2c);
i2cDumpInts(i2c->num);
}
#endif
switch(i2c->error) {
case I2C_OK :
reason = I2C_ERROR_OK;
@ -1025,11 +1051,12 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
i2c->stage = I2C_DONE;
i2c->dev->int_ena.val =0;
i2c->dev->int_clr.val = 0x1FFF;
if((i2c->queuePos==0)&&(i2c->byteCnt==0)) { // Bus Busy no bytes Moved
i2c_update_error_byte_cnt(i2c);
if(i2c->errorByteCnt == 0) { // Bus Busy no bytes Moved
reason = I2C_ERROR_BUSY;
eBits = eBits | EVENT_ERROR_BUS_BUSY|EVENT_ERROR|EVENT_DONE;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
log_e(" Busy Timeout start=0x%x, end=0x%x, =%d, max=%d error=%d",tBefore,tAfter,(tAfter-tBefore),ticksTimeOut,i2c->error);
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
log_d(" Busy Timeout start=0x%x, end=0x%x, =%d, max=%d error=%d",tBefore,tAfter,(tAfter-tBefore),ticksTimeOut,i2c->error);
i2cDumpI2c(i2c);
i2cDumpInts(i2c->num);
#endif
@ -1037,19 +1064,25 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
reason = I2C_ERROR_TIMEOUT;
eBits = eBits | EVENT_ERROR_TIMEOUT|EVENT_ERROR|EVENT_DONE;
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
log_e(" Gross Timeout Dead start=0x%x, end=0x%x, =%d, max=%d error=%d",tBefore,tAfter,(tAfter-tBefore),ticksTimeOut,i2c->error);
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
log_d(" Gross Timeout Dead start=0x%x, end=0x%x, =%d, max=%d error=%d",tBefore,tAfter,(tAfter-tBefore),ticksTimeOut,i2c->error);
i2cDumpI2c(i2c);
i2cDumpInts(i2c->num);
#endif
}
}
// offloading all EventGroups to dispatch, EventGroups in ISR is not always successful
// 11/20/2017
// if error, need to trigger all succeeding dataQueue events with the EVENT_ERROR_PREV
b = 0;
/* offloading all EventGroups to dispatch, EventGroups in ISR is not always successful
11/20/2017
if error, need to trigger all succeeding dataQueue events with the EVENT_ERROR_PREV
07/22/2018
Need to use the queueEvent value to identify transaction blocks, if an error occurs,
all subsequent queue items with the same queueEvent value will receive the EVENT_ERROR_PREV.
But, ProcQue should re-queue queue items that have a different queueEvent value(different transaction)
This change will support multi-thread i2c usage. Use the queueEvent as the transaction event
identifier.
*/
uint32_t b = 0;
while(b < i2c->queueCount) {
if(i2c->dq[b].ctrl.mode==1 && readCount) {
@ -1168,6 +1201,7 @@ i2c_err_t i2cDetachSDA(i2c_t * i2c, int8_t sda)
// 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
{
log_v("num=%d sda=%d scl=%d freq=%d",i2c_num, sda, scl, frequency);
if(i2c_num > 1) {
return NULL;
}
@ -1335,12 +1369,23 @@ 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 halfPeriod = period/2;
uint32_t quarterPeriod = period/4;
I2C_MUTEX_LOCK();
// Adjust Fifo thresholds based on frequency
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;
i2c->dev->fifo_conf.val = f.val; // set thresholds
log_v("Fifo threshold=%d",a);
//the clock num during SCL is low level
i2c->dev->scl_low_period.period = period;
//the clock num during SCL is high level
@ -1390,7 +1435,12 @@ void i2cDumpDqData(i2c_t * i2c)
I2C_DATA_QUEUE_t *tdq;
while(a<i2c->queueCount) {
tdq=&i2c->dq[a];
log_e("[%d] %x %c %s buf@=%p, len=%d, pos=%d, eventH=%p bits=%x",a,tdq->ctrl.addr,(tdq->ctrl.mode)?'R':'W',(tdq->ctrl.stop)?"STOP":"",tdq->data,tdq->length,tdq->position,tdq->queueEvent,(tdq->queueEvent)?xEventGroupGetBits(tdq->queueEvent):0);
log_e("[%d] %sbit %x %c %s buf@=%p, len=%d, pos=%d, eventH=%p bits=%x",a,
(tdq->ctrl.addr>0x100)?"10":"7",
(tdq->ctrl.addr>0x100)?(((tdq->ctrl.addr&0x600)>>1)|(tdq->ctrl.addr&0xff)):(tdq->ctrl.addr>>1),
(tdq->ctrl.mode)?'R':'W',
(tdq->ctrl.stop)?"STOP":"",
tdq->data,tdq->length,tdq->position,tdq->queueEvent,(tdq->queueEvent)?xEventGroupGetBits(tdq->queueEvent):0);
uint16_t offset = 0;
while(offset<tdq->length) {
memset(buff,' ',140);
@ -1412,8 +1462,6 @@ void i2cDumpDqData(i2c_t * i2c)
}
a++;
}
#else
log_n("Enable Core Debug Level \"Error\"");
#endif
}
@ -1433,7 +1481,8 @@ void i2cDumpI2c(i2c_t * i2c)
log_e("dq=%p",i2c->dq);
log_e("queueCount=%d",i2c->queueCount);
log_e("queuePos=%d",i2c->queuePos);
log_e("byteCnt=%d",i2c->byteCnt);
log_e("errorByteCnt=%d",i2c->errorByteCnt);
log_e("errorQueue=%d",i2c->errorQueue);
if(i2c->dq) {
i2cDumpDqData(i2c);
}
@ -1441,7 +1490,8 @@ void i2cDumpI2c(i2c_t * i2c)
void i2cDumpInts(uint8_t num)
{
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO) && (defined ENABLE_I2C_DEBUG_BUFFER)
uint32_t b;
log_e("%u row count INTR TX RX",num);
for(uint32_t a=1; a<=INTBUFFMAX; a++) {
@ -1451,15 +1501,15 @@ void i2cDumpInts(uint8_t num)
}
}
#else
log_n("enable Core Debug Level \"Error\"");
log_i("Debug Buffer not Enabled");
#endif
}
/* todo
24Nov17
Need to think about not usings I2C_MASTER_TRAN_COMP_INT_ST to adjust queuePos. This
INT triggers every byte. The only reason to know which byte is being transfered is
the status_reg.tx_fifo_cnt and a .txQueued to do this in the fillRxFifo(). The
same mechanism could work if an error occured in i2cErrorExit().
22JUL18
need to add multi-thread capability, use dq.queueEvent as the group marker. When multiple threads
transactions are present in the same queue, and an error occurs, abort all succeeding unserviced transactions
with the same dq.queueEvent value. Succeeding unserviced transactions with different dq.queueEvent values
can be re-queued and processed independently.
*/

View File

@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "esp32-hal.h"
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@ -24,6 +23,7 @@
#include "esp_timer.h"
#include "esp_bt.h"
#include <sys/time.h>
#include "esp32-hal.h"
//Undocumented!!! Get chip temperature in Farenheit
//Source: https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_int_temp_sensor/ESP32_int_temp_sensor.ino
@ -84,6 +84,9 @@ bool btInUse(){ return false; }
void initArduino()
{
#if CONFIG_SPIRAM_SUPPORT
psramInit();
#endif
esp_log_level_set("*", CONFIG_LOG_DEFAULT_LEVEL);
esp_err_t err = nvs_flash_init();
if(err == ESP_ERR_NVS_NO_FREE_PAGES){

View File

@ -0,0 +1,98 @@
#include "esp32-hal.h"
#if CONFIG_SPIRAM_SUPPORT
#include "esp_spiram.h"
#include "soc/efuse_reg.h"
#include "esp_heap_caps.h"
static volatile bool spiramDetected = false;
static volatile bool spiramFailed = false;
bool psramInit(){
if (spiramDetected) {
return true;
}
#ifndef CONFIG_SPIRAM_BOOT_INIT
if (spiramFailed) {
return false;
}
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) {
spiramFailed = true;
log_w("PSRAM not supported!");
return false;
}
esp_spiram_init_cache();
if (esp_spiram_init() != ESP_OK) {
spiramFailed = true;
log_w("PSRAM init failed!");
pinMatrixOutDetach(16, false, false);
pinMatrixOutDetach(17, false, false);
return false;
}
if (!esp_spiram_test()) {
spiramFailed = true;
log_e("PSRAM test failed!");
return false;
}
if (esp_spiram_add_to_heapalloc() != ESP_OK) {
spiramFailed = true;
log_e("PSRAM could not be added to the heap!");
return false;
}
#endif
spiramDetected = true;
log_d("PSRAM enabled");
return true;
}
bool IRAM_ATTR psramFound(){
return spiramDetected;
}
void IRAM_ATTR *ps_malloc(size_t size){
if(!spiramDetected){
return NULL;
}
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
}
void IRAM_ATTR *ps_calloc(size_t n, size_t size){
if(!spiramDetected){
return NULL;
}
return heap_caps_calloc(n, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
}
void IRAM_ATTR *ps_realloc(void *ptr, size_t size){
if(!spiramDetected){
return NULL;
}
return heap_caps_realloc(ptr, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
}
#else
bool psramInit(){
return false;
}
bool IRAM_ATTR psramFound(){
return false;
}
void IRAM_ATTR *ps_malloc(size_t size){
return NULL;
}
void IRAM_ATTR *ps_calloc(size_t n, size_t size){
return NULL;
}
void IRAM_ATTR *ps_realloc(void *ptr, size_t size){
return NULL;
}
#endif

View File

@ -0,0 +1,33 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESP32_HAL_PSRAM_H_
#define _ESP32_HAL_PSRAM_H_
#ifdef __cplusplus
extern "C" {
#endif
bool psramInit();
bool psramFound();
void *ps_malloc(size_t size);
void *ps_calloc(size_t n, size_t size);
void *ps_realloc(void *ptr, size_t size);
#ifdef __cplusplus
}
#endif
#endif /* _ESP32_HAL_PSRAM_H_ */

View File

@ -315,11 +315,14 @@ void uartFlush(uart_t* uart)
UART_MUTEX_LOCK();
while(uart->dev->status.txfifo_cnt);
uart->dev->conf0.txfifo_rst = 1;
uart->dev->conf0.txfifo_rst = 0;
//Due to hardware issue, we can not use fifo_rst to reset uart fifo.
//See description about UART_TXFIFO_RST and UART_RXFIFO_RST in <<esp32_technical_reference_manual>> v2.6 or later.
// we read the data out and make `fifo_len == 0 && rd_addr == wr_addr`.
while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
READ_PERI_REG(UART_FIFO_REG(uart->num));
}
uart->dev->conf0.rxfifo_rst = 1;
uart->dev->conf0.rxfifo_rst = 0;
UART_MUTEX_UNLOCK();
}

View File

@ -33,6 +33,7 @@ extern "C" {
#include <string.h>
#include <math.h>
#include "sdkconfig.h"
#include "esp_system.h"
#ifndef F_CPU
#define F_CPU (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ * 1000000U)
@ -59,7 +60,13 @@ void yield(void);
#include "esp32-hal-sigmadelta.h"
#include "esp32-hal-timer.h"
#include "esp32-hal-bt.h"
#include "esp_system.h"
#include "esp32-hal-psram.h"
#ifndef BOARD_HAS_PSRAM
#ifdef CONFIG_SPIRAM_SUPPORT
#undef CONFIG_SPIRAM_SUPPORT
#endif
#endif
//returns chip temperature in Celsius
float temperatureRead();

View File

@ -0,0 +1,59 @@
# Over the Air through Web browser
OTAWebUpdate is done with a web browser that can be useful in the following typical scenarios:
- Once the application developed and loading directly from Arduino IDE is inconvenient or not possible
- after deployment if user is unable to expose Firmware for OTA from external update server
- provide updates after deployment to small quantity of modules when setting an update server is not practicable
## Requirements
- The ESP and the computer must be connected to the same network
## Implementation
The sample implementation has been done using:
- example sketch OTAWebUpdater.ino
- ESP32 (Dev Module)
You can use another module also if it meets Flash chip size of the sketch
1-Before you begin, please make sure that you have the following software installed:
- Arduino IDE
- Host software depending on O/S you use:
- Avahi http://avahi.org/ for Linux
- Bonjour http://www.apple.com/support/bonjour/ for Windows
- Mac OSX and iOS - support is already built in / no any extra s/w is required
Prepare the sketch and configuration for initial upload with a serial port
- Start Arduino IDE and load sketch OTAWebUpdater.ino available under File > Examples > OTAWebUpdater.ino
- Update ssid and pass in the sketch so the module can join your Wi-Fi network
- Open File > Preferences, look for “Show verbose output during:” and check out “compilation” option
![verbrose](esp32verbose.PNG)
- Upload sketch (Ctrl+U)
- Now open web browser and enter the url, i.e. http://esp32.local. Once entered, browser should display a form
![login](esp32login.PNG)
> username= admin
> password= admin
**Note**-*If entering “http://ESP32.local” does not work, try replacing “ESP32” with modules IP address.This workaround is useful in case the host software installed does not work*.
Now click on Login button and browser will display a upload form
![upload](esp32upload.PNG)
For Uploading the New Firmware you need to provide the Binary File of your Code.
Exporting Binary file of the Firmware (Code)
- Open up the Arduino IDE
- Open up the Code, for Exporting up Binary file
- Now go to Sketch > export compiled Binary
![export](exportTobinary.PNG)
- Binary file is exported to the same Directory where your code is present
Once you are comfortable with this procedure go ahead and modify OTAWebUpdater.ino sketch to print some additional messages, compile it, Export new binary file and upload it using web browser to see entered changes on a Serial Monitor

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,15 @@
Installation instructions using Arduino IDE Boards Manager
==========================================================
Starting with 1.6.4, Arduino allows installation of third-party platform packages using Boards Manager. We have packages available for Windows, Mac OS, and Linux (32 and 64 bit).
- Install the current upstream Arduino IDE at the 1.8 level or later. The current version is at the [Arduino website](http://www.arduino.cc/en/main/software).
- Start Arduino and open Preferences window.
- Enter ```https://dl.espressif.com/dl/package_esp32_index.json``` into *Additional Board Manager URLs* field. You can add multiple URLs, separating them with commas.
- Open Boards Manager from Tools > Board menu and install *esp32* platform (and don't forget to select your ESP32 board from Tools > Board menu after installation).
#### [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/)
Stable release link: `https://dl.espressif.com/dl/package_esp32_index.json`
#### [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/)
Development release link: `https://dl.espressif.com/dl/package_esp32_dev_index.json`

View File

@ -0,0 +1,168 @@
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>
const char* host = "esp32";
const char* ssid = "xxx";
const char* password = "xxxx";
WebServer server(80);
/*
* Login page
*/
const char* loginIndex =
"<form name='loginForm'>"
"<table width='20%' bgcolor='A09F9F' align='center'>"
"<tr>"
"<td colspan=2>"
"<center><font size=4><b>ESP32 Login Page</b></font></center>"
"<br>"
"</td>"
"<br>"
"<br>"
"</tr>"
"<td>Username:</td>"
"<td><input type='text' size=25 name='userid'><br></td>"
"</tr>"
"<br>"
"<br>"
"<tr>"
"<td>Password:</td>"
"<td><input type='Password' size=25 name='pwd'><br></td>"
"<br>"
"<br>"
"</tr>"
"<tr>"
"<td><input type='submit' onclick='check(this.form)' value='Login'></td>"
"</tr>"
"</table>"
"</form>"
"<script>"
"function check(form)"
"{"
"if(form.userid.value=='admin' && form.pwd.value=='admin')"
"{"
"window.open('/serverIndex')"
"}"
"else"
"{"
" alert('Error Password or Username')/*displays error message*/"
"}"
"}"
"</script>";
/*
* Server Index Page
*/
const char* serverIndex =
"<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"
"<input type='file' name='update'>"
"<input type='submit' value='Update'>"
"</form>"
"<div id='prg'>progress: 0%</div>"
"<script>"
"$('form').submit(function(e){"
"e.preventDefault();"
"var form = $('#upload_form')[0];"
"var data = new FormData(form);"
" $.ajax({"
"url: '/update',"
"type: 'POST',"
"data: data,"
"contentType: false,"
"processData:false,"
"xhr: function() {"
"var xhr = new window.XMLHttpRequest();"
"xhr.upload.addEventListener('progress', function(evt) {"
"if (evt.lengthComputable) {"
"var per = evt.loaded / evt.total;"
"$('#prg').html('progress: ' + Math.round(per*100) + '%');"
"}"
"}, false);"
"return xhr;"
"},"
"success:function(d, s) {"
"console.log('success!')"
"},"
"error: function (a, b, c) {"
"}"
"});"
"});"
"</script>";
/*
* setup function
*/
void setup(void) {
Serial.begin(115200);
// Connect to WiFi network
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
/*use mdns for host name resolution*/
if (!MDNS.begin(host)) { //http://esp32.local
Serial.println("Error setting up MDNS responder!");
while (1) {
delay(1000);
}
}
Serial.println("mDNS responder started");
/*return index page which is stored in serverIndex */
server.on("/", HTTP_GET, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", loginIndex);
});
server.on("/serverIndex", HTTP_GET, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", serverIndex);
});
/*handling uploading firmware file */
server.on("/update", HTTP_POST, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
ESP.restart();
}, []() {
HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
Serial.printf("Update: %s\n", upload.filename.c_str());
if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_WRITE) {
/* flashing firmware to ESP*/
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) { //true to set the size to the current progress
Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
} else {
Update.printError(Serial);
}
}
});
server.begin();
}
void loop(void) {
server.handleClient();
delay(1);
}

View File

@ -9,7 +9,7 @@
#include "Update.h"
//#define OTA_DEBUG Serial
// #define OTA_DEBUG Serial
ArduinoOTAClass::ArduinoOTAClass()
: _port(0)
@ -20,6 +20,7 @@ ArduinoOTAClass::ArduinoOTAClass()
, _size(0)
, _cmd(0)
, _ota_port(0)
, _ota_timeout(1000)
, _start_callback(NULL)
, _end_callback(NULL)
, _error_callback(NULL)
@ -260,8 +261,9 @@ void ArduinoOTAClass::_runUpdate() {
}
uint32_t written = 0, total = 0, tried = 0;
while (!Update.isFinished() && client.connected()) {
size_t waited = 1000;
size_t waited = _ota_timeout;
size_t available = client.available();
while (!available && waited){
delay(1);
@ -387,6 +389,10 @@ int ArduinoOTAClass::getCommand() {
return _cmd;
}
void ArduinoOTAClass::setTimeout(int timeoutInMillis) {
_ota_timeout = timeoutInMillis;
}
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_ARDUINOOTA)
ArduinoOTAClass ArduinoOTA;
#endif

View File

@ -7,7 +7,6 @@
#define INT_BUFFER_SIZE 16
typedef enum {
OTA_IDLE,
OTA_WAITAUTH,
@ -75,6 +74,8 @@ class ArduinoOTAClass
//Gets update command type after OTA has started. Either U_FLASH or U_SPIFFS
int getCommand();
void setTimeout(int timeoutInMillis);
private:
int _port;
String _password;
@ -88,6 +89,7 @@ class ArduinoOTAClass
int _size;
int _cmd;
int _ota_port;
int _ota_timeout;
IPAddress _ota_ip;
String _md5;

View File

@ -286,6 +286,8 @@ AsyncUDPPacket::AsyncUDPPacket(AsyncUDP *udp, pbuf *pb, const ip_addr_t *raddr,
_len = pb->len;
_index = 0;
pbuf_ref(_pb);
//memcpy(&_remoteIp, raddr, sizeof(ip_addr_t));
_remoteIp.type = raddr->type;
_localIp.type = _remoteIp.type;

View File

@ -136,6 +136,16 @@ static bool _init_bt(const char *deviceName)
}
esp_bt_dev_set_device_name(deviceName);
// the default BTA_DM_COD_LOUDSPEAKER does not work with the macOS BT stack
esp_bt_cod_t cod;
cod.major = 0b00001;
cod.minor = 0b000100;
cod.service = 0b00000010110;
if (esp_bt_gap_set_cod(cod, ESP_BT_INIT_COD) != ESP_OK) {
log_e("%s set cod failed\n", __func__);
return false;
}
return true;
}
@ -220,21 +230,24 @@ int BluetoothSerial::read(void)
size_t BluetoothSerial::write(uint8_t c)
{
if (_spp_client){
if (!_spp_client){
return 0;
}
uint8_t buffer[1];
buffer[0] = c;
esp_spp_write(_spp_client, 1, buffer);
return 1;
}
return -1;
esp_err_t err = esp_spp_write(_spp_client, 1, buffer);
return (err == ESP_OK) ? 1 : 0;
}
size_t BluetoothSerial::write(const uint8_t *buffer, size_t size)
{
if (_spp_client){
esp_spp_write(_spp_client, size, (uint8_t *)buffer);
if (!_spp_client){
return 0;
}
return size;
esp_err_t err = esp_spp_write(_spp_client, size, (uint8_t *)buffer);
return (err == ESP_OK) ? size : 0;
}
void BluetoothSerial::flush()

View File

@ -24,7 +24,6 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "Arduino.h"
#include "EEPROM.h"
#include <esp_log.h>
@ -296,9 +295,9 @@ String EEPROMClass::readString (int address)
if (address + len > _size)
return String(0);
char value[len + 1];
char value[len];
memcpy((uint8_t*) value, _data + address, len);
value[len + 1] = 0;
value[len] = 0;
return String(value);
}

View File

@ -29,6 +29,7 @@
#ifndef EEPROM_FLASH_PARTITION_NAME
#define EEPROM_FLASH_PARTITION_NAME "eeprom"
#endif
#include <Arduino.h>
extern "C" {
#include <stddef.h>

View File

@ -0,0 +1,45 @@
#include <Arduino.h>
struct Button {
const uint8_t PIN;
uint32_t numberKeyPresses;
bool pressed;
};
Button button1 = {23, 0, false};
Button button2 = {18, 0, false};
void IRAM_ATTR isr(void* arg) {
Button* s = static_cast<Button*>(arg);
s->numberKeyPresses += 1;
s->pressed = true;
}
void IRAM_ATTR isr() {
button2.numberKeyPresses += 1;
button2.pressed = true;
}
void setup() {
Serial.begin(115200);
pinMode(button1.PIN, INPUT_PULLUP);
attachInterruptArg(button1.PIN, isr, &button1, FALLING);
pinMode(button2.PIN, INPUT_PULLUP);
attachInterrupt(button2.PIN, isr, FALLING);
}
void loop() {
if (button1.pressed) {
Serial.printf("Button 1 has been pressed %u times\n", button1.numberKeyPresses);
button1.pressed = false;
}
if (button2.pressed) {
Serial.printf("Button 2 has been pressed %u times\n", button2.numberKeyPresses);
button2.pressed = false;
}
static uint32_t lastMillis = 0;
if (millis() - lastMillis > 10000) {
lastMillis = millis();
detachInterrupt(button1.PIN);
}
}

View File

@ -47,7 +47,9 @@ enum SeekMode {
class File : public Stream
{
public:
File(FileImplPtr p = FileImplPtr()) : _p(p) {}
File(FileImplPtr p = FileImplPtr()) : _p(p) {
_timeout = 0;
}
size_t write(uint8_t) override;
size_t write(const uint8_t *buf, size_t size) override;

View File

@ -252,7 +252,7 @@ void HTTPClient::end(void)
bool HTTPClient::connected()
{
if(_tcp) {
return (_tcp->connected() || (_tcp->available() > 0));
return ((_tcp->available() > 0) || _tcp->connected());
}
return false;
}

View File

@ -1,6 +1,11 @@
#include "FS.h"
#include "SPIFFS.h"
/* You only need to format SPIFFS the first time you run a
test or else use the SPIFFS plugin to create a partition
https://github.com/me-no-dev/arduino-esp32fs-plugin */
#define FORMAT_SPIFFS_IF_FAILED true
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\r\n", dirname);
@ -151,7 +156,7 @@ void testFileIO(fs::FS &fs, const char * path){
void setup(){
Serial.begin(115200);
if(!SPIFFS.begin()){
if(!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)){
Serial.println("SPIFFS Mount Failed");
return;
}

View File

@ -0,0 +1,15 @@
#ifndef _HTTP_Method_H_
#define _HTTP_Method_H_
typedef enum {
HTTP_GET = 0b00000001,
HTTP_POST = 0b00000010,
HTTP_DELETE = 0b00000100,
HTTP_PUT = 0b00001000,
HTTP_PATCH = 0b00010000,
HTTP_HEAD = 0b00100000,
HTTP_OPTIONS = 0b01000000,
HTTP_ANY = 0b01111111,
} HTTPMethod;
#endif /* _HTTP_Method_H_ */

View File

@ -32,6 +32,10 @@
#define DEBUG_OUTPUT Serial
#endif
#ifndef WEBSERVER_MAX_POST_ARGS
#define WEBSERVER_MAX_POST_ARGS 32
#endif
static const char Content_Type[] PROGMEM = "Content-Type";
static const char filename[] PROGMEM = "filename";
@ -355,14 +359,14 @@ void WebServer::_uploadWriteByte(uint8_t b){
_currentUpload->buf[_currentUpload->currentSize++] = b;
}
uint8_t WebServer::_uploadReadByte(WiFiClient& client){
int WebServer::_uploadReadByte(WiFiClient& client){
int res = client.read();
if(res == -1){
while(!client.available() && client.connected())
yield();
delay(2);
res = client.read();
}
return (uint8_t)res;
return res;
}
bool WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
@ -383,8 +387,9 @@ bool WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
client.readStringUntil('\n');
//start reading the form
if (line == ("--"+boundary)){
RequestArgument* postArgs = new RequestArgument[32];
int postArgsLen = 0;
if(_postArgs) delete[] _postArgs;
_postArgs = new RequestArgument[WEBSERVER_MAX_POST_ARGS];
_postArgsLen = 0;
while(1){
String argName;
String argValue;
@ -445,7 +450,7 @@ bool WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
DEBUG_OUTPUT.println();
#endif
RequestArgument& arg = postArgs[postArgsLen++];
RequestArgument& arg = _postArgs[_postArgsLen++];
arg.key = argName;
arg.value = argValue;
@ -472,19 +477,20 @@ bool WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload);
_currentUpload->status = UPLOAD_FILE_WRITE;
uint8_t argByte = _uploadReadByte(client);
int argByte = _uploadReadByte(client);
readfile:
while(argByte != 0x0D){
if (!client.connected()) return _parseFormUploadAborted();
if(argByte < 0) return _parseFormUploadAborted();
_uploadWriteByte(argByte);
argByte = _uploadReadByte(client);
}
argByte = _uploadReadByte(client);
if (!client.connected()) return _parseFormUploadAborted();
if(argByte < 0) return _parseFormUploadAborted();
if (argByte == 0x0A){
argByte = _uploadReadByte(client);
if (!client.connected()) return _parseFormUploadAborted();
if(argByte < 0) return _parseFormUploadAborted();
if ((char)argByte != '-'){
//continue reading the file
_uploadWriteByte(0x0D);
@ -492,7 +498,7 @@ readfile:
goto readfile;
} else {
argByte = _uploadReadByte(client);
if (!client.connected()) return _parseFormUploadAborted();
if(argByte < 0) return _parseFormUploadAborted();
if ((char)argByte != '-'){
//continue reading the file
_uploadWriteByte(0x0D);
@ -552,22 +558,25 @@ readfile:
}
int iarg;
int totalArgs = ((32 - postArgsLen) < _currentArgCount)?(32 - postArgsLen):_currentArgCount;
int totalArgs = ((WEBSERVER_MAX_POST_ARGS - _postArgsLen) < _currentArgCount)?(WEBSERVER_MAX_POST_ARGS - _postArgsLen):_currentArgCount;
for (iarg = 0; iarg < totalArgs; iarg++){
RequestArgument& arg = postArgs[postArgsLen++];
RequestArgument& arg = _postArgs[_postArgsLen++];
arg.key = _currentArgs[iarg].key;
arg.value = _currentArgs[iarg].value;
}
if (_currentArgs) delete[] _currentArgs;
_currentArgs = new RequestArgument[postArgsLen];
for (iarg = 0; iarg < postArgsLen; iarg++){
_currentArgs = new RequestArgument[_postArgsLen];
for (iarg = 0; iarg < _postArgsLen; iarg++){
RequestArgument& arg = _currentArgs[iarg];
arg.key = postArgs[iarg].key;
arg.value = postArgs[iarg].value;
arg.key = _postArgs[iarg].key;
arg.value = _postArgs[iarg].value;
}
_currentArgCount = iarg;
if (postArgs)
delete[] postArgs;
if (_postArgs) {
delete[] _postArgs;
_postArgs=nullptr;
_postArgsLen = 0;
}
return true;
}
#ifdef DEBUG_ESP_HTTP_SERVER

View File

@ -54,6 +54,8 @@ WebServer::WebServer(IPAddress addr, int port)
, _lastHandler(nullptr)
, _currentArgCount(0)
, _currentArgs(nullptr)
, _postArgsLen(0)
, _postArgs(nullptr)
, _headerKeysCount(0)
, _currentHeaders(nullptr)
, _contentLength(0)
@ -72,6 +74,8 @@ WebServer::WebServer(int port)
, _lastHandler(nullptr)
, _currentArgCount(0)
, _currentArgs(nullptr)
, _postArgsLen(0)
, _postArgs(nullptr)
, _headerKeysCount(0)
, _currentHeaders(nullptr)
, _contentLength(0)
@ -94,11 +98,13 @@ WebServer::~WebServer() {
void WebServer::begin() {
close();
_server.begin();
_server.setNoDelay(true);
}
void WebServer::begin(uint16_t port) {
close();
_server.begin(port);
_server.setNoDelay(true);
}
String WebServer::_extractParam(String& authReq,const String& param,const char delimit){
@ -505,6 +511,10 @@ void WebServer::_streamFileCore(const size_t fileSize, const String & fileName,
String WebServer::arg(String name) {
for (int j = 0; j < _postArgsLen; ++j) {
if ( _postArgs[j].key == name )
return _postArgs[j].value;
}
for (int i = 0; i < _currentArgCount; ++i) {
if ( _currentArgs[i].key == name )
return _currentArgs[i].value;
@ -529,6 +539,10 @@ int WebServer::args() {
}
bool WebServer::hasArg(String name) {
for (int j = 0; j < _postArgsLen; ++j) {
if (_postArgs[j].key == name)
return true;
}
for (int i = 0; i < _currentArgCount; ++i) {
if (_currentArgs[i].key == name)
return true;

View File

@ -27,17 +27,17 @@
#include <functional>
#include <memory>
#include <WiFi.h>
#include "HTTP_Method.h"
enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS };
enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END,
UPLOAD_FILE_ABORTED };
enum HTTPClientStatus { HC_NONE, HC_WAIT_READ, HC_WAIT_CLOSE };
enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH };
#define HTTP_DOWNLOAD_UNIT_SIZE 1460
#define HTTP_DOWNLOAD_UNIT_SIZE 1436
#ifndef HTTP_UPLOAD_BUFLEN
#define HTTP_UPLOAD_BUFLEN 2048
#define HTTP_UPLOAD_BUFLEN 1436
#endif
#define HTTP_MAX_DATA_WAIT 5000 //ms to wait for the client to send the request
@ -147,7 +147,7 @@ protected:
bool _parseForm(WiFiClient& client, String boundary, uint32_t len);
bool _parseFormUploadAborted();
void _uploadWriteByte(uint8_t b);
uint8_t _uploadReadByte(WiFiClient& client);
int _uploadReadByte(WiFiClient& client);
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
bool _collectHeader(const char* headerName, const char* headerValue);
@ -179,6 +179,9 @@ protected:
int _currentArgCount;
RequestArgument* _currentArgs;
int _postArgsLen;
RequestArgument* _postArgs;
std::unique_ptr<HTTPUpload> _currentUpload;
int _headerKeysCount;

View File

@ -0,0 +1,63 @@
//Sketch edited by: Martin Chlebovec
//Personal website: https://arduino.php5.sk
#include "esp_wpa2.h"
#include <WiFi.h>
#define EAP_IDENTITY "login@university.domain" //eduroam login --> identity@youruniversity.domain
#define EAP_PASSWORD "password" //your Eduroam password
String line; //variable for response
const char* ssid = "eduroam"; // Eduroam SSID
const char* host = "arduino.php5.sk"; //external server domain for HTTP connection after authentification
void setup() {
Serial.begin(115200);
delay(10);
Serial.println();
Serial.print("Connecting to network: ");
Serial.println(ssid);
WiFi.disconnect(true); //disconnect form wifi to set new wifi connection
esp_wifi_sta_wpa2_ent_set_identity((uint8_t *)EAP_IDENTITY, strlen(EAP_IDENTITY)); //provide identity
esp_wifi_sta_wpa2_ent_set_username((uint8_t *)EAP_IDENTITY, strlen(EAP_IDENTITY)); //provide username
esp_wifi_sta_wpa2_ent_set_password((uint8_t *)EAP_PASSWORD, strlen(EAP_PASSWORD)); //provide password
esp_wpa2_config_t config = WPA2_CONFIG_INIT_DEFAULT(); //set config to default (fixed for 2018 and Arduino 1.8.5+)
esp_wifi_sta_wpa2_ent_enable(&config); //set config to enable function (fixed for 2018 and Arduino 1.8.5+)
WiFi.begin(ssid); //connect to Eduroam function
WiFi.setHostname("ESP32Name"); //set Hostname for your device - not neccesary
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address set: ");
Serial.println(WiFi.localIP()); //print LAN IP
}
void loop() {
delay(5000);
if (WiFi.status() != WL_CONNECTED) { //if we lost connection, retry
WiFi.begin(ssid);
delay(500);
}
Serial.print("Connecting to website: ");
Serial.println(host);
WiFiClient client;
if (!client.connect(host, 80)) { // HTTP connection on port 80
Serial.println("Connection lost! - Failed response");
}
String url = "/rele/rele1.txt"; //read .txt file
Serial.print("Requesting URL: ");
Serial.println(url);
client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n");
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println("Client timed out! - retry");
}
}
while(client.available()) {
line = client.readStringUntil('\n');
Serial.println(line);
}
Serial.println();
Serial.println("End connection");
client.stop();
}

View File

@ -31,8 +31,6 @@ const char* password = "**********";
WiFiServer server(23);
WiFiClient serverClients[MAX_SRV_CLIENTS];
HardwareSerial Serial1(2); // UART1/Serial1 pins 16,17
void setup() {
Serial.begin(115200);
Serial.println("\nConnecting");
@ -62,7 +60,7 @@ void setup() {
}
//start UART and the server
Serial1.begin(9600);
Serial2.begin(9600);
server.begin();
server.setNoDelay(true);
@ -98,7 +96,7 @@ void loop() {
if (serverClients[i] && serverClients[i].connected()){
if(serverClients[i].available()){
//get data from the telnet client and push it to the UART
while(serverClients[i].available()) Serial1.write(serverClients[i].read());
while(serverClients[i].available()) Serial2.write(serverClients[i].read());
}
}
else {
@ -108,10 +106,10 @@ void loop() {
}
}
//check UART for data
if(Serial1.available()){
size_t len = Serial1.available();
if(Serial2.available()){
size_t len = Serial2.available();
uint8_t sbuf[len];
Serial1.readBytes(sbuf, len);
Serial2.readBytes(sbuf, len);
//push UART data to all connected telnet clients
for(i = 0; i < MAX_SRV_CLIENTS; i++){
if (serverClients[i] && serverClients[i].connected()){

View File

@ -184,6 +184,11 @@ bool WiFiAPClass::softAPdisconnect(bool wifioff)
{
bool ret;
wifi_config_t conf;
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return ESP_ERR_INVALID_STATE;
}
*conf.ap.ssid = 0;
*conf.ap.password = 0;
conf.ap.authmode = WIFI_AUTH_OPEN; // auth must be open if pass=0
@ -204,6 +209,9 @@ bool WiFiAPClass::softAPdisconnect(bool wifioff)
uint8_t WiFiAPClass::softAPgetStationNum()
{
wifi_sta_list_t clients;
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return 0;
}
if(esp_wifi_ap_get_sta_list(&clients) == ESP_OK) {
return clients.num;
}
@ -217,6 +225,9 @@ uint8_t WiFiAPClass::softAPgetStationNum()
IPAddress WiFiAPClass::softAPIP()
{
tcpip_adapter_ip_info_t ip;
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return IPAddress();
}
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip);
return IPAddress(ip.ip.addr);
}
@ -229,7 +240,9 @@ IPAddress WiFiAPClass::softAPIP()
*/
uint8_t* WiFiAPClass::softAPmacAddress(uint8_t* mac)
{
if(WiFiGenericClass::getMode() != WIFI_MODE_NULL){
esp_wifi_get_mac(WIFI_IF_AP, mac);
}
return mac;
}
@ -241,6 +254,9 @@ String WiFiAPClass::softAPmacAddress(void)
{
uint8_t mac[6];
char macStr[18] = { 0 };
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return String();
}
esp_wifi_get_mac(WIFI_IF_AP, mac);
sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
@ -253,9 +269,12 @@ String WiFiAPClass::softAPmacAddress(void)
*/
const char * WiFiAPClass::softAPgetHostname()
{
const char * hostname;
const char * hostname = NULL;
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return hostname;
}
if(tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_AP, &hostname)) {
return NULL;
return hostname;
}
return hostname;
}
@ -267,6 +286,9 @@ const char * WiFiAPClass::softAPgetHostname()
*/
bool WiFiAPClass::softAPsetHostname(const char * hostname)
{
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return false;
}
return tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_AP, hostname) == ESP_OK;
}
@ -276,6 +298,9 @@ bool WiFiAPClass::softAPsetHostname(const char * hostname)
*/
bool WiFiAPClass::softAPenableIpV6()
{
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return false;
}
return tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_AP) == ESP_OK;
}
@ -286,6 +311,9 @@ bool WiFiAPClass::softAPenableIpV6()
IPv6Address WiFiAPClass::softAPIPv6()
{
static ip6_addr_t addr;
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return IPv6Address();
}
if(tcpip_adapter_get_ip6_linklocal(TCPIP_ADAPTER_IF_AP, &addr)) {
return IPv6Address();
}

View File

@ -31,6 +31,118 @@
#undef write
#undef read
class WiFiClientRxBuffer {
private:
size_t _size;
uint8_t *_buffer;
size_t _pos;
size_t _fill;
int _fd;
bool _failed;
size_t r_available()
{
if(_fd < 0){
return 0;
}
int count;
int res = lwip_ioctl_r(_fd, FIONREAD, &count);
if(res < 0) {
_failed = true;
return 0;
}
return count;
}
size_t fillBuffer()
{
if(!_buffer){
_buffer = (uint8_t *)malloc(_size);
}
if(_fill && _pos == _fill){
_fill = 0;
_pos = 0;
}
if(!_buffer || _size <= _fill || !r_available()) {
return 0;
}
int res = recv(_fd, _buffer + _fill, _size - _fill, MSG_DONTWAIT);
if(res < 0 && errno != EWOULDBLOCK) {
_failed = true;
return 0;
}
_fill += res;
return res;
}
public:
WiFiClientRxBuffer(int fd, size_t size=1436)
:_size(size)
,_buffer(NULL)
,_pos(0)
,_fill(0)
,_fd(fd)
,_failed(false)
{
//_buffer = (uint8_t *)malloc(_size);
}
~WiFiClientRxBuffer()
{
free(_buffer);
}
bool failed(){
return _failed;
}
int read(uint8_t * dst, size_t len){
if(!dst || !len || (_pos == _fill && !fillBuffer())){
return -1;
}
size_t a = _fill - _pos;
if(len <= a || ((len - a) <= (_size - _fill) && fillBuffer() >= (len - a))){
if(len == 1){
*dst = _buffer[_pos];
} else {
memcpy(dst, _buffer + _pos, len);
}
_pos += len;
return len;
}
size_t left = len;
size_t toRead = a;
uint8_t * buf = dst;
memcpy(buf, _buffer + _pos, toRead);
_pos += toRead;
left -= toRead;
buf += toRead;
while(left){
if(!fillBuffer()){
return len - left;
}
a = _fill - _pos;
toRead = (a > left)?left:a;
memcpy(buf, _buffer + _pos, toRead);
_pos += toRead;
left -= toRead;
buf += toRead;
}
return len;
}
int peek(){
if(_pos == _fill && !fillBuffer()){
return -1;
}
return _buffer[_pos];
}
size_t available(){
return _fill - _pos + r_available();
}
};
class WiFiClientSocketHandle {
private:
int sockfd;
@ -58,6 +170,7 @@ WiFiClient::WiFiClient():_connected(false),next(NULL)
WiFiClient::WiFiClient(int fd):_connected(true),next(NULL)
{
clientSocketHandle.reset(new WiFiClientSocketHandle(fd));
_rxBuffer.reset(new WiFiClientRxBuffer(fd));
}
WiFiClient::~WiFiClient()
@ -69,6 +182,7 @@ WiFiClient & WiFiClient::operator=(const WiFiClient &other)
{
stop();
clientSocketHandle = other.clientSocketHandle;
_rxBuffer = other._rxBuffer;
_connected = other._connected;
return *this;
}
@ -76,6 +190,7 @@ WiFiClient & WiFiClient::operator=(const WiFiClient &other)
void WiFiClient::stop()
{
clientSocketHandle = NULL;
_rxBuffer = NULL;
_connected = false;
}
@ -100,6 +215,7 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
return 0;
}
clientSocketHandle.reset(new WiFiClientSocketHandle(sockfd));
_rxBuffer.reset(new WiFiClientRxBuffer(sockfd));
_connected = true;
return 1;
}
@ -260,11 +376,9 @@ size_t WiFiClient::write(Stream &stream)
int WiFiClient::read(uint8_t *buf, size_t size)
{
if(!available()) {
return -1;
}
int res = recv(fd(), buf, size, MSG_DONTWAIT);
if(res < 0 && errno != EWOULDBLOCK) {
int res = -1;
res = _rxBuffer->read(buf, size);
if(_rxBuffer->failed()) {
log_e("%d", errno);
stop();
}
@ -273,16 +387,12 @@ int WiFiClient::read(uint8_t *buf, size_t size)
int WiFiClient::peek()
{
if(!available()) {
return -1;
}
uint8_t data = 0;
int res = recv(fd(), &data, 1, MSG_PEEK);
if(res < 0 && errno != EWOULDBLOCK) {
int res = _rxBuffer->peek();
if(_rxBuffer->failed()) {
log_e("%d", errno);
stop();
}
return data;
return res;
}
int WiFiClient::available()
@ -290,14 +400,12 @@ int WiFiClient::available()
if(!_connected) {
return 0;
}
int count;
int res = lwip_ioctl_r(fd(), FIONREAD, &count);
if(res < 0) {
int res = _rxBuffer->available();
if(_rxBuffer->failed()) {
log_e("%d", errno);
stop();
return 0;
}
return count;
return res;
}
// Though flushing means to send all pending data,
@ -330,24 +438,25 @@ uint8_t WiFiClient::connected()
if (_connected) {
uint8_t dummy;
int res = recv(fd(), &dummy, 0, MSG_DONTWAIT);
if (res < 0) {
switch (errno) {
case EWOULDBLOCK:
case ENOENT: //caused by vfs
_connected = true;
break;
case ENOTCONN:
case EPIPE:
case ECONNRESET:
case ECONNREFUSED:
case ECONNABORTED:
_connected = false;
log_d("Disconnected: RES: %d, ERR: %d", res, errno);
break;
default:
log_i("Unexpected: RES: %d, ERR: %d", res, errno);
_connected = true;
break;
}
}
else {
_connected = true;
}
}
return _connected;
}

View File

@ -28,11 +28,13 @@
#include <memory>
class WiFiClientSocketHandle;
class WiFiClientRxBuffer;
class WiFiClient : public Client
{
protected:
std::shared_ptr<WiFiClientSocketHandle> clientSocketHandle;
std::shared_ptr<WiFiClientRxBuffer> _rxBuffer;
bool _connected;
public:

View File

@ -334,7 +334,7 @@ void WiFiGenericClass::removeEvent(wifi_event_id_t id)
* @param arg
*/
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
const char * system_event_names[] = { "WIFI_READY", "SCAN_DONE", "STA_START", "STA_STOP", "STA_CONNECTED", "STA_DISCONNECTED", "STA_AUTHMODE_CHANGE", "STA_GOT_IP", "STA_LOST_IP", "STA_WPS_ER_SUCCESS", "STA_WPS_ER_FAILED", "STA_WPS_ER_TIMEOUT", "STA_WPS_ER_PIN", "AP_START", "AP_STOP", "AP_STACONNECTED", "AP_STADISCONNECTED", "AP_PROBEREQRECVED", "GOT_IP6", "ETH_START", "ETH_STOP", "ETH_CONNECTED", "ETH_DISCONNECTED", "ETH_GOT_IP", "MAX"};
const char * system_event_names[] = { "WIFI_READY", "SCAN_DONE", "STA_START", "STA_STOP", "STA_CONNECTED", "STA_DISCONNECTED", "STA_AUTHMODE_CHANGE", "STA_GOT_IP", "STA_LOST_IP", "STA_WPS_ER_SUCCESS", "STA_WPS_ER_FAILED", "STA_WPS_ER_TIMEOUT", "STA_WPS_ER_PIN", "AP_START", "AP_STOP", "AP_STACONNECTED", "AP_STADISCONNECTED", "AP_STAIPASSIGNED", "AP_PROBEREQRECVED", "GOT_IP6", "ETH_START", "ETH_STOP", "ETH_CONNECTED", "ETH_DISCONNECTED", "ETH_GOT_IP", "MAX"};
#endif
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_WARN
const char * system_event_reasons[] = { "UNSPECIFIED", "AUTH_EXPIRE", "AUTH_LEAVE", "ASSOC_EXPIRE", "ASSOC_TOOMANY", "NOT_AUTHED", "NOT_ASSOCED", "ASSOC_LEAVE", "ASSOC_NOT_AUTHED", "DISASSOC_PWRCAP_BAD", "DISASSOC_SUPCHAN_BAD", "UNSPECIFIED", "IE_INVALID", "MIC_FAILURE", "4WAY_HANDSHAKE_TIMEOUT", "GROUP_KEY_UPDATE_TIMEOUT", "IE_IN_4WAY_DIFFERS", "GROUP_CIPHER_INVALID", "PAIRWISE_CIPHER_INVALID", "AKMP_INVALID", "UNSUPP_RSN_IE_VERSION", "INVALID_RSN_IE_CAP", "802_1X_AUTH_FAILED", "CIPHER_SUITE_REJECTED", "BEACON_TIMEOUT", "NO_AP_FOUND", "AUTH_FAIL", "ASSOC_FAIL", "HANDSHAKE_TIMEOUT" };
@ -365,17 +365,29 @@ esp_err_t WiFiGenericClass::_eventCallback(void *arg, system_event_t *event)
} else if(reason == WIFI_REASON_BEACON_TIMEOUT || reason == WIFI_REASON_HANDSHAKE_TIMEOUT) {
WiFiSTAClass::_setStatus(WL_CONNECTION_LOST);
} else if(reason == WIFI_REASON_AUTH_EXPIRE) {
if(WiFi.getAutoReconnect()){
WiFi.begin();
}
} else {
WiFiSTAClass::_setStatus(WL_DISCONNECTED);
}
clearStatusBits(STA_CONNECTED_BIT | STA_HAS_IP_BIT | STA_HAS_IP6_BIT);
if(reason >= WIFI_REASON_BEACON_TIMEOUT && reason != WIFI_REASON_AUTH_FAIL && WiFi.getAutoReconnect()){
if(((reason == WIFI_REASON_AUTH_EXPIRE) ||
(reason >= WIFI_REASON_BEACON_TIMEOUT && reason != WIFI_REASON_AUTH_FAIL)) &&
WiFi.getAutoReconnect())
{
WiFi.enableSTA(false);
WiFi.enableSTA(true);
WiFi.begin();
}
} else if(event->event_id == SYSTEM_EVENT_STA_GOT_IP) {
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
uint8_t * ip = (uint8_t *)&(event->event_info.got_ip.ip_info.ip.addr);
uint8_t * mask = (uint8_t *)&(event->event_info.got_ip.ip_info.netmask.addr);
uint8_t * gw = (uint8_t *)&(event->event_info.got_ip.ip_info.gw.addr);
log_d("STA IP: %u.%u.%u.%u, MASK: %u.%u.%u.%u, GW: %u.%u.%u.%u",
ip[0], ip[1], ip[2], ip[3],
mask[0], mask[1], mask[2], mask[3],
gw[0], gw[1], gw[2], gw[3]);
#endif
WiFiSTAClass::_setStatus(WL_CONNECTED);
setStatusBits(STA_HAS_IP_BIT | STA_CONNECTED_BIT);
} else if(event->event_id == SYSTEM_EVENT_STA_LOST_IP) {
@ -403,6 +415,15 @@ esp_err_t WiFiGenericClass::_eventCallback(void *arg, system_event_t *event)
} else if(event->event_id == SYSTEM_EVENT_ETH_DISCONNECTED) {
clearStatusBits(ETH_CONNECTED_BIT | ETH_HAS_IP_BIT | ETH_HAS_IP6_BIT);
} else if(event->event_id == SYSTEM_EVENT_ETH_GOT_IP) {
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
uint8_t * ip = (uint8_t *)&(event->event_info.got_ip.ip_info.ip.addr);
uint8_t * mask = (uint8_t *)&(event->event_info.got_ip.ip_info.netmask.addr);
uint8_t * gw = (uint8_t *)&(event->event_info.got_ip.ip_info.gw.addr);
log_d("ETH IP: %u.%u.%u.%u, MASK: %u.%u.%u.%u, GW: %u.%u.%u.%u",
ip[0], ip[1], ip[2], ip[3],
mask[0], mask[1], mask[2], mask[3],
gw[0], gw[1], gw[2], gw[3]);
#endif
setStatusBits(ETH_CONNECTED_BIT | ETH_HAS_IP_BIT);
} else if(event->event_id == SYSTEM_EVENT_GOT_IP6) {

View File

@ -399,6 +399,9 @@ uint8_t WiFiSTAClass::waitForConnectResult()
*/
IPAddress WiFiSTAClass::localIP()
{
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return IPAddress();
}
tcpip_adapter_ip_info_t ip;
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip);
return IPAddress(ip.ip.addr);
@ -412,7 +415,9 @@ IPAddress WiFiSTAClass::localIP()
*/
uint8_t* WiFiSTAClass::macAddress(uint8_t* mac)
{
if(WiFiGenericClass::getMode() != WIFI_MODE_NULL){
esp_wifi_get_mac(WIFI_IF_STA, mac);
}
return mac;
}
@ -424,6 +429,9 @@ String WiFiSTAClass::macAddress(void)
{
uint8_t mac[6];
char macStr[18] = { 0 };
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return String();
}
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]);
@ -436,6 +444,9 @@ String WiFiSTAClass::macAddress(void)
*/
IPAddress WiFiSTAClass::subnetMask()
{
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return IPAddress();
}
tcpip_adapter_ip_info_t ip;
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip);
return IPAddress(ip.netmask.addr);
@ -447,6 +458,9 @@ IPAddress WiFiSTAClass::subnetMask()
*/
IPAddress WiFiSTAClass::gatewayIP()
{
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return IPAddress();
}
tcpip_adapter_ip_info_t ip;
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip);
return IPAddress(ip.gw.addr);
@ -459,6 +473,9 @@ IPAddress WiFiSTAClass::gatewayIP()
*/
IPAddress WiFiSTAClass::dnsIP(uint8_t dns_no)
{
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return IPAddress();
}
ip_addr_t dns_ip = dns_getserver(dns_no);
return IPAddress(dns_ip.u_addr.ip4.addr);
}
@ -469,6 +486,9 @@ IPAddress WiFiSTAClass::dnsIP(uint8_t dns_no)
*/
String WiFiSTAClass::SSID() const
{
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return String();
}
wifi_ap_record_t info;
if(!esp_wifi_sta_get_ap_info(&info)) {
return String(reinterpret_cast<char*>(info.ssid));
@ -482,6 +502,9 @@ String WiFiSTAClass::SSID() const
*/
String WiFiSTAClass::psk() const
{
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return String();
}
wifi_config_t conf;
esp_wifi_get_config(WIFI_IF_STA, &conf);
return String(reinterpret_cast<char*>(conf.sta.password));
@ -495,6 +518,9 @@ uint8_t* WiFiSTAClass::BSSID(void)
{
static uint8_t bssid[6];
wifi_ap_record_t info;
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return NULL;
}
if(!esp_wifi_sta_get_ap_info(&info)) {
memcpy(bssid, info.bssid, 6);
return reinterpret_cast<uint8_t*>(bssid);
@ -523,6 +549,9 @@ String WiFiSTAClass::BSSIDstr(void)
*/
int8_t WiFiSTAClass::RSSI(void)
{
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return 0;
}
wifi_ap_record_t info;
if(!esp_wifi_sta_get_ap_info(&info)) {
return info.rssi;
@ -536,7 +565,10 @@ int8_t WiFiSTAClass::RSSI(void)
*/
const char * WiFiSTAClass::getHostname()
{
const char * hostname;
const char * hostname = NULL;
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return hostname;
}
if(tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &hostname)){
return NULL;
}
@ -550,6 +582,9 @@ const char * WiFiSTAClass::getHostname()
*/
bool WiFiSTAClass::setHostname(const char * hostname)
{
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return false;
}
return tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, hostname) == 0;
}
@ -559,6 +594,9 @@ bool WiFiSTAClass::setHostname(const char * hostname)
*/
bool WiFiSTAClass::enableIpV6()
{
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return false;
}
return tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA) == 0;
}
@ -569,6 +607,9 @@ bool WiFiSTAClass::enableIpV6()
IPv6Address WiFiSTAClass::localIPv6()
{
static ip6_addr_t addr;
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return IPv6Address();
}
if(tcpip_adapter_get_ip6_linklocal(TCPIP_ADAPTER_IF_STA, &addr)){
return IPv6Address();
}

View File

@ -221,8 +221,10 @@ int WiFiUDP::parsePacket(){
}
remote_ip = IPAddress(si_other.sin_addr.s_addr);
remote_port = ntohs(si_other.sin_port);
if (len > 0) {
rx_buffer = new cbuf(len);
rx_buffer->write(buf, len);
}
delete[] buf;
return len;
}
@ -264,6 +266,7 @@ int WiFiUDP::peek(){
}
void WiFiUDP::flush(){
if(!rx_buffer) return;
cbuf *b = rx_buffer;
rx_buffer = 0;
delete b;

View File

@ -81,6 +81,7 @@ void WiFiClientSecure::stop()
close(sslclient->socket);
sslclient->socket = -1;
_connected = false;
_peek = -1;
}
stop_ssl_socket(sslclient, _CA_cert, _cert, _private_key);
}
@ -105,7 +106,7 @@ int WiFiClientSecure::connect(const char *host, uint16_t port, const char *_CA_c
int ret = start_ssl_client(sslclient, host, port, _CA_cert, _cert, _private_key);
_lastError = ret;
if (ret < 0) {
log_e("lwip_connect_r: %d", errno);
log_e("start_ssl_client: %d", ret);
stop();
return 0;
}
@ -117,7 +118,7 @@ int WiFiClientSecure::peek(){
if(_peek >= 0){
return _peek;
}
_peek = read();
_peek = timedRead();
return _peek;
}
@ -158,21 +159,30 @@ size_t WiFiClientSecure::write(const uint8_t *buf, size_t size)
int WiFiClientSecure::read(uint8_t *buf, size_t size)
{
if(_peek >= 0){
uint8_t data = -1;
data = _peek;
_peek = -1;
return data;
}
if (!available()) {
int peeked = 0;
if ((!buf && size) || (_peek < 0 && !available())) {
return -1;
}
if(!size){
return 0;
}
if(_peek >= 0){
buf[0] = _peek;
_peek = -1;
size--;
if(!size || !available()){
return 1;
}
buf++;
peeked = 1;
}
int res = get_ssl_receive(sslclient, buf, size);
if (res < 0) {
stop();
}
return res;
}
return res + peeked;
}
int WiFiClientSecure::available()
@ -183,6 +193,8 @@ int WiFiClientSecure::available()
int res = data_to_read(sslclient);
if (res < 0 ) {
stop();
} else if(_peek >= 0) {
res += 1;
}
return res;
}

View File

@ -364,3 +364,4 @@ void TwoWire::dumpI2C()
}
TwoWire Wire = TwoWire(0);
TwoWire Wire1 = TwoWire(1);

View File

@ -134,6 +134,7 @@ public:
};
extern TwoWire Wire;
extern TwoWire Wire1;
/*

View File

@ -38,7 +38,7 @@
{
"packager": "esp32",
"name": "esptool",
"version": "da31d9d"
"version": "2.3.1"
},
{
"packager": "esp32",
@ -85,21 +85,42 @@
},
{
"name": "esptool",
"version": "da31d9d",
"version": "2.3.1",
"systems": [
{
"host": "i686-mingw32",
"url": "https://dl.espressif.com/dl/esptool-da31d9d-windows.zip",
"archiveFileName": "esptool-da31d9d-windows.zip",
"checksum": "SHA-256:6476f4d6e33a59167dea364e177d97167316253d2c9ac75f81b469ecb3ed3875",
"size": "3395925"
"url": "https://dl.espressif.com/dl/esptool-2.3.1-windows.zip",
"archiveFileName": "esptool-2.3.1-windows.zip",
"checksum": "SHA-256:c187763d0faac7da7c30a292a23c759bbc256fcd084dc8846ed284000cb0fe29",
"size": "3396085"
},
{
"host": "x86_64-apple-darwin",
"url": "https://dl.espressif.com/dl/esptool-da31d9d-macos.tar.gz",
"archiveFileName": "esptool-da31d9d-macos.tar.gz",
"checksum": "SHA-256:76d53298366a294235356bb8d197a81b2afbfd62642851bfbaee252cc593faa9",
"size": "3810904"
"url": "https://dl.espressif.com/dl/esptool-2.3.1-macos.tar.gz",
"archiveFileName": "esptool-2.3.1-macos.tar.gz",
"checksum": "SHA-256:cd922418f02e0ca11dc066b36a22646a1b441da00d762b4464ca598c902c5ecb",
"size": "3810932"
},
{
"host": "x86_64-pc-linux-gnu",
"url": "https://dl.espressif.com/dl/esptool-2.3.1-linux.tar.gz",
"archiveFileName": "esptool-2.3.1-linux.tar.gz",
"checksum": "SHA-256:cff30841dad80ed5d7d2d58a31843b63afa57528979a9c839806568167691d8e",
"size": "39563"
},
{
"host": "i686-pc-linux-gnu",
"url": "https://dl.espressif.com/dl/esptool-2.3.1-linux.tar.gz",
"archiveFileName": "esptool-2.3.1-linux.tar.gz",
"checksum": "SHA-256:cff30841dad80ed5d7d2d58a31843b63afa57528979a9c839806568167691d8e",
"size": "39563"
},
{
"host": "arm-linux-gnueabihf",
"url": "https://dl.espressif.com/dl/esptool-2.3.1-linux.tar.gz",
"archiveFileName": "esptool-2.3.1-linux.tar.gz",
"checksum": "SHA-256:cff30841dad80ed5d7d2d58a31843b63afa57528979a9c839806568167691d8e",
"size": "39563"
}
]
},

View File

@ -3,7 +3,7 @@ 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
tools.esptool.path={runtime.platform.path}/tools/esptool
tools.esptool.cmd=esptool
tools.esptool.cmd.linux=esptool.py
tools.esptool.cmd.windows=esptool.exe
@ -49,7 +49,8 @@ build.flash_size=4MB
build.flash_mode=dio
build.boot=bootloader
build.code_debug=0
build.extra_flags=-DESP32 -DCORE_DEBUG_LEVEL={build.code_debug}
build.defines=
build.extra_flags=-DESP32 -DCORE_DEBUG_LEVEL={build.code_debug} {build.defines}
# These can be overridden in platform.local.txt
compiler.c.extra_flags=
@ -88,8 +89,8 @@ recipe.output.save_file={build.project_name}.{build.variant}.bin
## Compute size
recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf"
recipe.size.regex=^(?:\.iram0\.text|\.dram0\.text|\.flash\.text|\.dram0\.data|\.flash\.rodata|)\s+([0-9]+).*
recipe.size.regex.data=^(?:\.dram0\.data|\.dram0\.bss)\s+([0-9]+).*
recipe.size.regex=^(?:\.iram0\.text|\.iram0\.vectors|\.dram0\.data|\.flash\.text|\.flash\.rodata|)\s+([0-9]+).*
recipe.size.regex.data=^(?:\.dram0\.data|\.dram0\.bss|\.noinit)\s+([0-9]+).*
# ------------------------------

View File

@ -5,15 +5,16 @@
# $2 - JSON output file
function downloadAndMergePackageJSON()
{
echo " --- Package JSON definition merge BEGIN ---"
echo
echo " ---Package JSON definition merge BEGIN--->"
jsonLink=$1
jsonOut=$2
curlAuthToken=$3
outDirectory=$4
echo "Remote package JSON: $jsonLink (source)"
echo "Current package JSON: $jsonOut (target)"
echo " - remote package JSON: $jsonLink (source)"
echo " - current package JSON: $jsonOut (target)"
old_json=$outDirectory/oldJson.json
merged_json=$outDirectory/mergedJson.json
@ -22,7 +23,7 @@ function downloadAndMergePackageJSON()
#echo " Local tmp for remote JSON: $old_json"
#echo " Merge output JSON: $merged_json"
echo "Downloading JSON package definition: $jsonLink ..."
echo " - downloading JSON package definition: $jsonLink ..."
# Authentication through HTTP headers might fail on redirection due to bug in cURL (https://curl.haxx.se/docs/adv_2018-b3bf.html - headers are resent to the target location including the original authentication)
# Notes:
@ -35,10 +36,12 @@ function downloadAndMergePackageJSON()
#curl --verbose -sH "Authorization: token $curlAuthToken" -L -o "$old_json" "$jsonLink"
curl -L -o "$old_json" "$jsonLink?access_token=$curlAuthToken"
if [ $? -ne 0 ]; then echo "FAILED: $? => aborting"; exit 1; fi
#curl -L -o "$old_json" "$jsonLink"
echo "Merging $old_json into $jsonOut ..."
echo " - merging $old_json into $jsonOut ..."
echo
set +e
@ -49,16 +52,17 @@ function downloadAndMergePackageJSON()
set -v
if [ ! -s $merged_json ]; then
rm -f "$merged_json"
echo "Nothing to merge ($merged_json empty), $jsonOut unchanged"
echo " Done: nothing to merge ($merged_json empty) => $jsonOut remains unchanged"
else
rm -f "$jsonOut"
mv "$merged_json" "$jsonOut"
echo "Data successfully merged to $jsonOut"
echo " Done: JSON data successfully merged to $jsonOut"
fi
rm -f "$old_json"
set +v
echo " --- Package JSON definition merge END ---"
echo " <---Package JSON definition merge END---"
echo
}
############################################################
@ -73,58 +77,65 @@ echo "==================================================================="
echo "RELEASE PACKAGE PUBLISHING ARRANGEMENTS (GitHub/Arduino compliance)"
echo "==================================================================="
echo
cmdLine=`basename $0 $@`
echo "Cmdline: ${cmdLine}"
# cURL authentication token
while getopts ":a:,:d:" opt; do
case $opt in
a)
curlAuth=$OPTARG
echo "ACCESS TOKEN: $curlAuth" >&2
#echo " ACCESS TOKEN: $curlAuth" >&2
;;
d)
releaseDir=$OPTARG
echo "RELEASE OUTPUT DIRECTORY: $releaseDir" >&2
#echo " RELEASE OUTPUT DIRECTORY: $releaseDir" >&2
;;
\?)
echo "Invalid option: -$OPTARG" >&2
echo "Error: invalid option -$OPTARG => aborting" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
echo "Error: option -$OPTARG requires an argument => aborting" >&2
exit 1
;;
esac
done
# where we at?
echo
echo "Prequisite check:"
if [ -z "$TRAVIS_BUILD_DIR" ]; then
echo "Non-TravisCI environment"
echo " - non-TravisCI environment"
cd "$( dirname ${BASH_SOURCE[0]} )"/..
bTravisRun=0
else
echo "TravisCI run"
echo " - TravisCI run"
cd $TRAVIS_BUILD_DIR
bTravisRun=1
fi
# no tag, no love
if [ -z "$TRAVIS_TAG" ] && [ $bTravisRun -eq 1 ]; then
echo "Non-tagged builds not supported in Travis CI environment, exiting"
echo "Warning: non-tagged builds not supported in Travis CI environment => exiting"
exit 0
fi
currentDir=`pwd`
echo "Current working directory: $currentDir"
echo
echo "Package build settings:"
echo "======================="
srcdir=$currentDir
# source directory
srcdir=`pwd`
echo "Current working directory: ${srcdir}"
# target directory for actual release fileset
if [ -z "$releaseDir" ]; then
releaseDir=release
fi
echo "Release output directory: $releaseDir"
# get current branch name and commit hash
# Git versions, branch names, tags
branch_name=""
verx=""
extent=""
@ -132,15 +143,18 @@ extent=""
if [ -z "$TRAVIS_TAG" ]; then
branch_name=`git rev-parse --abbrev-ref HEAD 2>/dev/null`
ver=`sed -n -E 's/version=([0-9.]+)/\1/p' platform.txt`
verx=`git rev-parse --short=8 HEAD 2>/dev/null`
else
ver=$TRAVIS_TAG
fi
verx=`git rev-parse --short=8 HEAD 2>/dev/null`
# Package name resolving (case-insensitive):
# - unknown branch, master branch or branch in detached state (HEAD revision) use only the tag's name as version string (esp32-$TAG_NAME, eg 'esp32-1.0.0-RC1')
# - all other branches use long-version string (esp32-$BRANCH_NAME-$GITREV_NUMBER_SHORT, eg 'esp32-idf_update-cde668da')
# Package name (case-insensitive)
shopt -s nocasematch
if [ ! -z "$branch_name" ] && [ "$branch_name" != "master" ]; then
if [ ! -z "$branch_name" ] && [ "$branch_name" != "master" ] && [ "$branch_name" != "head" ]; then
extent="-$branch_name-$verx"
fi
@ -148,54 +162,56 @@ package_name=esp32-$ver$extent
shopt -u nocasematch
echo "Version: $ver"
echo "Branch name: $branch_name"
echo "Git revision (8B): $verx"
echo "Extension: $extent"
echo "Package version: $ver"
echo "Git branch name: $branch_name"
echo "Git revision number: $verx"
echo "Package name extension: $extent"
echo "Travis CI tag: $TRAVIS_TAG"
echo "Package name: $package_name"
echo "Release package name: $package_name"
# Set REMOTE_URL environment variable to the address where the package will be
# available for download. This gets written into package json file.
if [ -z "$REMOTE_URL" ]; then
REMOTE_URL="http://localhost:8000"
echo "REMOTE_URL not defined, using default"
remoteEchoOut="${REMOTE_URL} (REMOTE_URL variable not defined, using default)"
else
remoteEchoOut="${REMOTE_URL}"
fi
echo "Remote: $REMOTE_URL"
echo "Target URL for download (JSON incl): ${remoteEchoOut}"
# Create directory for the package
outdir=$releaseDir/$package_name
echo "Temporary output directory: $outdir"
echo "Local temp directory: $outdir"
rm -rf $releaseDir
mkdir -p $outdir
# Copy package required stuff:
# Copy files required for the package release:
echo
echo "Package build processing:"
echo "========================="
echo
echo "Prepare files for the package main archive:"
echo " - copying neccessary files from current Git repository..."
# <package root>
# <PACKAGE ROOT>
cp -f $srcdir/boards.txt $outdir/
cp -f $srcdir/platform.txt $outdir/
cp -f $srcdir/programmers.txt $outdir/
# <complete dirs>
# <COMPLETE DIRS>
# cores/
# libraries/
# variants/
# tools/partitions/
cp -Rf $srcdir/cores $outdir/
cp -Rf $srcdir/libraries $outdir/
cp -Rf $srcdir/variants $outdir/
mkdir -p $outdir/tools
cp -Rf $srcdir/tools/partitions $outdir/tools/
# <dir & files>
# tools/partitions/
mkdir -p $outdir/tools/partitions
cp -f $srcdir/tools/partitions/boot_app0.bin $outdir/tools/partitions
cp -f $srcdir/tools/partitions/default.csv $outdir/tools/partitions
cp -f $srcdir/tools/partitions/minimal.csv $outdir/tools/partitions
cp -f $srcdir/tools/partitions/min_spiffs.csv $outdir/tools/partitions
cp -f $srcdir/tools/partitions/no_ota.csv $outdir/tools/partitions
# <DIR & FILES>
# tools/sdk/
cp -Rf $srcdir/tools/sdk $outdir/tools/
@ -206,50 +222,51 @@ cp -f $srcdir/tools/esptool.py $outdir/tools/
cp -f $srcdir/tools/gen_esp32part.py $outdir/tools/
cp -f $srcdir/tools/gen_esp32part.exe $outdir/tools/
echo " - cleaning *.DS_Store files..."
find $outdir -name '*.DS_Store' -exec rm -f {} \;
# Do some replacements in platform.txt file, which are required because IDE
# handles tool paths differently when package is installed in hardware folder
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' \
> $outdir/platform.txt
# Put core version and short hash of git version into core_version.h
ver_define=`echo $plain_ver | tr "[:lower:].\055" "[:upper:]_"`
echo Ver define: $ver_define
echo \#define ARDUINO_ESP32_GIT_VER 0x`git rev-parse --short=8 HEAD 2>/dev/null` >$outdir/cores/esp32/core_version.h
ver_define=`echo $ver | tr "[:lower:].\055" "[:upper:]_"`
echo " - generating C/C++ header defines ($ver_define -> /cores/esp32/core_version.h)..."
echo \#define ARDUINO_ESP32_GIT_VER 0x$verx >$outdir/cores/esp32/core_version.h
echo \#define ARDUINO_ESP32_GIT_DESC `git describe --tags 2>/dev/null` >>$outdir/cores/esp32/core_version.h
echo \#define ARDUINO_ESP32_RELEASE_$ver_define >>$outdir/cores/esp32/core_version.h
echo \#define ARDUINO_ESP32_RELEASE \"$ver_define\" >>$outdir/cores/esp32/core_version.h
# Store submodules' current versions
echo " - getting submodule list (${releaseDir}/submodules.txt)..."
git submodule status > $releaseDir/submodules.txt
# remove all .git* files
echo " - removing *.git files possibly fetched to package tempdir..."
find $outdir -name '*.git*' -type f -delete
# Zip the package
package_name_zip=$package_name.zip
echo "----------------------------------------------------------"
echo "Making $package_name ZIP archive..."
echo
echo " - creating package ZIP archive (${package_name_zip})..."
pushd $releaseDir >/dev/null
zip -qr $package_name_zip $package_name
if [ $? -ne 0 ]; then echo " !error: failed to create ${package_name_zip} (ZIP errno: $?) => aborting"; exit 1; fi
echo "----------------------------------------------------------"
echo "Making $package_name JSON definition file(s)..."
echo
# Calculate SHA sum and size
# Calculate SHA sum and size of ZIP archive
sha=`shasum -a 256 $package_name_zip | cut -f 1 -d ' '`
size=`/bin/ls -l $package_name_zip | awk '{print $5}'`
echo Size: $size
echo SHA-256: $sha
echo " ${package_name_zip} creation OK (size: $size, sha2: $sha)"
echo
echo "Making $package_name JSON definition file(s):"
popd >/dev/null
@ -261,20 +278,47 @@ shopt -s nocasematch
if [[ $TRAVIS_TAG == *-RC* ]]; then
bIsPrerelease=1
package_name_json=$PACKAGE_JSON_DEV
echo "Package type: PRE-RELEASE, JSON def.file: $PACKAGE_JSON_DEV"
echo " - package type: PRE-RELEASE, JSON def.file: $PACKAGE_JSON_DEV"
else
bIsPrerelease=0
package_name_json=$PACKAGE_JSON_REL
echo "Package type: RELEASE, JSON def.files: $PACKAGE_JSON_REL, $PACKAGE_JSON_DEV"
echo " - package type: RELEASE, JSON def.files: $PACKAGE_JSON_REL, $PACKAGE_JSON_DEV"
fi
shopt -u nocasematch
# Generate JSON package definition
echo
echo "----------------------------------------------------------"
echo "Preparing current package definition ($package_name_json)..."
# Cleanup temporary work dir
rm -rf $outdir
# JSON contents
# Get all previously released versions
echo " - fetching previous (pre)release versions from GitHub..."
set +e
releasesJson=$releaseDir/releases.json
curl -sH "Authorization: token $curlAuth" https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases > $releasesJson
if [ $? -ne 0 ]; then echo "FAILED: $? => aborting"; exit 1; fi
prev_release=$(jq -e -r '. | map(select(.draft == false and .prerelease == false)) | sort_by(.created_at | - fromdateiso8601) | .[0].tag_name' ${releasesJson})
prev_any_release=$(jq -e -r '. | map(select(.draft == false)) | sort_by(.created_at | - fromdateiso8601) | .[0].tag_name' ${releasesJson})
prev_pre_release=$(jq -e -r '. | map(select(.draft == false and .prerelease == true)) | sort_by(.created_at | - fromdateiso8601) | .[0].tag_name' ${releasesJson})
shopt -s nocasematch
if [ "$prev_any_release" == "$TRAVIS_TAG" ]; then
prev_release=$(jq -e -r '. | map(select(.draft == false and .prerelease == false)) | sort_by(.created_at | - fromdateiso8601) | .[1].tag_name' ${releasesJson})
prev_any_release=$(jq -e -r '. | map(select(.draft == false)) | sort_by(.created_at | - fromdateiso8601) | .[1].tag_name' ${releasesJson})
prev_pre_release=$(jq -e -r '. | map(select(.draft == false and .prerelease == true)) | sort_by(.created_at | - fromdateiso8601) | .[1].tag_name' ${releasesJson})
fi
shopt -u nocasematch
set -e
rm -f "$releasesJson"
echo " previous Release: $prev_release"
echo " previous Pre-release: $prev_pre_release"
echo " previous (any)release: $prev_any_release"
# add generated items to JSON package-definition contents
jq_arg=".packages[0].platforms[0].version = \"$ver\" | \
.packages[0].platforms[0].url = \"$REMOTE_URL/$package_name_zip\" |\
.packages[0].platforms[0].archiveFileName = \"$package_name_zip\""
@ -283,42 +327,13 @@ jq_arg="$jq_arg |\
.packages[0].platforms[0].size = \"$size\" |\
.packages[0].platforms[0].checksum = \"SHA-256:$sha\""
# Cleanup temporary work dir
rm -rf $outdir
# Get previous release name
echo
echo "----------------------------------------------------------"
echo "Getting previous releases versions..."
releasesJson=$releaseDir/releases.json
curl -sH "Authorization: token $curlAuth" https://api.github.com/repos/$TRAVIS_REPO_SLUG/releases > $releasesJson
# Previous final release (prerelase == false)
prev_release=$(jq -r '. | map(select(.draft == false and .prerelease == false)) | sort_by(.created_at | - fromdateiso8601) | .[0].tag_name' ${releasesJson})
# Previous release (possibly a pre-release)
prev_any_release=$(jq -r '. | map(select(.draft == false)) | sort_by(.created_at | - fromdateiso8601) | .[0].tag_name' ${releasesJson})
# Previous pre-release
prev_pre_release=$(jq -r '. | map(select(.draft == false and .prerelease == true)) | sort_by(.created_at | - fromdateiso8601) | .[0].tag_name' ${releasesJson})
rm -f "$releasesJson"
echo "Previous release: $prev_release"
echo "Previous (pre-?)release: $prev_any_release"
echo "Previous pre-release: $prev_pre_release"
# always get DEV version of JSON (included in both RC/REL)
echo
echo "----------------------------------------------------------"
echo "Generating $PACKAGE_JSON_DEV..."
echo
pkgJsonDev=$releaseDir/$PACKAGE_JSON_DEV
echo " - generating/merging _DEV_ JSON file (${pkgJsonDev})..."
cat $srcdir/package/package_esp32_index.template.json | jq "$jq_arg" > $releaseDir/$PACKAGE_JSON_DEV
cat $srcdir/package/package_esp32_index.template.json | jq "$jq_arg" > $pkgJsonDev
if [ ! -z "$prev_any_release" ] && [ "$prev_any_release" != "null" ]; then
downloadAndMergePackageJSON "https://github.com/$TRAVIS_REPO_SLUG/releases/download/${prev_any_release}/${PACKAGE_JSON_DEV}" "$releaseDir/${PACKAGE_JSON_DEV}" "${curlAuth}" "$releaseDir"
downloadAndMergePackageJSON "https://github.com/$TRAVIS_REPO_SLUG/releases/download/${prev_any_release}/${PACKAGE_JSON_DEV}" "${pkgJsonDev}" "${curlAuth}" "$releaseDir"
# Release notes: GIT log comments (prev_any_release, current_release>
git log --oneline $prev_any_release.. > $releaseDir/commits.txt
@ -327,14 +342,12 @@ fi
# for RELEASE run update REL JSON as well
if [ $bIsPrerelease -eq 0 ]; then
echo
echo "----------------------------------------------------------"
echo "Generating $PACKAGE_JSON_REL..."
echo
pkgJsonRel=$releaseDir/$PACKAGE_JSON_REL
echo " - generating/merging _REL_ JSON file (${pkgJsonRel})..."
cat $srcdir/package/package_esp32_index.template.json | jq "$jq_arg" > $releaseDir/$PACKAGE_JSON_REL
cat $srcdir/package/package_esp32_index.template.json | jq "$jq_arg" > $pkgJsonRel
if [ ! -z "$prev_release" ] && [ "$prev_release" != "null" ]; then
downloadAndMergePackageJSON "https://github.com/$TRAVIS_REPO_SLUG/releases/download/${prev_release}/${PACKAGE_JSON_REL}" "$releaseDir/${PACKAGE_JSON_REL}" "${curlAuth}" "$releaseDir"
downloadAndMergePackageJSON "https://github.com/$TRAVIS_REPO_SLUG/releases/download/${prev_release}/${PACKAGE_JSON_REL}" "${pkgJsonRel}" "${curlAuth}" "$releaseDir"
# Release notes: GIT log comments (prev_release, current_release>
git log --oneline $prev_release.. > $releaseDir/commits.txt
@ -342,7 +355,17 @@ if [ $bIsPrerelease -eq 0 ]; then
fi
echo
echo "=============================================================="
echo "Package '$package_name' ready for publishing, script finished."
echo "=============================================================="
echo "JSON definition file(s) creation OK"
echo
echo "==================================================================="
echo "Package preparation done ('$releaseDir' contents):"
fileset=`ls -1 $releaseDir`
echo -e $fileset
echo
echo "==================================================================="
echo "==================================================================="
echo "'$package_name' ready for publishing, processing completed."
echo "==================================================================="
echo

View File

@ -1,12 +1,9 @@
#!/bin/bash
# run cmake tests
tools/check_cmakelists.sh
if [ $? -ne 0 ]; then exit 1; fi
# run sketch tests
tools/build-tests.sh
if [ $? -ne 0 ]; then exit 1; fi
# zip the package if tagged build, otherwise finish here
tools/build-release.sh -a$ESP32_GITHUB_TOKEN
if [ ! -z "$TRAVIS_TAG" ]; then
# zip the package if tagged build
tools/build-release.sh -a$ESP32_GITHUB_TOKEN
else
# run cmake and sketch tests
tools/check_cmakelists.sh && tools/build-tests.sh
fi

View File

@ -1,5 +1,11 @@
#!/bin/bash
json_escape () {
printf '%s' "$1" | python -c 'import json,sys; print(json.dumps(sys.stdin.read()))'
#printf '%s' "$1" | php -r 'echo json_encode(file_get_contents("php://stdin"));'
}
set -e
#Cmdline options
@ -46,6 +52,16 @@ while getopts ":t:,:a:,:s:,:p:,:f:,:d:" opt; do
esac
done
# use TravisCI env as default, if available
if [ -z $varTagName ] && [ ! -z $TRAVIS_TAG ]; then
varTagName=$TRAVIS_TAG
fi
if [ -z $varTagName ]; then
echo "No tag name available => aborting"
exit 1
fi
#Check tag name for release/prerelease (prerelease tag contains '_RC' as for release-candidate. case-insensitive)
shopt -s nocasematch
if [ -z $varPrerelease ]; then
@ -60,60 +76,142 @@ shopt -u nocasematch
#
# Prepare Markdown release notes:
#################################
#
# - tag's description:
# ignore first 3 lines - commiter, tagname, blank
# first line of message: heading
# other lines: converted to bullets
# - annotated tags only, lightweight tags just display message of referred commit
# - tag's description conversion to relnotes:
# first 3 lines (tagname, commiter, blank): ignored
# 4th line: relnotes heading
# remaining lines: each converted to bullet-list item
# empty lines ignored
# if '* ' found as a first char pair, it's converted to '- ' to keep bulleting unified
echo
echo Preparing release notes
echo -----------------------
echo "Tag's message:"
relNotesRaw=`git show -s --format=%b $varTagName`
readarray -t msgArray <<<"$relNotesRaw"
arrLen=${#msgArray[@]}
if [ $arrLen > 3 ]; then
#process annotated tags only
if [ $arrLen > 3 ] && [ "${msgArray[0]:0:3}" == "tag" ]; then
ind=3
while [ $ind -lt $arrLen ]; do
if [ $ind -eq 3 ]; then
releaseNotes="#### ${msgArray[ind]}\\n"
releaseNotes="#### ${msgArray[ind]}"
releaseNotes+=$'\r\n'
else
oneLine="$(echo -e "${msgArray[ind]}" | sed -e 's/^[[:space:]]*//')"
if [ ${#oneLine} -gt 0 ]; then
if [ "${oneLine:0:2}" == "* " ]; then oneLine=$(echo ${oneLine/\*/-}); fi
if [ "${oneLine:0:2}" != "- " ]; then releaseNotes+="- "; fi
releaseNotes+="$oneLine\\n"
releaseNotes+="$oneLine"
releaseNotes+=$'\r\n'
#debug output
echo " ${oneLine}"
fi
fi
let ind=$ind+1
done
else
releaseNotes="#### Release of $varTagName\\n"
fi
echo "$releaseNotes"
# - list of commits (commits.txt must exit in the output dir)
commitFile=$varAssetsDir/commits.txt
if [ -e "$commitFile" ]; then
if [ -s "$commitFile" ]; then
releaseNotes+="\\n##### Commits\\n"
releaseNotes+=$'\r\n##### Commits\r\n'
echo
echo "Commits:"
IFS=$'\n'
for next in `cat $commitFile`
do
IFS=' ' read -r commitId commitMsg <<< "$next"
releaseNotes+="- [$commitId](https://github.com/$varRepoSlug/commit/$commitId) $commitMsg\\n"
commitLine="- [$commitId](https://github.com/$varRepoSlug/commit/$commitId) $commitMsg"
echo " $commitLine"
releaseNotes+="$commitLine"
releaseNotes+=$'\r\n'
done
rm -f $commitFile
fi
releaseNotes=$(perl -pe 's/\r?\n/\\n/' <<< ${releaseNotes})
# Check possibly existing release for current tag
echo
echo "Processing GitHub release record for $varTagName:"
echo "-------------------------------------------------"
#JSON parameters to create a new release
curlData="{\"tag_name\": \"$varTagName\",\"target_commitish\": \"master\",\"name\": \"v$varTagName\",\"body\": \"$releaseNotes\",\"draft\": false,\"prerelease\": $varPrerelease}"
echo " - check $varTagName possible existence..."
#Create the release (initial source file assets created by GitHub)
releaseId=$(curl --data "$curlData" https://api.github.com/repos/$varRepoSlug/releases?access_token=$varAccessToken | jq -r '.id')
echo Release ID: $releaseId
# (eg build invoked by Create New Release GHUI button -> GH default release pack created immediately including default assests)
HTTP_RESPONSE=$(curl -L --silent --write-out "HTTPSTATUS:%{http_code}" https://api.github.com/repos/$varRepoSlug/releases/tags/$varTagName?access_token=$varAccessToken)
if [ $? -ne 0 ]; then echo "FAILED: $? => aborting"; exit 1; fi
HTTP_BODY=$(echo $HTTP_RESPONSE | sed -e 's/HTTPSTATUS\:.*//g')
HTTP_STATUS=$(echo $HTTP_RESPONSE | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
echo " ---> GitHub server HTTP response: $HTTP_STATUS"
# if the release exists, append/update recent files to its assets vector
if [ $HTTP_STATUS -eq 200 ]; then
releaseId=$(echo $HTTP_BODY | jq -r '.id')
echo " - $varTagName release found (id $releaseId)"
#Merge release notes and overwrite pre-release flag. all other attributes remain unchanged:
# 1. take existing notes from server (added by release creator)
releaseNotesGH=$(echo $HTTP_BODY | jq -r '.body')
# - strip possibly trailing CR
if [ "${releaseNotesGH: -1}" == $'\r' ]; then
releaseNotesTemp="${releaseNotesGH:0:-1}"
else
releaseNotesTemp="$releaseNotesGH"
fi
# - add CRLF to make relnotes consistent for JSON encoding
releaseNotesTemp+=$'\r\n'
# 2. #append generated relnotes (usually commit oneliners)
releaseNotes="$releaseNotesTemp$releaseNotes"
# 3. JSON-encode whole string for GH API transfer
releaseNotes=$(json_escape "$releaseNotes")
# 4. remove extra quotes returned by python (dummy but whatever)
releaseNotes=${releaseNotes:1:-1}
#Update current GH release record
echo " - updating release notes and pre-release flag:"
curlData="{\"body\": \"$releaseNotes\",\"prerelease\": $varPrerelease}"
echo " <data.begin>$curlData<data.end>"
echo
#echo "DEBUG: curl --data \"$curlData\" https://api.github.com/repos/$varRepoSlug/releases/$releaseId?access_token=$varAccessToken"
curl --data "$curlData" https://api.github.com/repos/$varRepoSlug/releases/$releaseId?access_token=$varAccessToken
if [ $? -ne 0 ]; then echo "FAILED: $? => aborting"; exit 1; fi
echo " - $varTagName release record successfully updated"
#... or create a new release record
else
releaseNotes=$(json_escape "$releaseNotes")
releaseNotes=${releaseNotes:1:-1}
echo " - release $varTagName not found, creating a new record:"
curlData="{\"tag_name\": \"$varTagName\",\"target_commitish\": \"master\",\"name\": \"v$varTagName\",\"body\": \"$releaseNotes\",\"draft\": false,\"prerelease\": $varPrerelease}"
echo " <data.begin>$curlData<data.end>"
#echo "DEBUG: curl --data \"${curlData}\" https://api.github.com/repos/${varRepoSlug}/releases?access_token=$varAccessToken | jq -r '.id'"
releaseId=$(curl --data "$curlData" https://api.github.com/repos/$varRepoSlug/releases?access_token=$varAccessToken | jq -r '.id')
if [ $? -ne 0 ]; then echo "FAILED: $? => aborting"; exit 1; fi
echo " - $varTagName release record successfully created (id $releaseId)"
fi
# Assets defined by dir contents
if [ ! -z $varAssetsDir ]; then
@ -125,23 +223,26 @@ if [ ! -z $varAssetsDir ]; then
done
fi
echo
echo varAssets: $varAssets
#Upload additional assets
if [ ! -z $varAssets ]; then
echo
echo "Uploading assets:"
echo "-----------------"
echo " Files to upload:"
echo " $varAssets"
echo
curlAuth="Authorization: token $varAccessToken"
for filename in $(echo $varAssets | tr ";" "\n")
do
echo
echo
echo Uploading $filename...
echo " - ${filename}:"
curl -X POST -sH "$curlAuth" -H "Content-Type: application/octet-stream" --data-binary @"$filename" https://uploads.github.com/repos/$varRepoSlug/releases/$releaseId/assets?name=$(basename $filename)
if [ $? -ne 0 ]; then echo "FAILED: $? => aborting"; exit 1; fi
echo
echo "OK"
echo
done
fi
echo
echo

Binary file not shown.

View File

@ -190,7 +190,6 @@
#define CONFIG_LOG_BOOTLOADER_LEVEL 0
#define CONFIG_MBEDTLS_TLS_ENABLED 1
#define CONFIG_LWIP_MAX_RAW_PCBS 16
#define CONFIG_SPIRAM_IGNORE_NOTFOUND 1
#define CONFIG_SMP_ENABLE 1
#define CONFIG_SPIRAM_SIZE 4194304
#define CONFIG_MBEDTLS_SSL_SESSION_TICKETS 1
@ -228,6 +227,7 @@
#define CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED 1
#define CONFIG_MONITOR_BAUD 115200
#define CONFIG_ESP32_DEBUG_STUBS_ENABLE 1
#define CONFIG_WIFI_LWIP_ALLOCATION_FROM_SPIRAM_FIRST 1
#define CONFIG_FREERTOS_CORETIMER_0 1
#define CONFIG_PARTITION_TABLE_CUSTOM_FILENAME "partitions.csv"
#define CONFIG_MBEDTLS_HAVE_TIME 1
@ -238,12 +238,10 @@
#define CONFIG_ADC_CAL_EFUSE_VREF_ENABLE 1
#define CONFIG_MBEDTLS_TLS_SERVER 1
#define CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT 1
#define CONFIG_SPIRAM_BOOT_INIT 1
#define CONFIG_FREERTOS_ISR_STACKSIZE 1536
#define CONFIG_CLASSIC_BT_ENABLED 1
#define CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK 1
#define CONFIG_OPENSSL_ASSERT_DO_NOTHING 1
#define CONFIG_SPIRAM_MEMTEST 1
#define CONFIG_WL_SECTOR_SIZE_4096 1
#define CONFIG_OPTIMIZATION_LEVEL_DEBUG 1
#define CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED 1

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -217,17 +217,15 @@ CONFIG_SPIRAM_SUPPORT=y
#
# SPI RAM config
#
CONFIG_SPIRAM_BOOT_INIT=y
CONFIG_SPIRAM_IGNORE_NOTFOUND=y
CONFIG_SPIRAM_BOOT_INIT=
CONFIG_SPIRAM_USE_MEMMAP=
CONFIG_SPIRAM_USE_CAPS_ALLOC=y
CONFIG_SPIRAM_USE_MALLOC=
CONFIG_SPIRAM_TYPE_ESPPSRAM32=y
CONFIG_SPIRAM_SIZE=4194304
CONFIG_SPIRAM_SPEED_40M=y
CONFIG_SPIRAM_MEMTEST=y
CONFIG_SPIRAM_CACHE_WORKAROUND=y
CONFIG_WIFI_LWIP_ALLOCATION_FROM_SPIRAM_FIRST=
CONFIG_WIFI_LWIP_ALLOCATION_FROM_SPIRAM_FIRST=y
CONFIG_MEMMAP_TRACEMEM=
CONFIG_MEMMAP_TRACEMEM_TWOBANKS=
CONFIG_ESP32_TRAX=

View File

@ -0,0 +1,82 @@
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <stdint.h>
#define EXTERNAL_NUM_INTERRUPTS 16
#define NUM_DIGITAL_PINS 40
#define NUM_ANALOG_INPUTS 16
#define analogInputToDigitalPin(p) (((p)<20)?(esp32_adc2gpio[(p)]):-1)
#define digitalPinToInterrupt(p) (((p)<40)?(p):-1)
#define digitalPinHasPWM(p) (p < 34)
#define ALKSESP32 // tell library to not map pins again
static const uint8_t TX = 1;
static const uint8_t RX = 3;
static const uint8_t D0 = 40;
static const uint8_t D1 = 41;
static const uint8_t D2 = 15;
static const uint8_t D3 = 2;
static const uint8_t D4 = 0;
static const uint8_t D5 = 4;
static const uint8_t D6 = 16;
static const uint8_t D7 = 17;
static const uint8_t D8 = 5;
static const uint8_t D9 = 18;
static const uint8_t D10 = 19;
static const uint8_t D11 = 21;
static const uint8_t D12 = 22;
static const uint8_t D13 = 23;
static const uint8_t A0 = 32;
static const uint8_t A1 = 33;
static const uint8_t A2 = 25;
static const uint8_t A3 = 26;
static const uint8_t A4 = 27;
static const uint8_t A5 = 14;
static const uint8_t A6 = 12;
static const uint8_t A7 = 15;
static const uint8_t L_R = 22;
static const uint8_t L_G = 17;
static const uint8_t L_Y = 23;
static const uint8_t L_B = 5;
static const uint8_t L_RGB_R = 4;
static const uint8_t L_RGB_G = 21;
static const uint8_t L_RGB_B = 16;
static const uint8_t SW1 = 15;
static const uint8_t SW2 = 2;
static const uint8_t SW3 = 0;
static const uint8_t POT1 = 32;
static const uint8_t POT2 = 33;
static const uint8_t PIEZO1 = 19;
static const uint8_t PIEZO2 = 18;
static const uint8_t PHOTO = 25;
static const uint8_t DHT_PIN = 26;
static const uint8_t S1 = 4;
static const uint8_t S2 = 16;
static const uint8_t S3 = 18;
static const uint8_t S4 = 19;
static const uint8_t S5 = 21;
static const uint8_t SDA = 27;
static const uint8_t SCL = 14;
static const uint8_t SS = 19;
static const uint8_t MOSI = 21;
static const uint8_t MISO = 22;
static const uint8_t SCK = 23;
static const uint8_t DAC1 = 25;
static const uint8_t DAC2 = 26;
#endif /* Pins_Arduino_h */

54
variants/d32/d32_core.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef _D32_CORE_H_
#define _D32_CORE_H_
#define EXTERNAL_NUM_INTERRUPTS 16
#define NUM_DIGITAL_PINS 40
#define NUM_ANALOG_INPUTS 16
#define analogInputToDigitalPin(p) (((p)<20)?(esp32_adc2gpio[(p)]):-1)
#define digitalPinToInterrupt(p) (((p)<40)?(p):-1)
#define digitalPinHasPWM(p) (p < 34)
static const uint8_t TX = 1;
static const uint8_t RX = 3;
static const uint8_t SDA = 21;
static const uint8_t SCL = 22;
static const uint8_t SS = 5;
static const uint8_t MOSI = 23;
static const uint8_t MISO = 19;
static const uint8_t SCK = 18;
static const uint8_t A0 = 36;
static const uint8_t A3 = 39;
static const uint8_t A4 = 32;
static const uint8_t A5 = 33;
static const uint8_t A6 = 34;
static const uint8_t A7 = 35;
static const uint8_t A10 = 4;
static const uint8_t A11 = 0;
static const uint8_t A12 = 2;
static const uint8_t A13 = 15;
static const uint8_t A14 = 13;
static const uint8_t A15 = 12;
static const uint8_t A16 = 14;
static const uint8_t A17 = 27;
static const uint8_t A18 = 25;
static const uint8_t A19 = 26;
static const uint8_t T0 = 4;
static const uint8_t T1 = 0;
static const uint8_t T2 = 2;
static const uint8_t T3 = 15;
static const uint8_t T4 = 13;
static const uint8_t T5 = 12;
static const uint8_t T6 = 14;
static const uint8_t T7 = 27;
static const uint8_t T8 = 33;
static const uint8_t T9 = 32;
static const uint8_t DAC1 = 25;
static const uint8_t DAC2 = 26;
#endif

View File

@ -0,0 +1,11 @@
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <stdint.h>
#include <d32_core.h>
static const uint8_t LED_BUILTIN = 5;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
static const uint8_t _VBAT = 35; // battery voltage
#endif /* Pins_Arduino_h */

View File

@ -0,0 +1,19 @@
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <stdint.h>
#include <../d32/d32_core.h>
static const uint8_t LED_BUILTIN = 5;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
static const uint8_t _VBAT = 35; // battery voltage
static const uint8_t TF_CS = 4; // TF (Micro SD Card) CS pin
static const uint8_t TS_CS = 12; // Touch Screen CS pin
static const uint8_t TFT_CS = 14; // TFT CS pin
static const uint8_t TFT_LED = 32; // TFT backlight control pin
static const uint8_t TFT_RST = 33; // TFT reset pin
static const uint8_t TFT_DC = 27; // TFT DC pin
#endif /* Pins_Arduino_h */

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