diff --git a/boards/common/esp32/include/periph_conf_common.h b/boards/common/esp32/include/periph_conf_common.h index 9cef5906ca24..dbfb390c4cd4 100644 --- a/boards/common/esp32/include/periph_conf_common.h +++ b/boards/common/esp32/include/periph_conf_common.h @@ -173,7 +173,7 @@ static const gpio_t pwm1_channels[] = PWM1_GPIOS; */ /** - * @brief Static array with configuration for declared I2C devices + * @brief Static array with configuration for declared SPI devices */ static const spi_conf_t spi_config[] = { #ifdef SPI0_CTRL @@ -220,7 +220,7 @@ static const spi_conf_t spi_config[] = { #endif /** - * @brief Static array with configuration for declared I2C devices + * @brief Static array with configuration for declared UART devices */ static const uart_conf_t uart_config[] = { { @@ -249,13 +249,7 @@ static const uart_conf_t uart_config[] = { * * @note UART_NUMOF definition must not be changed. */ -#if defined(UART1_TXD) && defined(UART1_RXD) && defined(UART2_TXD) && defined(UART2_RXD) -#define UART_NUMOF 3 -#elif (defined(UART1_TXD) && defined(UART1_RXD)) || (defined(UART2_TXD) && defined(UART2_RXD)) -#define UART_NUMOF 2 -#else -#define UART_NUMOF 1 -#endif +#define UART_NUMOF ARRAY_SIZE(uart_config) /** @} */ #ifdef __cplusplus diff --git a/boards/common/esp8266/Makefile.features b/boards/common/esp8266/Makefile.features index 127c7b88b82f..c41253575691 100644 --- a/boards/common/esp8266/Makefile.features +++ b/boards/common/esp8266/Makefile.features @@ -10,3 +10,4 @@ FEATURES_PROVIDED += periph_i2c FEATURES_PROVIDED += periph_pwm FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_uart +FEATURES_PROVIDED += periph_uart_modecfg diff --git a/boards/common/esp8266/Makefile.include b/boards/common/esp8266/Makefile.include index d830ea9a47fa..4f17c06da8a9 100644 --- a/boards/common/esp8266/Makefile.include +++ b/boards/common/esp8266/Makefile.include @@ -4,5 +4,5 @@ PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.SLAB_USBtoUART*))) include $(RIOTMAKE)/tools/serial.inc.mk # reset tool configuration -RESET ?= esptool.py -RESET_FLAGS ?= --port $(PROG_DEV) --before default_reset run +RESET ?= $(RIOTTOOLS)/esptool/espreset.py +RESET_FLAGS ?= --port $(PROG_DEV) diff --git a/boards/common/esp8266/board_common.c b/boards/common/esp8266/board_common.c index 2b703b2b13d9..942262791d10 100644 --- a/boards/common/esp8266/board_common.c +++ b/boards/common/esp8266/board_common.c @@ -16,9 +16,12 @@ * @author Gunar Schorcht */ -#include "board_common.h" +#include "board.h" +#include "esp_common.h" #include "log.h" #include "periph/gpio.h" +#include "esp_libc.h" +#include "rom/ets_sys.h" #ifdef __cplusplus extern "C" { @@ -40,35 +43,69 @@ void board_init(void) #endif } +extern void adc_print_config(void); +extern void dac_print_config(void); extern void pwm_print_config(void); extern void i2c_print_config(void); extern void spi_print_config(void); extern void uart_print_config(void); extern void timer_print_config(void); +extern void can_print_config(void); void board_print_config (void) { - LOG_INFO("\nBoard configuration:\n"); + ets_printf("\nBoard configuration:\n"); + #if MODULE_PERIPH_ADC + adc_print_config(); + #endif + #if MODULE_PERIPH_DAC + dac_print_config(); + #endif + #if MODULE_PERIPH_PWM pwm_print_config(); + #endif + #if MODULE_PERIPH_I2C i2c_print_config(); + #endif + #if MODULE_PERIPH_SPI spi_print_config(); + #endif + #if MODULE_PERIPH_UART uart_print_config(); + #endif + #if MODULE_PERIPH_TIMER timer_print_config(); + #endif + #ifdef MODULE_ESP_CAN + can_print_config(); + #endif - LOG_INFO("\tLED: pins=[ "); + ets_printf("\tLED\t\tpins=[ "); #ifdef LED0_PIN - LOG_INFO("%d ", LED0_PIN); + ets_printf("%d ", LED0_PIN); #endif #ifdef LED1_PIN - LOG_INFO("%d ", LED1_PIN); + ets_printf("%d ", LED1_PIN); #endif #ifdef LED2_PIN - LOG_INFO("%d ", LED2_PIN); + ets_printf("%d ", LED2_PIN); + #endif + ets_printf("]\n"); + + ets_printf("\tBUTTON\t\tpins=[ "); + #ifdef BUTTON0_PIN + ets_printf("%d ", BUTTON0_PIN); + #endif + #ifdef BUTTON2_PIN + ets_printf("%d ", BUTTON1_PIN); + #endif + #ifdef BUTTON3_PIN + ets_printf("%d ", BUTTON2_PIN); #endif - LOG_INFO("]\n"); + ets_printf("]\n"); - LOG_INFO("\n\n"); + ets_printf("\n"); } #ifdef __cplusplus diff --git a/boards/common/esp8266/include/board_common.h b/boards/common/esp8266/include/board_common.h index 6f5c815c0b3d..90942b864d78 100644 --- a/boards/common/esp8266/include/board_common.h +++ b/boards/common/esp8266/include/board_common.h @@ -17,6 +17,9 @@ * @{ */ +/* not required when compiling ESP vendor code parts */ +#ifndef ESP_PLATFORM + #include #include "cpu.h" @@ -124,7 +127,7 @@ extern mtd_dev_t *mtd0; * initializations are done during the CPU initialization that is called from * boot loader. */ -extern void board_init(void); +void board_init (void); /** * @brief Print the board configuration in a human readable format @@ -140,4 +143,5 @@ void board_print_config (void); /** @} */ +#endif /* ESP_PLATFORM */ #endif /* BOARD_COMMON_H */ diff --git a/boards/common/esp8266/include/board_modules.h b/boards/common/esp8266/include/board_modules.h index 1bfe64496379..b6281f105abf 100644 --- a/boards/common/esp8266/include/board_modules.h +++ b/boards/common/esp8266/include/board_modules.h @@ -53,13 +53,13 @@ extern "C" { #define ENC28J60_PARAM_SPI SPI_DEV(0) /**< SPI_DEV(0) is used (fixed) */ #ifndef ENC28J60_PARAM_CS -#define ENC28J60_PARAM_CS GPIO4 /**< ENC28J60 CS signal (can be overriden) */ +#define ENC28J60_PARAM_CS GPIO4 /**< ENC28J60 CS signal (can be overridden) */ #endif #ifndef ENC28J60_PARAM_INT -#define ENC28J60_PARAM_INT GPIO9 /**< ENC28J60 INT signal (can be overriden) */ +#define ENC28J60_PARAM_INT GPIO9 /**< ENC28J60 INT signal (can be overridden) */ #endif #ifndef ENC28J60_PARAM_RESET -#define ENC28J60_PARAM_RESET GPIO10 /**< ENC28J60 RESET signal (can be overriden) */ +#define ENC28J60_PARAM_RESET GPIO10 /**< ENC28J60 RESET signal (can be overridden) */ #endif /** @} */ #endif /* defined(MODULE_ENC28J60) || defined(DOXYGEN) */ @@ -82,16 +82,16 @@ extern "C" { #define MRF24J40_PARAM_SPI SPI_DEV(0) /**< SPI_DEV(0) is used (fixed) */ #ifndef MRF24J40_PARAM_SPI_CLK -#define MRF24J40_PARAM_SPI_CLK SPI_CLK_1MHZ /**< SPI bus speed used (can be overriden) */ +#define MRF24J40_PARAM_SPI_CLK SPI_CLK_1MHZ /**< SPI bus speed used (can be overridden) */ #endif #ifndef MRF24J40_PARAM_CS -#define MRF24J40_PARAM_CS GPIO16 /**< MRF24J40 CS signal (can be overriden) */ +#define MRF24J40_PARAM_CS GPIO16 /**< MRF24J40 CS signal (can be overridden) */ #endif #ifndef MRF24J40_PARAM_INT -#define MRF24J40_PARAM_INT GPIO0 /**< MRF24J40 INT signal (can be overriden) */ +#define MRF24J40_PARAM_INT GPIO0 /**< MRF24J40 INT signal (can be overridden) */ #endif #ifndef MRF24J40_PARAM_RESET -#define MRF24J40_PARAM_RESET GPIO2 /**< MRF24J40 RESET signal (can be overriden) */ +#define MRF24J40_PARAM_RESET GPIO2 /**< MRF24J40 RESET signal (can be overridden) */ #endif /** @} */ #endif /* defined(MODULE_MRF24J40) || defined(DOXYGEN) */ @@ -109,14 +109,14 @@ extern "C" { * If not defined, the default CS signal of SPI_DEV(0) is used. * @{ */ -#define SDCARD_SPI_PARAM_SPI SPI_DEV(0) /**< SPI_DEV(0) is used (fixed) */ -#define SDCARD_SPI_PARAM_CLK SPI0_SCK_GPIO /**< SPI_DEV(0) SCK is used (fixed) */ -#define SDCARD_SPI_PARAM_MOSI SPI0_MOSI_GPIO /**< SPI_DEV(0) MOSI is used (fixed) */ -#define SDCARD_SPI_PARAM_MISO SPI0_MISO_GPIO /**< SPI_DEV(0) MISO is used (fixed) */ -#define SDCARD_SPI_PARAM_POWER GPIO_UNDEF /**< power control is not used (fixed) */ +#define SDCARD_SPI_PARAM_SPI SPI_DEV(0) /**< SPI_DEV(0) is used (fixed) */ +#define SDCARD_SPI_PARAM_CLK SPI0_SCK /**< SPI_DEV(0) SCK is used (fixed) */ +#define SDCARD_SPI_PARAM_MOSI SPI0_MOSI /**< SPI_DEV(0) MOSI is used (fixed) */ +#define SDCARD_SPI_PARAM_MISO SPI0_MISO /**< SPI_DEV(0) MISO is used (fixed) */ +#define SDCARD_SPI_PARAM_POWER GPIO_UNDEF /**< power control is not used (fixed) */ #ifndef SDCARD_SPI_PARAM_CS -#define SDCARD_SPI_PARAM_CS SPI0_CS0_GPIO /**< SD-Card CS signal (can be overridden) */ +#define SDCARD_SPI_PARAM_CS SPI0_CS0 /**< SD-Card CS signal (can be overridden) */ #endif /** @} */ #endif /* defined(MODULE_SDCARD_SPI) || defined(DOXYGEN) */ diff --git a/boards/common/esp8266/include/periph_conf_common.h b/boards/common/esp8266/include/periph_conf_common.h index 96444e5753b4..6c969b36fcdf 100644 --- a/boards/common/esp8266/include/periph_conf_common.h +++ b/boards/common/esp8266/include/periph_conf_common.h @@ -19,8 +19,8 @@ #define PERIPH_CONF_COMMON_H /* include board.h and periph_cpu.h to make them visible in any case */ -#include "board.h" #include "periph_cpu.h" +#include "kernel_defines.h" #ifdef __cplusplus extern "C" { @@ -36,18 +36,67 @@ extern "C" { * ESP8266 provides one ADC pin that is broken out on all boards. * @{ */ -#define ADC_NUMOF 1 /**< number of ADC channels */ +#define ADC_NUMOF (1) /**< number of ADC channels */ /** @} */ +/** + * @name DAC configuration + * + * ESP8266 provides no DAC. + * @{ + */ +#define DAC_NUMOF (0) /**< number of DAC channels */ +/** @} */ + + +/** + * @name I2C configuration + * @{ + */ + +/** + * @brief Static array with configuration for declared I2C devices + */ +static const i2c_conf_t i2c_config[] = { + #if defined(I2C0_SCL) && defined(I2C0_SDA) && defined(I2C0_SPEED) + { + .speed = I2C0_SPEED, + .scl = I2C0_SCL, + .sda = I2C0_SDA, + }, + #endif + #if defined(I2C1_SCL) && defined(I2C1_SDA) && defined(I2C1_SPEED) + { + .speed = I2C1_SPEED, + .scl = I2C1_SCL, + .sda = I2C1_SDA, + }, + #endif +}; + +/** + * @brief Number of I2C interfaces + * + * The number of I2C interfaces is determined automatically from board-specific + * peripheral definitions. + * + * @note I2C_NUMOF definition must not be changed. + */ +#define I2C_NUMOF ARRAY_SIZE(i2c_config) + +/** @} */ + /** * @name PWM configuration * - * The hardware implementation of ESP8266 PWM supports only frequencies as power of - * two. Therefore a software implementation of one PWM device PWM_DEV(0) with up to - * 8 PWM channels (PWM_CHANNEL_NUM_MAX) is used. + * The hardware implementation of ESP8266 PWM supports only frequencies as + * power of two. Therefore a software implementation of one PWM device + * PWM_DEV(0) with up to 8 PWM channels (#PWM_CHANNEL_NUM_MAX) is used. The + * GPIOs that can be used as PWM channels are defined by #PWM0_GPIOS in board + * definition. * - * @note The minumum PWM period that can be realized is 10 us or 100.000 PWM + * @note The minimum PWM period that can be realized is 10 us or 100.000 PWM * clock cycles per second. Therefore, the product of frequency and resolution * should not be greater than 100.000. Otherwise the frequency is scaled down * automatically. @@ -55,71 +104,85 @@ extern "C" { * @{ */ -#define PWM_NUMOF (1) /**< Number of PWM devices */ - +#if defined(PWM0_GPIOS) || defined(DOXYGEN) /** - * @brief Maximum number of channels per PWM device. + * @brief Static array of GPIOs that can be used as channels of PWM_DEV(0) */ -#define PWM_CHANNEL_NUM_MAX (8) +static const gpio_t pwm0_channels[] = PWM0_GPIOS; /** - * @brief Definition of GPIOs that can be used as PWM channels - * of device PWM_DEV(0). + * @brief Number of PWM devices * - * The following definition is just an example configuration. Declare up to - * \ref PWM_CHANNEL_NUM_MAX GPIOs as PWM channels. GPIOs with a duty cycle - * value of 0 can be used as normal GPIOs for other purposes. GPIOs in the - * list that are used for other purposes, e.g., I2C or SPI, are then not - * available as PWM channels. + * The number of PWM devices is determined from the #PWM0_GPIOS definition. + * + * @note #PWM_NUMOF definition must not be changed. */ -#ifndef PWM0_CHANNEL_GPIOS -#define PWM0_CHANNEL_GPIOS { GPIO2, GPIO4, GPIO5 } -#endif +#define PWM_NUMOF (1) /**< Number of PWM devices */ -/** Alternative device definition */ -#define PWM0_DEV PWM_DEV(0) +#endif /* defined(PWM0_GPIOS) || defined(DOXYGEN) */ /** @} */ - /** - * @name SPI configuration + * @name SPI configuration + * + * ESP8266 has two SPI controllers: * - * ESP8266 provides two hardware SPI interfaces: + * - _CSPI_ for caching and accessing the flash memory
+ * - _HSPI_ for peripherals * - * _FSPI_ for flash memory and usually simply referred to as _SPI_
- * _HSPI_ for peripherals + * Thus, _HSPI_ is the only SPI interface that is available for peripherals. + * It is exposed as RIOT's SPI_DEV(0). Furthermore, the pin configuration of + * the _HSPI_ interface is fixed as shown in following table. * - * Even though _FSPI_ (or simply _SPI_) is a normal SPI interface, it is not - * possible to use it for peripherals. _HSPI_ is therefore the only usable - * SPI interface available for peripherals as RIOT's SPI_DEV(0). + * Signal | Pin + * -----------|------- + * #SPI0_MISO | GPIO12 + * #SPI0_MOSI | GPIO13 + * #SPI0_SCK | GPIO14 + * #SPI0_CS0 | GPIOn with n = 0, 2, 4, 5, 15, 16 (additionally 9, 10 in DOUT flash mode) * - * The pin configuration of the _HSPI_ interface SPI_DEV(0) is fixed. The - * only pin definition that can be overridden by an application-specific - * board configuration is the CS signal defined by SPI0_CS0_GPIO. + * The only pin definition that can be overridden by an application-specific + * board configuration is the CS signal defined by #SPI0_CS0. * - * Signal | Pin - * ----------------|------- - * SPI_DEV(0).MISO | GPIO12 - * SPI_DEV(0).MOSI | GPIO13 - * SPI_DEV(0).SCK | GPIO14 - * SPI_DEV(0).CS | GPIOn with n = 0, 2, 4, 5, 15, 16 (additionally 9, 10 in DOUT flash mode) * @{ */ -#if defined(MODULE_PERIPH_SPI) || defined(DOXYGEN) -#define SPI_NUMOF 1 /**< Number of SPI interfaces */ -#define SPI_DEV(x) ((unsigned int)(x+1)) /**< SPI_DEV to SPI hardware mapping */ +#define SPI0_DEV SPI_DEV(0) /**< HSPI / SPI_DEV(0) device */ +#define SPI0_CTRL HSPI /**< HSPI / SPI_DEV(0) controller */ +#define SPI0_MISO GPIO12 /**< HSPI / SPI_DEV(0) MISO pin */ +#define SPI0_MOSI GPIO13 /**< HSPI / SPI_DEV(0) MOSI pin */ +#define SPI0_SCK GPIO14 /**< HSPI / SPI_DEV(0) SCK pin */ -#define SPI0_DEV SPI_DEV(0) /**< HSPI / SPI_DEV(0) device */ -#define SPI0_MISO_GPIO GPIO12 /**< HSPI / SPI_DEV(0) MISO pin */ -#define SPI0_MOSI_GPIO GPIO13 /**< HSPI / SPI_DEV(0) MOSI pin */ -#define SPI0_SCK_GPIO GPIO14 /**< HSPI / SPI_DEV(0) SCK pin */ +#ifndef SPI0_CS0 +#define SPI0_CS0 GPIO15 /**< HSPI / SPI_DEV(0) CS default pin, only used when cs + parameter in spi_acquire is #GPIO_UNDEF */ +#endif -#ifndef SPI0_CS0_GPIO -#define SPI0_CS0_GPIO GPIO15 /**< HSPI / SPI_DEV(0) CS default pin, only used when cs - parameter in spi_acquire is GPIO_UNDEF */ +/** + * @brief Static array with configuration for declared SPI devices + */ +static const spi_conf_t spi_config[] = { +#ifdef SPI0_CTRL + { + .ctrl = SPI0_CTRL, + .sck = SPI0_SCK, + .mosi = SPI0_MOSI, + .miso = SPI0_MISO, + .cs = SPI0_CS0, + }, #endif -#endif /* defined(MODULE_PERIPH_SPI) || defined(DOXYGEN) */ +}; + +/** + * @brief Number of SPI interfaces + * + * The number of SPI interfaces is determined from board-specific peripheral + * definitions of SPIn_*. + * + * @note SPI_NUMOF definition must not be changed. + */ +#define SPI_NUMOF ARRAY_SIZE(spi_config) + /** @} */ /** @@ -153,9 +216,29 @@ extern "C" { * * @{ */ -#define UART_NUMOF 1 /**< Number of UART devices */ + #define UART0_TXD GPIO1 /**< TxD pin of UART_DEV(0) */ #define UART0_RXD GPIO3 /**< RxD pin of UART_DEV(0) */ + +/** + * @brief Static array with configuration for declared UART devices + */ +static const uart_conf_t uart_config[] = { + { + .txd = UART0_TXD, + .rxd = UART0_RXD, + }, +}; + +/** + * @brief Number of UART interfaces + * + * The number of UART interfaces is determined from board-specific peripheral + * definitions of UARTn_*. + * + * @note UART_NUMOF definition must not be changed. + */ +#define UART_NUMOF (sizeof(uart_config)/sizeof(uart_config[0])) /** @} */ #ifdef __cplusplus diff --git a/boards/esp8266-esp-12x/doc.txt b/boards/esp8266-esp-12x/doc.txt index 30ca331cc573..e70321ea93c5 100644 --- a/boards/esp8266-esp-12x/doc.txt +++ b/boards/esp8266-esp-12x/doc.txt @@ -82,7 +82,7 @@ D1 mini Pro | ESP8266EX | 16 MByte | ceramic | | Following image shows the pinout of all WEMOS LOLIN D1 mini boards. It is compatible with the WEMOS LOLIN D32 Pro ESP32 board. -@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp8266/Wemos_D1_mini_pinout.png?inline=false" "WEMOS LOLIN D1 min pinout"
+@image html "https://gitlab.com/gschorcht/RIOT.wiki-Images/raw/master/esp8266/Wemos_D1_mini_pinout.png?inline=false" "WEMOS LOLIN D1 mini pinout"
## NodeMCU DEVKIT diff --git a/boards/esp8266-esp-12x/include/board.h b/boards/esp8266-esp-12x/include/board.h index 1ab77c25feec..260cca81f54b 100644 --- a/boards/esp8266-esp-12x/include/board.h +++ b/boards/esp8266-esp-12x/include/board.h @@ -6,10 +6,6 @@ * directory for more details. */ -/** - * @ingroup boards_esp8266_esp-12x - */ - /** * @ingroup boards_esp8266_esp-12x * @brief Board specific definitions for ESP-12x based boards. diff --git a/boards/esp8266-esp-12x/include/periph_conf.h b/boards/esp8266-esp-12x/include/periph_conf.h index da08d17e5cb3..346d85624290 100644 --- a/boards/esp8266-esp-12x/include/periph_conf.h +++ b/boards/esp8266-esp-12x/include/periph_conf.h @@ -27,9 +27,6 @@ extern "C" { * @name I2C configuration * @{ */ -#ifndef I2C_NUMOF -#define I2C_NUMOF (1) /**< Number of I2C interfaces */ -#endif #ifndef I2C0_SPEED #define I2C0_SPEED I2C_SPEED_FAST /**< I2C bus speed of I2C_DEV(0) */ #endif @@ -41,6 +38,25 @@ extern "C" { #endif /** @} */ +/** + * @name PWM channel configuration + * + * @{ + */ + +/** + * @brief Declaration of the channels for device PWM_DEV(0), + * at maximum 8 channels. + * + * @note As long as PWM_DEV(0) is not initialized with \ref pwm_init, the GPIOs + * declared as PWM channels can be used for other purposes. + */ +#ifndef PWM0_GPIOS +#define PWM0_GPIOS { GPIO0, GPIO2, GPIO16 } +#endif + +/** @} */ + #ifdef __cplusplus } /* end extern "C" */ #endif diff --git a/boards/esp8266-olimex-mod/include/board.h b/boards/esp8266-olimex-mod/include/board.h index 38e540409ef0..4e62b87fb3dc 100644 --- a/boards/esp8266-olimex-mod/include/board.h +++ b/boards/esp8266-olimex-mod/include/board.h @@ -6,10 +6,6 @@ * directory for more details. */ -/** - * @ingroup boards_esp8266_olimex-mod - */ - /** * @ingroup boards_esp8266_olimex-mod * @brief Board specific definitions for diff --git a/boards/esp8266-olimex-mod/include/periph_conf.h b/boards/esp8266-olimex-mod/include/periph_conf.h index 428e14ef4f54..82566b726393 100644 --- a/boards/esp8266-olimex-mod/include/periph_conf.h +++ b/boards/esp8266-olimex-mod/include/periph_conf.h @@ -28,9 +28,6 @@ * @name I2C configuration * @{ */ -#ifndef I2C_NUMOF -#define I2C_NUMOF (1) /**< Number of I2C interfaces */ -#endif #ifndef I2C0_SPEED #define I2C0_SPEED I2C_SPEED_FAST /**< I2C bus speed of I2C_DEV(0) */ #endif @@ -42,6 +39,23 @@ #endif /** @} */ +/** + * @name PWM channel configuration + * + * @{ + */ + +/** + * @brief Declaration of the channels for device PWM_DEV(0), + * at maximum 8 channels. + * + * @note As long as PWM_DEV(0) is not initialized with \ref pwm_init, the GPIOs + * declared as PWM channels can be used for other purposes. + */ +#ifndef PWM0_GPIOS +#define PWM0_GPIOS { GPIO0, GPIO5, GPIO16 } +#endif + #ifdef __cplusplus } /* end extern "C" */ #endif diff --git a/boards/esp8266-sparkfun-thing/include/board.h b/boards/esp8266-sparkfun-thing/include/board.h index e40f67ac7ab3..343cd8152541 100644 --- a/boards/esp8266-sparkfun-thing/include/board.h +++ b/boards/esp8266-sparkfun-thing/include/board.h @@ -6,10 +6,6 @@ * directory for more details. */ -/** - * @ingroup boards_esp8266_sparkfun-thing - */ - /** * @ingroup boards_esp8266_sparkfun-thing * @brief Board specific definitions for diff --git a/boards/esp8266-sparkfun-thing/include/periph_conf.h b/boards/esp8266-sparkfun-thing/include/periph_conf.h index 07a8e8c4de33..c0ebfd1ce288 100644 --- a/boards/esp8266-sparkfun-thing/include/periph_conf.h +++ b/boards/esp8266-sparkfun-thing/include/periph_conf.h @@ -28,9 +28,6 @@ * @name I2C configuration * @{ */ -#ifndef I2C_NUMOF -#define I2C_NUMOF (1) /**< Number of I2C interfaces */ -#endif #ifndef I2C0_SPEED #define I2C0_SPEED I2C_SPEED_FAST /**< I2C bus speed of I2C_DEV(0) */ #endif @@ -42,6 +39,25 @@ #endif /** @} */ +/** + * @name PWM channel configuration + * + * @{ + */ + +/** + * @brief Declaration of the channels for device PWM_DEV(0), + * at maximum 8 channels. + * + * @note As long as PWM_DEV(0) is not initialized with \ref pwm_init, the GPIOs + * declared as PWM channels can be used for other purposes. + */ +#ifndef PWM0_GPIOS +#define PWM0_GPIOS { GPIO0, GPIO4, GPIO5 } +#endif + +/** @} */ + #ifdef __cplusplus } /* end extern "C" */ #endif diff --git a/cpu/esp32/exceptions.c b/cpu/esp32/exceptions.c index bd203165b107..55a236e39034 100644 --- a/cpu/esp32/exceptions.c +++ b/cpu/esp32/exceptions.c @@ -205,3 +205,10 @@ void IRAM NORETURN panic_arch(void) UNREACHABLE(); } + +void _panic_handler(uint32_t addr) +{ + ets_printf("#! _xt_panic called from 0x%08x: powering off\n", addr); + pm_off(); + while (1) { }; +} diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index de130d7ed4eb..f4281ff5e18e 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -170,7 +170,7 @@ typedef enum { * * ESP32 integrates two 12-bit ADCs (ADC1 and ADC2) capable of measuring up to * 18 analog signals in total. Most of these ADC channels are either connected - * to a number of intergrated sensors like a Hall sensors, touch sensors and a + * to a number of integrated sensors like a Hall sensors, touch sensors and a * temperature sensor or can be connected with certain GPIOs. Integrated * sensors are disabled in RIOT's implementation and are not accessible. Thus, * up to 18 GPIOs, the RTC GPIOs, can be used as ADC inputs: @@ -209,7 +209,7 @@ typedef enum { * determines the mapping between the RIOT's ADC lines and the GPIOs. * * @note ADC_GPIOS must be defined even if there are no GPIOs that could be - * used as ADC channels on the board. In this case, an empy list hast to be + * used as ADC channels on the board. In this case, an empty list hast to be * defined which just contains the curly braces. * * ADC_NUMOF is determined automatically from the ADC_GPIOS definition. @@ -240,7 +240,7 @@ typedef enum { #endif /* ndef DOXYGEN */ /** - * @brief Number of ADC cahnnels that could be used at maximum + * @brief Number of ADC channels that could be used at maximum * * @note GPIO37 and GPIO38 are usually not broken out on ESP32 modules and are * therefore not usable. The maximum number of ADC channels (ADC_NUMOF_MAX) @@ -263,7 +263,7 @@ typedef enum { * determines the mapping between the RIOT's DAC lines and the GPIOs. * * @note DAC_GPIOS must be defined even if there are no GPIOs that could be - * used as DAC channels on the board. In this case, an empy list hast to be + * used as DAC channels on the board. In this case, an empty list hast to be * defined which just contains the curly braces. * * DAC_NUMOF is determined automatically from the DAC_GPIOS definition. @@ -275,7 +275,7 @@ typedef enum { */ /** - * @brief Number of DAC cahnnels that could be used at maximum. + * @brief Number of DAC channels that could be used at maximum. */ #define DAC_NUMOF_MAX 2 @@ -287,7 +287,7 @@ typedef enum { * ESP32 has two built-in I2C interfaces. * * The board-specific configuration of the I2C interface I2C_DEV(n) requires - * the defintion of + * the definition of * * I2Cn_SPEED, the bus speed, * I2Cn_SCL, the GPIO used as SCL signal, and @@ -332,6 +332,11 @@ typedef struct { gpio_t sda; /**< GPIO used as SDA pin */ } i2c_conf_t; +/** + * @brief Maximum number of I2C interfaces that can be used by board definitions + */ +#define I2C_NUMOF_MAX (2) + #define PERIPH_I2C_NEED_READ_REG /**< i2c_read_reg required */ #define PERIPH_I2C_NEED_READ_REGS /**< i2c_read_regs required */ #define PERIPH_I2C_NEED_WRITE_REG /**< i2c_write_reg required */ @@ -340,7 +345,6 @@ typedef struct { /** * @name PWM configuration - * @{ * * PWM implementation uses ESP32's high-speed MCPWM modules. ESP32 has 2 such * modules, each with up to 6 channels (PWM_CHANNEL_NUM_DEV_MAX). Thus, the @@ -362,6 +366,8 @@ typedef struct { * @note As long as the GPIOs listed in PWM0_GPIOS and PMW1_GPIOS are not * initialized as PWM channels with the *pwm_init* function, they can be used * other purposes. + * + * @{ */ /** @@ -395,7 +401,7 @@ typedef struct { * device driver doesn't support it. * * The board-specific configuration of the SPI interface SPI_DEV(n) requires - * the defintion of + * the definition of * * - SPIn_CTRL, the SPI controller which is used for the interface (VSPI or HSPI), * - SPIn_SCK, the GPIO used as clock signal @@ -409,6 +415,8 @@ typedef struct { * * SPI_NUMOF is determined automatically from the board-specific peripheral * definitions of SPIn_*. + * + * @{ */ /** @@ -430,6 +438,11 @@ typedef struct { gpio_t cs; /**< GPIO used as CS0 pin */ } spi_conf_t; +/** + * @brief Maximum number of SPI interfaces that can be used by board definitions + */ +#define SPI_NUMOF_MAX 2 + #define PERIPH_SPI_NEEDS_TRANSFER_BYTE /**< requires function spi_transfer_byte */ #define PERIPH_SPI_NEEDS_TRANSFER_REG /**< requires function spi_transfer_reg */ #define PERIPH_SPI_NEEDS_TRANSFER_REGS /**< requires function spi_transfer_regs */ diff --git a/cpu/esp8266/Makefile b/cpu/esp8266/Makefile index 1b16977b69bc..ebb63f918f78 100644 --- a/cpu/esp8266/Makefile +++ b/cpu/esp8266/Makefile @@ -3,6 +3,7 @@ MODULE = cpu # Add a list of subdirectories, that should also be built: DIRS += $(RIOTCPU)/esp_common +DIRS += freertos DIRS += periph DIRS += sdk DIRS += vendor @@ -11,4 +12,6 @@ ifneq (, $(filter esp_wifi, $(USEMODULE))) DIRS += esp-wifi endif +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/esp8266/include/internal + include $(RIOTBASE)/Makefile.base diff --git a/cpu/esp8266/Makefile.dep b/cpu/esp8266/Makefile.dep index 9cd556e24f7f..88bfeb5923ff 100644 --- a/cpu/esp8266/Makefile.dep +++ b/cpu/esp8266/Makefile.dep @@ -1,17 +1,5 @@ # additional modules dependencies -ifneq (, $(filter esp_sdk, $(USEMODULE))) - USEMODULE += core_thread_flags - INCLUDES += -I$(ESP8266_SDK_DIR)/third_party/include - LINKFLAGS += -Wl,-wrap=malloc - LINKFLAGS += -Wl,-wrap=free - LINKFLAGS += -Wl,-wrap=calloc - LINKFLAGS += -Wl,-wrap=realloc - LINKFLAGS += -Wl,-wrap=_malloc_r - LINKFLAGS += -Wl,-wrap=_free_r - LINKFLAGS += -Wl,-wrap=_realloc_r -endif - ifneq (, $(filter esp_spiffs, $(USEMODULE))) export SPIFFS_STD_OPTION = -std=c99 USEMODULE += spiffs @@ -19,12 +7,9 @@ ifneq (, $(filter esp_spiffs, $(USEMODULE))) endif ifneq (, $(filter esp_wifi, $(USEMODULE))) - CFLAGS += -DLWIP_OPEN_SRC - LINKFLAGS += -Wl,-wrap=ethernet_input USEMODULE += netdev_eth endif -ifneq (,$(filter ndn-riot,$(USEPKG))) - USEMODULE += crypto - USEMODULE += cipher_modes +ifneq (,$(filter log_color,$(USEMODULE))) + USEMODULE += esp_log_colored endif diff --git a/cpu/esp8266/Makefile.features b/cpu/esp8266/Makefile.features index 3c3c6579de4d..82e159cedd6b 100644 --- a/cpu/esp8266/Makefile.features +++ b/cpu/esp8266/Makefile.features @@ -2,6 +2,7 @@ FEATURES_PROVIDED += arch_32bit FEATURES_PROVIDED += arch_esp8266 +FEATURES_PROVIDED += cpp FEATURES_PROVIDED += periph_cpuid FEATURES_PROVIDED += periph_hwrng FEATURES_PROVIDED += periph_pm diff --git a/cpu/esp8266/Makefile.include b/cpu/esp8266/Makefile.include index f488ed2f61da..1c7ba7e14e74 100644 --- a/cpu/esp8266/Makefile.include +++ b/cpu/esp8266/Makefile.include @@ -1,23 +1,13 @@ # check some environment variables first -ifndef ESP8266_NEWLIB_DIR - $(info ESP8266_NEWLIB_DIR should be defined as /path/to/newlib directory) - $(info ESP8266_NEWLIB_DIR is set by default to /opt/esp/newlib-xtensa) - export ESP8266_NEWLIB_DIR=/opt/esp/newlib-xtensa -endif - -ifndef ESP8266_SDK_DIR - $(info ESP8266_SDK_DIR should be defined as /path/to/sdk directory) - $(info ESP8266_SDK_DIR is set by default to /opt/esp/esp-open-sdk/sdk) - export ESP8266_SDK_DIR=/opt/esp/esp-open-sdk/sdk +ifndef ESP8266_RTOS_SDK_DIR + $(info ESP8266_RTOS_SDK_DIR should be defined as /path/to/sdk directory) + $(info ESP8266_RTOS_SDK_DIR is set by default to /opt/esp/ESP8266-RTOS-SDK) + export ESP8266_RTOS_SDK_DIR=/opt/esp/ESP8266-RTOS-SDK endif # Options to control the compilation -ifeq ($(USE_SDK), 1) - USEMODULE += esp_sdk -endif - ifeq ($(ENABLE_GDB), 1) USEMODULE += esp_gdb endif @@ -29,85 +19,117 @@ endif # SPECIAL module dependencies # cannot be done in Makefile.dep since Makefile.dep is included too late -ifneq (, $(filter esp_sw_timer, $(USEMODULE))) - USEMODULE += esp_sdk -endif - -ifneq (, $(filter esp_wifi, $(USEMODULE))) - $(eval GNRC_NETIF_NUMOF=$(shell echo $$(($(GNRC_NETIF_NUMOF)+1)))) - USEMODULE += esp_sdk - USEMODULE += netopt -endif - -ifneq (, $(filter esp_now, $(USEMODULE))) +ifneq (, $(filter esp_now esp_wifi, $(USEMODULE))) $(eval GNRC_NETIF_NUMOF=$(shell echo $$(($(GNRC_NETIF_NUMOF)+1)))) - USEMODULE += esp_sdk + CFLAGS += -DSCHED_PRIO_LEVELS=32 + USEMODULE += esp_wifi_any USEMODULE += netopt + USEMODULE += xtimer endif ifneq (, $(filter esp_gdbstub, $(USEMODULE))) USEMODULE += esp_gdb endif +ifneq (, $(filter spiffs, $(USEMODULE))) + export RIOT_TEST_TIMEOUT = 300 +endif + +ifneq (, $(filter littlefs, $(USEMODULE))) + export RIOT_TEST_TIMEOUT = 300 +endif + # regular Makefile -export TARGET_ARCH ?= xtensa-lx106-elf +export TARGET_ARCH ?= xtensa-esp8266-elf # ESP8266 pseudomodules PSEUDOMODULES += esp_gdb -PSEUDOMODULES += esp_sdk +PSEUDOMODULES += esp_log_colored +PSEUDOMODULES += esp_log_tagged +PSEUDOMODULES += esp_qemu PSEUDOMODULES += esp_sw_timer PSEUDOMODULES += esp_spiffs - -USEMODULE += esp +PSEUDOMODULES += esp_wifi_any + +USEMODULE += esp_freertos +USEMODULE += esp_idf +USEMODULE += esp_idf_esp8266 +USEMODULE += esp_idf_nvs_flash +USEMODULE += esp_idf_spi_flash +USEMODULE += esp_idf_util +USEMODULE += esp_idf_wpa_supplicant_crypto +USEMODULE += esp_sdk +USEMODULE += log USEMODULE += mtd USEMODULE += newlib -USEMODULE += newlib_nano USEMODULE += newlib_syscalls_default USEMODULE += periph +USEMODULE += periph_common +USEMODULE += periph_hrng +USEMODULE += periph_flash +USEMODULE += periph_uart USEMODULE += ps USEMODULE += random -USEMODULE += sdk USEMODULE += stdio_uart USEMODULE += xtensa -ifneq (, $(filter pthread, $(USEMODULE))) - # has to be included before $(ESP8266_NEWLIB_DIR) - INCLUDES += -I$(RIOTBASE)/sys/posix/pthread/include -endif - -INCLUDES += -I$(ESP8266_NEWLIB_DIR)/$(TARGET_ARCH)/include INCLUDES += -I$(RIOTBOARD)/common/$(CPU)/include INCLUDES += -I$(RIOTCPU)/esp_common/vendor/ INCLUDES += -I$(RIOTCPU)/$(CPU) +INCLUDES += -I$(RIOTCPU)/$(CPU)/include +INCLUDES += -I$(RIOTCPU)/$(CPU)/include/freertos INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor -INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/espressif - -CFLAGS += -DESP_OPEN_SDK -DSCHED_PRIO_LEVELS=32 -DCONTEXT_SWITCH_BY_INT +INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/ +INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/bootloader_support/include +INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/esp8266/include +INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/esp8266/include/esp8266 +INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/heap/include +INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/log/include +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/ +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/bootloader_support/include/ +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/esp8266/include +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/esp8266/include/esp8266 +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/heap/include +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/heap/port/esp8266/include +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/nvs_flash/include +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/spi_flash/include + +CFLAGS += -D__ESP_FILE__=__FILE__ CFLAGS += -Wno-unused-parameter -Wformat=0 -CFLAGS += -mlongcalls -mtext-section-literals -CFLAGS += -ffunction-sections -fdata-sections -fzero-initialized-in-bss +CFLAGS += -mlongcalls -mtext-section-literals -fstrict-volatile-bitfields +CFLAGS += -fdata-sections -ffunction-sections -fzero-initialized-in-bss + +OPTIONAL_CFLAGS_BLACKLIST += -fdiagnostics-color +OPTIONAL_CFLAGS_BLACKLIST += -Wformat-overflow +OPTIONAL_CFLAGS_BLACKLIST += -Wformat-truncation +OPTIONAL_CFLAGS_BLACKLIST += -gz + ASFLAGS += --longcalls --text-section-literals -ifneq (, $(filter esp_sdk, $(USEMODULE))) - INCLUDES += -I$(ESP8266_SDK_DIR)/include - CFLAGS += -DUSE_US_TIMER -endif +# thin archives trigger a reboot loop - see #12258, #12035, #12346 +ARFLAGS = rcs ifneq (, $(filter esp_gdbstub, $(USEMODULE))) GDBSTUB_DIR ?= $(RIOTCPU)/$(CPU)/vendor/esp-gdbstub - CFLAGS += -DGDBSTUB_FREERTOS=0 + CFLAGS += -DGDBSTUB_BREAK_ON_INIT=1 INCLUDES += -I$(GDBSTUB_DIR) endif ifneq (, $(filter esp_gdb, $(USEMODULE))) - CFLAGS += -Og -ggdb -g3 + CFLAGS_OPT ?= -Og -ggdb -g3 else - CFLAGS += -Os + # TODO should be -Os + # With -Os char arrays have not to be 32-bit word aligned. This leads to + # an alignment exception when the address of an char array is assigned to + # an uint32_t pointer and the pointer is used for the access. + CFLAGS_OPT ?= -O2 endif +CFLAGS += $(CFLAGS_OPT) + ifeq ($(QEMU), 1) - CFLAGS += -DQEMU + USEMODULE += esp_qemu endif ifeq ($(FLASH_MODE), qio) @@ -118,51 +140,80 @@ ifeq ($(FLASH_MODE), qout) CFLAGS += -DFLASH_MODE_QOUT endif -LINKFLAGS += -L$(ESP8266_NEWLIB_DIR)/$(TARGET_ARCH)/lib -LINKFLAGS += -L$(ESP8266_SDK_DIR)/lib +LINKFLAGS += -L$(ESP8266_RTOS_SDK_DIR)/components/esp8266/lib +LINKFLAGS += $(CFLAGS_OPT) -ifneq (, $(filter esp_sdk, $(USEMODULE))) - LINKFLAGS += -Wl,--start-group $(BINDIR)/sdk.a - ifneq (, $(filter esp_now, $(USEMODULE))) - LINKFLAGS += -lespnow - endif - LINKFLAGS += -lmain -lnet80211 -lcrypto -lwpa2 -lwpa -llwip -lpp -lphy -lc -lhal - LINKFLAGS += -Wl,--end-group - LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.riot-os.sdk.app.ld -else - LINKFLAGS += -Wl,--start-group -lphy -lhal -lc -Wl,--end-group - LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.riot-os.no_sdk.app.ld +BASELIBS += -lc -lgcc -lwpa -lcore -lnet80211 -lphy -lpp -lhal -lstdc++ + +ifneq (, $(filter esp_now, $(USEMODULE))) + BASELIBS += -lespnow endif -LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/eagle.rom.addr.v6.ld -LINKFLAGS += -nostdlib -lgcc -u ets_run -Wl,-gc-sections # -Wl,--print-gc-sections +LINKFLAGS += -u _malloc_r +LINKFLAGS += -nostdlib -Wl,-gc-sections -Wl,-static # -Wl,--print-gc-sections + +LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.rom.ld +LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.riot-os.ld +LINKFLAGS += -T$(RIOTCPU)/$(CPU)/ld/esp8266.peripherals.ld + +LINKFLAGS += -Wl,-wrap=pp_attach +LINKFLAGS += -Wl,-wrap=pm_attach + +ifneq (, $(filter esp_idf_heap, $(USEMODULE))) + LINKFLAGS += -Wl,-wrap=_malloc_r + LINKFLAGS += -Wl,-wrap=_calloc_r + LINKFLAGS += -Wl,-wrap=_free_r + LINKFLAGS += -Wl,-wrap=_realloc_r +endif # The ELFFILE is the base one used for flashing FLASHFILE ?= $(ELFFILE) # configure preflasher to convert .elf to .bin before flashing -FLASH_SIZE = -fs 8m -PREFLASHER ?= esptool.py -PREFFLAGS ?= elf2image $(FLASH_SIZE) $(FLASHFILE) +FLASH_MODE = dout # FIX configuration, DO NOT CHANGE +FLASH_FREQ = 26m # FIX configuration, DO NOT CHANGE +FLASH_SIZE ?= 1MB FLASHDEPS += preflash -# flasher configuration -ifeq ($(QEMU), 1) - FLASHER = cat - FFLAGS += $(FLASHFILE)-0x00000.bin /dev/zero | head -c $$((0x10000)) | cat - - FFLAGS += $(FLASHFILE)-0x10000.bin /dev/zero | head -c $$((0xfc000)) | cat - - FFLAGS += $(RIOTCPU)/$(CPU)/bin/esp_init_data_default.bin > $(FLASHFILE).bin +PREFLASHER ?= $(RIOTTOOLS)/esptool/esptool.py +PREFFLAGS = --chip esp8266 elf2image +PREFFLAGS += --flash_mode $(FLASH_MODE) --flash_size $(FLASH_SIZE) +PREFFLAGS += --flash_freq $(FLASH_FREQ) --version 3 +PREFFLAGS += -o $(FLASHFILE).bin $(FLASHFILE); +PREFFLAGS += echo "" > $(BINDIR)/partitions.csv; +PREFFLAGS += echo "nvs, data, nvs, 0x9000, 0x6000" >> $(BINDIR)/partitions.csv; +PREFFLAGS += echo "phy_init, data, phy, 0xf000, 0x1000" >> $(BINDIR)/partitions.csv; +PREFFLAGS += echo -n "factory, app, factory, 0x10000, " >> $(BINDIR)/partitions.csv; +PREFFLAGS += ls -l $(FLASHFILE).bin | awk '{ print $$5 }' >> $(BINDIR)/partitions.csv; + +PREFFLAGS += python $(RIOTCPU)/$(CPU)/vendor/esp-idf/partition_table/gen_esp32part.py +PREFFLAGS += --verify $(BINDIR)/partitions.csv $(BINDIR)/partitions.bin + +ifneq (, $(filter esp_log_colored, $(USEMODULE))) + BOOTLOADER ?= bootloader_dout_115200_color.bin +else + BOOTLOADER ?= bootloader_dout_115200_no_color.bin +endif + +ifneq (, $(filter esp_qemu, $(USEMODULE))) + FLASHER = dd + FFLAGS += if=/dev/zero bs=1M count=1 | tr "\\000" "\\377" > tmp.bin && + FFLAGS += cat $(RIOTCPU)/$(CPU)/bin/$(BOOTLOADER) tmp.bin | + FFLAGS += head -c $$((0x8000)) | + FFLAGS += cat - $(BINDIR)/partitions.bin tmp.bin | + FFLAGS += head -c $$((0x10000)) | + FFLAGS += cat - $(FLASHFILE).bin tmp.bin | + FFLAGS += head -c $$((0xfc000)) | + FFLAGS += cat - $(RIOTCPU)/$(CPU)/bin/esp_init_data_default.bin tmp.bin | + FFLAGS += head -c $$((0x100000)) > $(BINDIR)/esp8266flash.bin && rm tmp.bin else - FLASH_MODE ?= dout export PROGRAMMER_SPEED ?= 460800 - FLASHER = esptool.py - FFLAGS += -p $(PROG_DEV) -b $(PROGRAMMER_SPEED) write_flash - FFLAGS += -fm $(FLASH_MODE) - FFLAGS += 0 $(FLASHFILE)-0x00000.bin - FFLAGS += 0x10000 $(FLASHFILE)-0x10000.bin; esptool.py -p $(PROG_DEV) run + FLASHER = $(RIOTBASE)/dist/tools/esptool/esptool.py + FFLAGS += --chip esp8266 --port $(PROG_DEV) --baud $(PROGRAMMER_SPEED) + FFLAGS += --before default_reset write_flash -z + FFLAGS += --flash_size detect + FFLAGS += --flash_mode $(FLASH_MODE) --flash_freq $(FLASH_FREQ) + FFLAGS += 0x0000 $(RIOTCPU)/$(CPU)/bin/$(BOOTLOADER) + FFLAGS += 0x8000 $(BINDIR)/partitions.bin + FFLAGS += 0x10000 $(FLASHFILE).bin endif - -OPTIONAL_CFLAGS_BLACKLIST += -fdiagnostics-color -OPTIONAL_CFLAGS_BLACKLIST += -Wformat-overflow -OPTIONAL_CFLAGS_BLACKLIST += -Wformat-truncation -OPTIONAL_CFLAGS_BLACKLIST += -gz diff --git a/cpu/esp8266/bin/bootloader_dout_115200_color.bin b/cpu/esp8266/bin/bootloader_dout_115200_color.bin new file mode 100644 index 000000000000..daff33c59ca9 Binary files /dev/null and b/cpu/esp8266/bin/bootloader_dout_115200_color.bin differ diff --git a/cpu/esp8266/bin/bootloader_dout_115200_no_color.bin b/cpu/esp8266/bin/bootloader_dout_115200_no_color.bin new file mode 100644 index 000000000000..7a7d3d7f4f99 Binary files /dev/null and b/cpu/esp8266/bin/bootloader_dout_115200_no_color.bin differ diff --git a/cpu/esp8266/doc.txt b/cpu/esp8266/doc.txt index 616cb5c1849f..2b17cce82ec2 100644 --- a/cpu/esp8266/doc.txt +++ b/cpu/esp8266/doc.txt @@ -10,12 +10,9 @@ 1. [Overview](#esp8266_overview) 2. [Short Configuration Reference](#esp8266_short_configuration_reference) 3. [MCU ESP8266](#esp8266_mcu_esp8266) - 1. [Features of ESP8266](#esp8266_features) - 2. [Features Supported by RIOT-OS](#esp8266_supported_features) 4. [Toolchain](#esp8266_toolchain) 1. [RIOT Docker Toolchain (riotdocker)](#esp8266_riot_docker_toolchain) - 2. [Precompiled Toolchain](#esp8266_precompiled_toolchain) - 3. [Manual Toolchain Installation](#esp8266_manual_toolchain_installation) + 2. [Manual Toolchain Installation](#esp8266_manual_toolchain_installation) 5. [Flashing the Device](#esp8266_flashing_the_device) 1. [Toolchain Usage](#esp8266_toolchain_usage) 2. [Compile Options](#esp8266_compile_options) @@ -24,9 +21,9 @@ 6. [Peripherals](#esp8266_peripherals) 1. [GPIO pins](#esp8266_gpio_pins) 2. [ADC Channels](#esp8266_adc_channels) - 3. [PWM Channels](#esp8266_pwm_channels) + 3. [SPI Interfaces](#esp8266_spi_interfaces) 4. [I2C Interfaces](#esp8266_i2c_interfaces) - 5. [SPI Interfaces](#esp8266_spi_interfaces) + 5. [PWM Channels](#esp8266_pwm_channels) 6. [Timers](#esp8266_timers) 7. [SPIFFS Device](#esp8266_spiffs_device) 8. [Other Peripherals](#esp8266_other_peripherals) @@ -39,42 +36,51 @@ 9. [Application-Specific Configurations](#esp8266_application_specific_configurations) 1. [Application-Specific Board Configuration](#esp8266_application_specific_board_configuration) 2. [Application-Specific Driver Configuration](#esp8266_application_specific_driver_configuration) -10. [SDK Task Handling](#esp8266_sdk_task_handling) -11. [QEMU Mode and GDB](#esp8266_qemu_mode_and_gdb) - +10. [SDK Specific Information](#esp8266_sdk_specifics) + 1. [Tasks](#esp8266_sdk_tasks) + 2. [Heap](#esp8266_esp_idf_heap_implementation) +11. [Debugging](#esp8266_debugging) + 1. [QEMU Mode and GDB](#esp8266_qemu_mode_and_gdb) + 2. [Module esp_gdbstub](#esp8266_esp_gdbstub) # Overview    [[TOC](#esp8266_toc)] -There are two implementations that can be used: - -- the **SDK version** which is realized on top of an SDK (*esp-open-sdk* or - *ESP8266_NONOS_SDK*) and -- the **non-SDK version** which is realized without the SDK. - -The non-SDK version produces a much smaller code size than the SDK version and -is more efficient in execution because it does not need to run additional SDK -functions to keep the SDK system alive. +RIOT-Xtensa-ESP is a bare metal implementation of RIOT-OS for +ESP8266 / ESP8285 SOCs which supports most features of RIOT-OS. The +peripheral SPI and I2C interfaces allow to connect all external hardware +modules supported by RIOT-OS, such as sensors and actuators. SPI interface +can also be used to connect external IEEE802.15.4 modules to integrate +ESP8266 boards into a GNRC network. -The **non-SDK version** is probably the **best choice if you do not need the -built-in WiFi module**, for example, when you plan to connect an IEEE 802.15.4 -radio module to the MCU for communication. - -By **default**, the **non-SDK version** is compiled. To compile the SDK -version, enable module `esp_wifi`, for example, at the make command line: +The RIOT-OS port for ESP8266 supports ESP8266 as well as ESP8285 MCUs and requires +the [ESP8266 RTOS SDK v3.x](https://github.com/espressif/ESP8266_RTOS_SDK). +To build a RIOT application, simply use the `make` command and specify an +existing ESP8266 board, for example: ``` -USEMODULE=esp_sdk make flash BOARD=esp8266-esp-12x -C tests/shell ... +make flash BOARD=esp8266-esp-12x -C tests/shell ... ``` -The SDK version is compiled automatically if one of the modules `esp_wifi`, -`esp_now` or `esp_sw_timers` is enabled. +For more information about the `make` command variables and specific compile +options, see section [Compile Options](#esp8266_compile_options). + +Although the port does not use the official ESP8266 RTOS SDK directly, +it must be installed for compilation. The reason is that the port uses most of +the ESP8266 SOC definitions provided by SDK header files. In addition, +it needs the hardware abstraction library (libhal), and ESP8266 WiFi stack +binary libraries which are part of the SDK. + +# MCU ESP8266  [[TOC](#esp8266_toc)] -For more information about the make command variables, see section -[Compile Options](#esp8266_compile_options). +ESP8266 is a low-cost, ultra-low-power, single-core SoCs with an integrated +WiFi module from Espressif Systems. The processor core is based on the +Tensilica Xtensa Diamond Standard 106Micro 32-bit Controller Processor Core, +which Espressif calls L106. The key features of ESP8266 are: # Short Configuration Reference  [[TOC](#esp8266_toc)] -The following table gives a short reference of all board configuration parameters used by the ESP8266 port in alphabetical order. +The following table gives a short reference of all board configuration +parameters used by the ESP8266 port in alphabetical order.
@@ -82,13 +88,16 @@ Parameter | Short Description | Type* ----------|----------------------------------------|------ [I2C0_SPEED](#esp8266_i2c_interfaces)| Bus speed of I2C_DEV(0) | o [I2C0_SCL](#esp8266_i2c_interfaces) | GPIO used as SCL for I2C_DEV(0) | o -[I2C0_SDA](#esp8266_i2c_interfaces) | GPIO used as SCL for I2C_DEV(0 | o -[PWM0_GPIOS](#esp8266_pwm_channels) | GPIOs that can be used at channels of PWM_DEV(0) | o +[I2C0_SDA](#esp8266_i2c_interfaces) | GPIO used as SCL for I2C_DEV(0) | o +[I2C1_SPEED](#esp8266_i2c_interfaces)| Bus speed of I2C_DEV(1) | o +[I2C1_SCL](#esp8266_i2c_interfaces) | GPIO used as SCL for I2C_DEV(1) | o +[I2C1_SDA](#esp8266_i2c_interfaces) | GPIO used as SCL for I2C_DEV(1) | o +[PWM0_GPIOS](#esp8266_pwm_channels) | GPIOs that can be used at channels of PWM_DEV(0) | o [SPI0_CS0](#esp8266_spi_interfaces) | GPIO used as default CS for SPI_DEV(0) | o
-Type: m - mandatory, o - optional# MCU ESP8266  [[TOC](#esp8266_toc)] +*Type: m - mandatory, o - optional The following table gives a short reference in alphabetical order of modules that can be enabled/disabled by board configurations and/or application's makefile using `USEMODULE` and `DISABLE_MODULE`. @@ -96,21 +105,16 @@ The following table gives a short reference in alphabetical order of modules th Module | Default | Short description ----------|----------|------------------- -[esp_gdb](#esp8266_qemu_mode_and_gdb) | not used | Enable the compilation with debug information for debugging. -[esp_now](#esp8266_esp_now_network_interface) | not used | Enable the ESP-NOW network device, implies the module `esp_sdk`. -[esp_sdk](#esp8266_sdk_task_handling) | not used | Enable the SDK version. -[esp_spiffs](#esp8266_spiffs_device) | not used | Enable the SPIFFS drive in on-board flash memory. -[esp_sw_timer](#esp8266_timers) | not used | Enable software timer implementation, implies the module `esp_sdk`. -[esp_wifi](#esp8266_wifi_network_interface) | not used | Enable the built-in WiFi module as `netdev` network device, implies the module `esp_sdk`. +[esp_gdb](#esp8266_qemu_mode_and_gdb) | not used | enable the compilation with debug information for debugging +[esp_gdbstub](#esp8266_esp_gdbstub) | not used | enable the compilation of the `gdbstub` interface +[esp_idf_heap](#esp8266_esp_idf_heap_implementation) | not used | use SDK heap implementation +[esp_now](#esp8266_esp_now_network_interface) | not used | enable the ESP-NOW network device +[esp_qemu](#esp8266_qemu_mode_and_gdb) | not used | generate image for `QEMU` and `GDB` debugging +[esp_spiffs](#esp8266_spiffs_device) | not used | enable SPIFFS for on-board flash memory +[esp_wifi](#esp8266_wifi_network_interface) | not used | enable the Wifi network device -ESP8266 is a low-cost, ultra-low-power, single-core SoCs with an integrated WiFi module from Espressif Systems. The processor core is based on the Tensilica Xtensa Diamond Standard 106Micro 32-bit Controller Processor Core, which Espressif calls L106. The key features of ESP8266 are: - -## Features of ESP8266  [[TOC](#esp8266_toc)] - -The key features of ESP8266 are: -
MCU | ESP8266EX @@ -135,319 +139,323 @@ Technical Reference | [Technical Reference](https://www.espressif.com/sites/defa

-@note ESP8285 is simply an ESP8266 SoC with 1 MB built-in flash. Therefore, the documentation also applies to the SoC ESP8285, even if only the ESP8266 SoC is described below. +@note ESP8285 is simply an ESP8266 SoC with 1 MB built-in flash. Therefore, the +documentation also applies to the SoC ESP8285, even if only the ESP8266 SoC is +described below. -## Features Supported by RIOT-OS  [[TOC](#esp8266_toc)] +# Toolchain -The RIOT-OS for ESP8266 SoCs supports the following features at the moment: +The following software components are required for compilation: -- I2C interfaces -- SPI interfaces -- UART interfaces -- CPU ID access -- ADC channel -- PWM channels -- SPI Flash Drive (MTD with SPIFFS and VFS) -- Hardware number generator -- Hardware timer devices -- ESP-NOW netdev interface +- Xtensa GCC compiler suite for ESP8266 +- Modified ESP8266 RTOS SDK which includes all SOC definitions and + some binary libraries +- Modified version of ESP flash programmer tool `esptool.py` +There are two options to install the toolchain: -# Toolchain  [[TOC](#esp8266_toc)] +- using RIOT Docker (riotdocker), see section + [RIOT Docker Toolchain (riotdocker)](#esp8266_riot_docker_toolchain) +- manual installation, see section [Manual Toolchain Installation](#esp8266_manual_toolchain_installation) -To compile RIOT for The ESP8266 SoC, the following software components are required: +In both cases, the ESP flash programmer tool `esptool.py` is required, +see section [Installation of `esptool.py`](#esp8266_installation_of_esptool). -- **esp-open-sdk** which includes the **Xtensa GCC** compiler toolchain, the hardware abstraction library **libhal** for Xtensa LX106, and the flash programmer tool `esptool.py` -- **newlib-c** library for Xtensa (esp-open-rtos version) -- **SDK (optional)**, either as part of `esp-open-sdk` or the `ESP8266_NONOS_SDK` +## RIOT Docker Toolchain (riotdocker)  [[TOC](#esp8266_toc)] -You have the following options to install the Toolchain: +The easiest way to install the toolchain is to use RIOT Docker +`riotdocker`. The compilation process using RIOT Docker consists of two steps -- `riotdocker` image and `esptool.py`, see section [RIOT Docker Toolchain (riotdocker)](#esp8266_riot_docker_toolchain) -- **precompiled toolchain** installation from GIT, see section [Precompiled Toolchain](#esp8266_toolchain_installation) -- **manual installation**, see section [Manual Toolchain Installation](#esp8266_manual_toolchain_installation) +1. making the RIOT application in RIOT Docker with command `make BOARD=...` +2. flashing the RIOT application on the host computer with command + `make flash-only BOARD=...` -## RIOT Docker Toolchain (riotdocker)  [[TOC](#esp8266_toc)] +where step 2 requires that the ESP flash programmer tool `esptool.py` is +installed. Both steps can also be performed with a single command on the host +system using the `BUILD_IN_DOCKER` variable: -The easiest way to use the toolchain is Docker. +``` +BUILD_IN_DOCKER=1 make BOARD=... flash +``` ### Preparing the Environment  [[TOC](#esp8266_toc)] -Using RIOT Docker requires at least the following software: +Using RIOT Docker requires at least the following software components: + +- Docker container virtualization software +- RIOT Docker image (`riotdocker`) +- ESP flash programmer tool `esptool.py` -- `Docker` container virtualization software -- RIOT Docker (`riotdocker`) image -- flasher tool `esptool.py` +For information about installing Docker on your host, refer to the appropriate +manuals for your operating system. The easiest way to install Docker on an +Ubuntu/Debian system is for example: -For information about installing Docker on your host, refer to the appropriate manuals for your operating system. For example, the easiest way to install Docker on the Ubuntu/Debian system is: ``` sudo apt-get install docker.io ``` -The ESP Flasher tool `esptool.py` is available at [GitHub](https://github.com/espressif/esptool). To install the tool, either Python 2.7 or Python 3.4 or later must be installed. The latest stable version of `esptool.py` can be installed with `pip`: -``` -pip install esptool -``` +For information on how to install `esptool.py`, see section +[Installation of `esptool.py`](#esp8266_installation_of_esptool). -`esptool.py` depends on `pySerial` which can be installed either using `pip` +### Using an Existing RIOT Docker Image  [[TOC](#esp8266_toc)] + +The easiest way to use RIOT Docker is to use an existing `riotdocker` image. +You can either pull and start the +[schorcht/riotbuild_esp8266_rtos](https://hub.docker.com/r/schorcht/riotbuild_esp8266_rtos) +Docker image which only contains the toolchain for ESP8266 RTOS SDK using ``` -pip install pyserial +cd /path/to/RIOT +docker run -i -t -u $UID -v $(pwd):/data/riotbuild schorcht/riotbuild_esp8266_rtos_sdk ``` -or the package manager of your OS, for example on Debian/Ubuntu systems: + +or the [riot/riotbuild](https://hub.docker.com/r/riot/riotbuild/) Docker image +(size is about 1.5 GB) which contains the toolchains for all platforms using + ``` -apt-get install pyserial +cd /path/to/RIOT +docker run -i -t -u $UID -v $(pwd):/data/riotbuild riot/riotbuild ``` -For more information on `esptool.py`, please refer the [git repository](https://github.com/espressif/esptool) - -Please make sure that `esptool.py` is in your `PATH` variable. ### Generating a riotdocker Image  [[TOC](#esp8266_toc)] -A `riotdocker` fork that only installs the `RIOT-Xtensa-ESP8266-toolchain` is available at [GitHub](https://github.com/gschorcht/riotdocker-Xtensa-ESP.git). After cloning this git repository, you can use branch `esp8266_only` to generate a Docker image with a size of "only" 990 MByte: +Alternatively, you can generate the `riotdocker` image by yourself. +A `riotdocker` fork that only installs the toolchain for ESP8266 RTOS SDK is +available at [GitHub](https://github.com/gschorcht/riotdocker-Xtensa-ESP.git). +After cloning this repository, checkout branch `esp8266_only_rtos_sdk` to +generate a Docker image with a size of "only" 890 MByte: ``` +cd $HOME/esp git clone https://github.com/gschorcht/riotdocker-Xtensa-ESP.git cd riotdocker-Xtensa-ESP -git checkout esp8266_only +git checkout esp8266_only_rtos_sdk docker build -t riotbuild . ``` -A `riotdocker` version that contains the toolchains for all different RIOT platforms can be found at [GitHub](https://github.com/RIOT-OS/riotdocker). However, the Docker image generated from the this Docker file has a size of about 1.5 GByte. -Once a Docker image has been created, it can be started with the following commands while in the RIOT root directory: +A `riotdocker` version that contains toolchains for all platforms supported +by RIOT can be found at [GitHub](https://github.com/RIOT-OS/riotdocker). +However, the Docker image generated from this Docker file has a size of +about 1.5 GByte. + +Once the Docker image has been created, it can be started with the following +commands while in the RIOT root directory: + ``` cd /path/to/RIOT -docker run -i -t --privileged -v /dev:/dev -u $UID -v $(pwd):/data/riotbuild riotbuild +docker run -i -t -u $UID -v $(pwd):/data/riotbuild riotbuild ``` -@note RIOT's root directory `/path/to/RIOT` becomes visible as the home directory of the `riotbuild` user in the Docker image. That is, the output of compilations performed in RIOT Docker is also accessible on the host system. -Please refer the [RIOT wiki](https://github.com/RIOT-OS/RIOT/wiki/Use-Docker-to-build-RIOT) on how to use the Docker image to compile RIOT OS. +@note RIOT's root directory `/path/to/RIOT` becomes visible as the home +directory of the `riotbuild` user in the Docker. That is, the output +of compilations in RIOT Docker are also accessible on the host system. -### Using an Existing riotdocker Image  [[TOC](#esp8266_toc)] +Please refer the [RIOT wiki](https://github.com/RIOT-OS/RIOT/wiki/Use-Docker-to-build-RIOT) +on how to use the Docker image to compile RIOT OS. -Alternatively, an existing Docker image from Docker Hub can be used. You can either pull and start the [schorcht/riotbuild_esp8266](https://hub.docker.com/r/schorcht/riotbuild_esp8266) Docker image which only contains the `RIOT-Xtensa-ESP8266-toolchain` using -``` -cd /path/to/RIOT -docker run -i -t --privileged -v /dev:/dev -u $UID -v $(pwd):/data/riotbuild schorcht/riotbuild_esp8266 -``` -or the [riot/riotbuild](https://hub.docker.com/r/riot/riotbuild/) Docker image (size is about 1.5 GB) which contains the toolchains for all platforms using -``` -cd /path/to/RIOT -docker run -i -t --privileged -v /dev:/dev -u $UID -v $(pwd):/data/riotbuild riot/riotbuild -``` -### Make Process with Docker Image  [[TOC](#esp8266_toc)] +### Make Process with RIOT Docker  [[TOC](#esp8266_toc)] -Using Docker, the make process consists of the following two steps: +Using RIOT Docker, the make process consists of the following two steps: -1. **making** the RIOT binary **within a RIOT Docker image** +1. **making** the RIOT binary **within RIOT Docker** 2. **flashing** the RIOT binary using a flasher program **on the host system** -Once the RIOT Docker image has been started from RIOT's root directory, a RIOT application can be compiled inside the Docker using the make command as usual, for example: +Once the according RIOT Docker image has been started from RIOT's root +directory, a RIOT application can be compiled inside RIOT Docker using the +make command as usual, for example: ``` make BOARD=esp8266-esp-12x -C tests/shell ... ``` This will generate a RIOT binary in ELF format. -@note You can't use the `flash` target inside the Docker image. - -The RIOT binary has to be flash outside docker on the host system. Since the Docker image was stared while in RIOT's root directory, the output of the compilations is also accessible on the host system. On the host system, the `flash-only` target can then be used to flash the binary. -``` -make flash-only BOARD=esp8266-esp-12x -C tests/shell -``` - - -## Precompiled Toolchain  [[TOC](#esp8266_toc)] - -You can get a precompiled version of the whole toolchain from the GIT repository [RIOT-Xtensa-ESP8266-toolchain](https://github.com/gschorcht/RIOT-Xtensa-ESP8266-toolchain). This repository contains the precompiled toolchain including all libraries that are necessary to compile RIOT-OS for ESP8266. - -@note To use the precompiled toolchain the following packages (Debian/Ubuntu) have to be installed:
`cppcheck` `coccinelle` `curl` `doxygen` `git` `graphviz` `make` `pcregrep` `python` `python-serial` `python3` `python3-flake8` `unzip` `wget` - -To install the toolchain use the following commands: -``` -cd /opt -sudo git clone https://github.com/gschorcht/RIOT-Xtensa-ESP8266-toolchain.git esp -``` -After the installation, all components of the toolchain are installed in directory `/opt/esp`. Of course, you can use any other location for the installation. +@note You can't use the `flash` target inside RIOT Docker. -To use the toolchain, you have to add the path of the binaries to your `PATH` variable according to your toolchain location +The RIOT binary has to be flash outside RIOT Docker on the host system. Since +the RIOT Docker image was started while in RIOT's root directory, the output +of the compilations is also accessible on the host system. On the host system, +the `flash-only` target can then be used to flash the binary. ``` -export PATH=$PATH:/path/to/toolchain/esp-open-sdk/xtensa-lx106-elf/bin -``` -where `/path/to/toolchain/` is the directory you selected for the installation of the toolchain. For the default installation in `/opt/esp` this would be: -``` -export PATH=$PATH:/opt/esp/esp-open-sdk/xtensa-lx106-elf/bin +make flash-only BOARD=esp8266-esp-12x -C tests/shell ``` -Furthermore, you have to set variables `ESP8266_SDK_DIR` and `ESP8266_NEWLIB_DIR` according to the location of the toolchain. +@note Both steps can also be performed with a single command on the host +system using the `BUILD_IN_DOCKER` variable: ``` -export ESP8266_SDK_DIR=/path/to/toolchain/esp-open-sdk/sdk -export ESP8266_NEWLIB_DIR=/path/to/toolchain/newlib-xtensa +`BUILD_IN_DOCKER=1 make BOARD=... flash ``` -If you have used `/opt/esp` as installation directory, it is not necessary to set these variables since makefiles use them as default directories. ## Manual Toolchain Installation  [[TOC](#esp8266_toc)] -The most difficult way to install the toolchain is the manual installation of required components as described below. +A more difficult way to install the toolchain is the manual installation of +all required components as described below. -@note Manual toolchain installation requires that the following packages (Debian/Ubuntu) are installed: `autoconf` `automake` `bash` `bison` `build-essential` `bzip2` `coccinelle` `cppcheck` `curl` `doxygen` `g++` `gperf` `gawk` `gcc` `git` `graphviz` `help2man` `flex` `libexpat-dev` `libtool` `libtool-bin` `make` `ncurses-dev` `pcregrep` `python` `python-dev` `python-serial` `python3` `python3-flake8` `sed` `texinfo` `unrar-free` `unzip wget` +@note To install the toolchain manually, a 64-bit Linux system is required. +Furthermore, the following packages (Debian/Ubuntu) have to be installed:
+`build-essential`, `cppcheck`, `coccinelle`, `curl`, `doxygen`, `git`, +`graphviz`, `make`, `pcregrep`, `python`, `python-serial`, `python3`, +`python3-flake8`, `unzip`, `wget` -### Installation of esp-open-sdk  [[TOC](#esp8266_toc)] +### Installation of Xtensa GCC compiler suite  [[TOC](#esp8266_toc)] -esp-open-sdk is directly installed inside its source directory. Therefore, change directly to the target directory of the toolchain to build it. +The Xtensa GCC compiler for ESP8266 configured for use with RIOT-OS can +be downloaded and installed as precompiled binary archive from +[GitHub](https://github.com/gschorcht/xtensa-esp8266-elf): ``` -cd /path/to/esp -git clone --recursive https://github.com/pfalcon/esp-open-sdk.git -cd esp-open-sdk -export ESP_OPEN_SDK_DIR=$PWD +mkdir -p $HOME/esp +cd $HOME/esp +git clone https://github.com/gschorcht/xtensa-esp8266-elf ``` -If you plan to use the SDK version of the RIOT port and to use the SDK as part of esp-open-sdk, simply build its standalone version. +Once the compiler is installed, you have to expand your `PATH` variable by +the directory with Xtensa GCC binaries: ``` -make STANDALONE=y +export PATH=$HOME/esp/xtensa-esp8266-elf/bin:$PATH ``` -If you only plan to use the non-SDK version of the RIOT port or if you want to use one of Espressif's original SDKs, it is enough to build the toolchain. +### Installation of the ESP8266 RTOS SDK  [[TOC](#esp8266_toc)] -``` -make toolchain esptool libhal STANDALONE=n -``` - -Once compilation has been finished, the toolchain is available in `$PWD/xtensa-lx106-elf/bin`. To use it, set the `PATH` variable accordingly. +To compile RIOT-OS with the ESP8266 RTOS SDK, a modified version of the SDK is +required. This modified version can also be downloaded as +[GIT](https://github.com/gschorcht/RIOT-Xtensa-ESP8266-RTOS-SDK.git) repository. ``` -export PATH=$ESP_OPEN_SDK_DIR/xtensa-lx106-elf/bin:$PATH +cd $HOME/esp +git clone https://github.com/gschorcht/RIOT-Xtensa-ESP8266-RTOS-SDK.git ESP8266_RTOS_SDK +cd ESP8266_RTOS_SDK/ +git checkout release/v3.1-for-riot-os ``` +@note +- Please be sure to checkout the correct branch that was used for the +RIOT-OS port. Other versions will not work because they do not have the +necessary changes. +- Since we only use a few header files and some binary libraries, ESP8266 RTOS +SDK does not need to be compiled in any way. -If you have compiled the standalone version of esp-open-sdk and you plan to use this SDK version, set additionally the `ESP8266_SDK_DIR` variable. +To use the installed ESP8266 RTOS SDK, set the environment variable +`ESP8266_RTOS_SDK_DIR`. ``` -export ESP8266_SDK_DIR=$ESP_OPEN_SDK_DIR/sdk +export ESP8266_RTOS_SDK_DIR=$HOME/esp/ESP8266_RTOS_SDK ``` -### Installation of newlib-c  [[TOC](#esp8266_toc)] - -First, set the target directory for the installation. - -``` -export ESP8266_NEWLIB_DIR=/path/to/esp/newlib-xtensa -``` - -Please take care, to use the newlib-c version that was modified for esp-open-rtos since it includes `stdatomic.h`. - -``` -cd /my/source/dir -git clone https://github.com/ourairquality/newlib.git -``` - -Once you have cloned the GIT repository, build and install it with following commands. -``` -cd newlib -./configure --prefix=$ESP8266_NEWLIB_DIR --with-newlib --enable-multilib --disable-newlib-io-c99-formats --enable-newlib-supplied-syscalls --enable-target-optspace --program-transform-name="s&^&xtensa-lx106-elf-&" --disable-option-checking --with-target-subdir=xtensa-lx106-elf --target=xtensa-lx106-elf --enable-newlib-nano-formatted-io --enable-newlib-reent-small -make -make install -``` -### Installation of Espressif original SDK (optional)  [[TOC](#esp8266_toc)] +### Installation of `esptool.py` (ESP flash programmer tool)  [[TOC](#esp8266_toc)] -If you plan to use the SDK version of the RIOT port and if you want to use one of Espressif's original SDKs, you have to install it. +The RIOT port does not work with the `esptool.py` ESP flasher program +available on [GitHub](https://github.com/espressif/esptool) or +as package for your OS. +Instead, a modified version from the ESP8266 RTOS SDK is required. -First, download the _ESP8266_NONOS_SDK_ version 2.1.0 from the [Espressif web site](https://github.com/espressif/ESP8266_NONOS_SDK/releases/tag/v2.1.0). Probably other version might also work. However, RIOT port is tested with version 2.1.0. +To avoid the installation of the complete ESP8266 RTOS SDK, for example +because RIOT Docker `riotdocker` is used for compilation, `esptool.py` +has been extracted from the ESP8266 RTOS SDK and placed in RIOT's +directory `dist/tools/esptool`. +For convenience, the build system uses always the version from this directory. -Once you have downloaded it, you can install it with following commands. +Therefore, it is **not necessary to install** `esptool.py` explicitly. However +`esptool.py` depends on `pySerial` which can be installed either +using `pip` ``` -cd /path/to/esp -tar xvfz /downloads/ESP8266_NONOS_SDK-2.1.0.tar.gz +sudo pip install pyserial ``` - -To use the installed SDK, set variable `ESP8266_SDK_DIR` accordingly. - +or the package manager of your OS, for example on Debian/Ubuntu systems: ``` -export ESP8266_SDK_DIR=/path/to/esp/ESP8266_NONOS_SDK-2.1.0 +apt install python-pyserial ``` +For more information on `esptool.py`, please refer the +[git repository](https://github.com/espressif/esptool). # Flashing the Device  [[TOC](#esp8266_toc)] ## Toolchain Usage  [[TOC](#esp8266_toc)] -Once you have installed all required components, you should have the following directories. +Once you have installed all required components, you should have the following +directories. ``` -/path/to/esp/esp-open-sdk -/path/to/esp/newlib-xtensa -/path/to/esp/ESP8266_NONOS_SDK-2.1.0 (optional) +/path/to/esp/xtensa-esp8266-elf +/path/to/esp/ESP8266_RTOS_SDK ``` -To use the toolchain and optionally the SDK, please check that your environment variables are set correctly to - -``` -export PATH=/path/to/esp/esp-open-sdk/xtensa-lx106-elf/bin:$PATH -export ESP8266_NEWLIB_DIR=/path/to/esp/newlib-xtensa -``` -and -``` -export ESP8266_SDK_DIR=/path/to/esp/esp-open-sdk/sdk -``` -or +To use the toolchain, please ensure that your environment variables are set +correctly to ``` -export ESP8266_SDK_DIR=/path/to/esp/ESP8266_NONOS_SDK-2.1.0 +export PATH=/path/to/esp/xtensa-esp8266-elf/bin:$PATH +export ESP8266_RTOS_SDK_DIR=/path/to/esp/ESP8266_RTOS_SDK ``` ## Compile Options  [[TOC](#esp8266_toc)] -The compilation process can be controlled by a number of variables for the make command: +The compilation process can be controlled by following make variables:
Option | Values | Default | Description -------|--------|---------|------------ -ENABLE_GDB | 0, 1 | 0 | Enable compilation with debug information for debugging with QEMU (`QEMU=1`), see section [QEMU Mode and GDB](#esp8266_qemu_mode_and_gdb) FLASH_MODE | dout, dio, qout, qio | dout | Set the flash mode, please take care with your module, see section [Flash Modes](#esp8266_flash_modes) -PORT | /dev/ttyUSBx | /dev/* | Set the USB port for flashing the firmware -QEMU | 0, 1 | 0 | Generate an image for QEMU, see section [QEMU Mode and GDB](#esp8266_qemu_mode_and_gdb). -USE_SDK | 0, 1 | 0 | Compile the SDK version (`USE_SDK=1`), see section [SDK Task Handling](#esp8266_sdk_task_handling) +PORT | /dev/<port> | /dev/USB0 | Set the USB port for flashing the firmware

-Optional features of ESP8266 can be enabled by `USEMODULE` definitions in the makefile of the application. These are: +Optional features of ESP8266 can be enabled using `USEMODULE` definitions +in the makefile of the application. These are:
Module | Description -------|------------ -[esp_gdb](#esp8266_qemu_mode_and_gdb) | Enable the compilation with debug information, which is equivalent to using `ENABLE_GDB=1`. -[esp_now](#esp8266_esp_now_network_interface) | Enable the built-in WiFi module with the ESP-NOW protocol as `netdev` network device, implies the setting module `esp_sdk`. -[esp_sdk](#esp8266_sdk_task_handling) | Enable the SDK version, which is equivalent to using `USE_SDK=1`. +[esp_gdb](#esp8266_qemu_mode_and_gdb) | Enable the compilation with debug information +[esp_gdbstub](#esp8266_esp_gdbstub) | Enable the compilation of the `gdbstub` interface for debugging with `GDB` +[esp_idf_heap](#esp8266_esp_idf_heap_implementation) | Enable SDK heap implementation which provides remaining IRAM as additional heap region +[esp_now](#esp8266_esp_now_network_interface) | Enable the built-in WiFi module with the ESP-NOW protocol as `netdev` network device +[esp_qemu](#esp8266_qemu_mode_and_gdb) | Enable the compilation of an `QEMU` image for debugging with `GDB` [esp_spiffs](#esp8266_spiffs_device) | Enable the SPIFFS drive in on-board flash memory -[esp_sw_timer](#esp8266_timers) | Enable software timer implementation, implies the setting module `esp_sdk`. -[esp_wifi](#esp8266_wifi_network_interface) | Use the built-in WiFi module as `netdev` network device, implies the setting module `esp_sdk`. +[esp_sw_timer](#esp8266_timers) | Enable software timer implementation +[esp_wifi](#esp8266_wifi_network_interface) | Enable the built-in WiFi module in infrastructure mode as `netdev` network device

-For example, to activate the SPIFFS drive in on-board flash memory, the makefile of application has simply to add the `esp_spiffs` module to `USEMODULE` make variable: +For example, to activate the SPIFFS drive in on-board flash memory, the +makefile of application has simply to add the `esp_spiffs` module to +`USEMODULE` make variable: + ``` USEMODULE += esp_spiffs ``` -Modules can also be activated temporarily at the command line when calling the make command: +Modules can also be activated temporarily at the command line when calling +the make command: + ``` USEMODULE="esp_spiffs" make BOARD=... ``` ## Flash Modes  [[TOC](#esp8266_toc)] -The `FLASH_MODE` make command variable determines the mode that is used for flash access in normal operation. +The `FLASH_MODE` make command variable determines the mode that is used for +flash access in normal operation. -The flash mode determines whether 2 data lines (`dio` and `dout`) or 4 data lines (`qio` and `qout`) for addressing and data access. For each data line, one GPIO is required. Therefore, using `qio` or `qout` increases the performance of SPI Flash data transfers, but uses two additional GPIOs (GPIO9 and GPIO10). That is, in this flash modes these GPIOs are not available for other purposes. If you can live with lower flash data transfer rates, you should always use `dio` or `dout` to keep GPIO9 and GPIO10 free for other purposes. +The flash mode determines whether 2 data lines (`dio` and `dout`) or 4 data +lines (`qio` and `qout`) for addressing and data access. For each data line, +one GPIO is required. Therefore, using `qio` or `qout` increases the +performance of SPI Flash data transfers, but uses two additional GPIOs +(GPIO9 and GPIO10). That is, in this flash modes these GPIOs are not +available for other purposes. If you can live with lower flash data +transfer rates, you should always use `dio` or `dout` to keep GPIO9 and +GPIO10 free for other purposes. -For more information about these flash modes, refer the documentation of [esptool.py](https://github.com/espressif/esptool/wiki/SPI-Flash-Modes). +For more information about these flash modes, refer the documentation of +[esptool.py](https://github.com/espressif/esptool/wiki/SPI-Flash-Modes). -@note While ESP8266 modules can be flashed with `qio`, `qout`, `dio` and `dout`, ESP8285 modules have to be always flashed in `dout` mode. The default flash mode is `dout`. +@note While ESP8266 modules can be flashed with `qio`, `qout`, `dio` and +`dout`, ESP8285 modules have to be always flashed in `dout` mode. The +default flash mode is `dout`. ## Erasing the Device  [[TOC](#esp8266_toc)] @@ -456,32 +464,12 @@ The flash memory of ESP8266 can be erased completely with following command: esptool.py erase_flash ``` -@note After deleting the flash, the default init data must be rewritten. In a non-SDK version, this will happen automatically when RIOT is started for the first time after flashing the image. In the SDK version, this must be done explicitly. There are two possible approaches to rewriting standard initialization data: - -- Flash and start a non-SDK image before the SDK version is flashed. -- Use the esptool.py file to update the default init data as following. - -``` -esptool.py write_flash
$RIOTBASE/cpu/esp8266/bin/esp_init_data_default.bin -``` - -where `address` depends on ESP8266 chip version. - -Chip version | `address` | Module examples ------------- | ------------- | ---------------- -512 kByte | 0x07c000 | ESP-01, ESP-03, ESP-07, etc. -1 MByte | 0x0fc000 | ESP8285-based modules like Wemos D1 mini lite, PSF-A85, some ESP-01, ESP-03 etc. -2 MByte | 0x1fc000 | | -4 MByte | 0x3fc000 | ESP-12E, NodeMCU devkit 1.0, WeMos D1 mini -8 MByte | 0x7fc000 | | -16 MByte | 0xffc000 | WeMos D1 mini pro (USE 0x07c000!) - - # Peripherals  [[TOC](#esp8266_toc)] ## GPIO pins  [[TOC](#esp8266_toc)] -ESP8266 has 17 GPIO pins, which are all digital pins. Some of them can not be used at all or have bootstrapping capabilities and are therefore not available on all boards. +ESP8266 has 17 GPIO pins, which are all digital pins. Some of them can not be +used at all or have bootstrapping capabilities and are therefore not available on all boards.
@@ -507,7 +495,8 @@ GPIO16 | RTC pin and wake up signal in deep sleep mode
-GPIO0, GPIO2, and GPIO15 are bootstrapping pins which are used to boot ESP8266 in different modes: +GPIO0, GPIO2, and GPIO15 are bootstrapping pins which are used +to boot ESP8266 in different modes:
@@ -521,43 +510,60 @@ GPIO0 | GPIO2 | GPIO15 (MTDO) | Mode ## ADC Channels  [[TOC](#esp8266_toc)] -ESP8266 has **one dedicated ADC** pin with a resolution of 10 bits. This ADC pin can measure voltages in the range of **0 V ... 1.1 V**. +ESP8266 has **one dedicated ADC** pin with a resolution of 10 bits. This ADC +pin can measure voltages in the range of **0 V ... 1.1 V**. -@note Some boards have voltage dividers to scale this range to a maximum of 3.3 V. For more information, see the hardware manual for the board. +@note Some boards have voltage dividers to scale this range to a maximum of +3.3 V. For more information, see the hardware manual for the board. -## PWM Channels  [[TOC](#esp8266_toc)] +## SPI Interfaces  [[TOC](#esp8266_toc)] -The hardware implementation of ESP8266 PWM supports only frequencies as power of two. Therefore, a **software implementation** of **one PWM device** (`PWM_DEV(0)`) with up to **8 PWM channels** (`PWM_CHANNEL_NUM_MAX`) is used. +ESP8266 has two SPI controllers: -@note The minimum PWM period that can be realized with this software implementation is 10 us or 100.000 PWM clock cycles per second. Therefore, the product of frequency and resolution should not be greater than 100.000. Otherwise the frequency is scaled down automatically. +- _CSPI_ for caching and accessing the flash memory
+- _HSPI_ for peripherals -GPIOs that can be used as channels of the PWM device `PWM_DEV(0)` are defined by `PWM0_CHANNEL_GPIOS`. By default, GPIOs 2, 4 and 5 are defined as PWM channels. As long as these channels are not started with function `pwm_set`, they can be used as normal GPIOs for other purposes. +Thus, _HSPI_ is the only SPI interface that is available for peripherals. +It is exposed as RIOT's SPI_DEV(0). The pin configuration of the _HSPI_ +interface is fixed as shown in following table. -GPIOs in `PWM0_CHANNEL_GPIOS` with a duty cycle value of 0 can be used as normal GPIOs for other purposes. GPIOs in `PWM0_CHANNEL_GPIOS` that are used for other purposes, e.g., I2C or SPI, are no longer available as PWM channels. +
-To define other GPIOs as PWM channels, just overwrite the definition of `PWM_CHANNEL_GPIOS` in an [application-specific board configuration](#esp8266_application_specific_board_configuration) +Signal | Pin +-----------|------- +#SPI0_MISO | GPIO12 +#SPI0_MOSI | GPIO13 +#SPI0_SCK | GPIO14 +#SPI0_CS0 | GPIOn with n = 0, 2, 4, 5, 15, 16 (additionally 9, 10 in DOUT flash mode) -``` -#define PWM0_CHANNEL_GPIOS { GPIO12, GPIO13, GPIO14, GPIO15 } -``` +
-## I2C Interfaces  [[TOC](#esp8266_toc)] +The only pin definition that can be overridden by an application-specific +board configuration is the CS signal defined by #SPI0_CS0. -Since the ESP8266 does not or only partially support the I2C in hardware, I2C interfaces are realized as **bit-banging protocol in software**. The maximum usable bus speed is `I2C_SPEED_FAST_PLUS`. The maximum number of buses that can be defined is 2, `I2C_DEV(0)` ... `I2C_DEV(1)`. +When the SPI is enabled using module `periph_spi`, these GPIOs cannot be +used for any other purpose. GPIOs 0, 2, 4, 5, 15, and 16 can be used as CS +signal. In `dio` and `dout` flash modes (see section +[Flash Modes](#esp8266_flash_modes)), GPIOs 9 and 10 can also be used as +CS signal. -The board-specific configuration of the I2C interface `I2C_DEV(n)` requires the definition of +## I2C Interfaces  [[TOC](#esp8266_toc)] -- `I2Cn_SPEED`, the bus speed, -- `I2Cn_SCL`, the GPIO used as SCL signal, and -- `I2Cn_SDA`, the GPIO used as SDA signal, +Since the ESP8266 does not or only partially support the I2C in hardware, +I2C interfaces are realized as **bit-banging protocol in software**. The +maximum usable bus speed is therefore #I2C_SPEED_FAST_PLUS. The maximum +number of buses that can be defined is 2, #I2C_DEV(0) and #I2C_DEV(1). -where `n` can be 0 or 1. If they are not defined, the I2C interface `I2C_DEV(n)` is not used. +GPIO pins (#I2C0_SCL, #I2C0_SDA and/or `I2C1_SCL`, `I2C1_SDA`) +have to be defined in the board-specific peripheral configuration in +`$BOARD/periph_conf.h`. Furthermore, the default I2C bus speed (#I2C0_SPEED +and/or `I2C1_SPEED`) that is used for I2C bus(ses) has to be defined. The +number of configured buses #I2C_NUMOF is then determined automatically +from these definitions. In the following example, only one I2C bus is defined: ``` -#define I2C_NUMOF (1) - #define I2C0_SPEED I2C_SPEED_FAST #define I2C0_SDA GPIO4 #define I2C0_SCL GPIO5 @@ -565,8 +571,6 @@ In the following example, only one I2C bus is defined: A configuration with two I2C buses would look like the following: ``` -#define I2C_NUMOF (2) - #define I2C0_SPEED I2C_SPEED_FAST #define I2C0_SDA GPIO4 #define I2C0_SCL GPIO5 @@ -576,64 +580,71 @@ A configuration with two I2C buses would look like the following: #define I2C1_SCL GPIO14 ``` -All these configurations can be overridden by an [application-specific board configuration](#esp8266_application_specific_board_configuration). - -## SPI Interfaces  [[TOC](#esp8266_toc)] +All these configurations can be overridden by an +[application-specific board configuration](#esp8266_application_specific_board_configuration). -ESP8266 provides two hardware SPI interfaces: - -- _FSPI_ for flash memory access that is usually simply referred to as _SPI_ -- _HSPI_ for peripherals - -Even though _FSPI_ (or simply _SPI_) is a normal SPI interface, it is not possible to use it for peripherals. **HSPI is therefore the only usable SPI interface** available for peripherals as RIOT's `SPI_DEV(0)`. - -The pin configuration of the _HSPI_ interface is defined as shown in the following table. Only the CS signal can be configured and overridden by [application-specific card configuration] (# esp8266_application_specific_board_configuration). +## PWM Channels  [[TOC](#esp8266_toc)] -
+The hardware implementation of ESP8266 PWM supports only frequencies as power +of two. Therefore, a **software implementation** of **one PWM device** +(#PWM_DEV(0)) with up to **8 PWM channels** (#PWM_CHANNEL_NUM_MAX) is used. -Signal of _HSPI_ | Pin ------------------|------- -MISO | GPIO12 -MOSI | GPIO13 -SCK | GPIO14 -CS | GPIO15 +@note The minimum PWM period that can be realized with this software +implementation is 10 us or 100.000 PWM clock cycles per second. Therefore, +the product of frequency and resolution should not be greater than 100.000. +Otherwise the frequency is scaled down automatically. -
+The GPIOs that can be used as channels of the PWM device #PWM_DEV(0) are +defined by #PWM0_GPIOS. By default, all GPIOs that are not used as I2C, SPI, +or UART signals are defined as PWM channels in board definition. As long as +these channels are not initialized with function #pwm_init, they can be used as +normal GPIOs for other purposes. Even if they are already initialized, but +have a duty cycle value of 0 can be used as output GPIOs for other purposes. +GPIOs in #PWM0_GPIOS that are used for other purposes, e.g., I2C or SPI, are +no longer available as PWM channels. -When SPI is enabled using module `periph_spi`, these GPIOs cannot be used for any other purpose. The given CS pin is used when `spi_acquire` is called with `cs=GPIO_UNDEF` parameter. +To define other GPIOs as PWM channels, just overwrite the definition of +#PWM0_GPIOS in an +[application-specific board configuration](#esp8266_application_specific_board_configuration) -To the default CS can be overridden as following: ``` -#define SPI0_CS0_GPIO GPIO15 /* HSPI/SPI_DEV(0) CS default pin */ +#define PWM0_GPIOS { GPIO12, GPIO13, GPIO14, GPIO15 } ``` -GPIOs 0, 2, 4, 5, 15, and 16 can be used as CS signal. In `dio` and `dout` flash modes (see section [Flash Modes](#esp8266_flash_modes)), GPIOs 9 and 10 can also be used as CS signal. - ## Timers  [[TOC](#esp8266_toc)] There are two timer implementations: -- **hardware timer** implementation with **1 timer device** and only **1 channel**, the default -- **software timer** implementation with **1 timer device** and only **10 channels** +- **hardware timer** implementation with **1 timer device** and + only **1 channel** (default) +- **software timer** implementation with **1 timer device** and **10 channels** By default, the **hardware timer implementation** is used. -When the SDK version of the RIOT port (`USE_SDK=1`) is used, the **software timer** implementation is activated by using module `esp_sw_timer`. - -The software timer uses SDK's software timers to implement the timer channels. Although these SDK timers usually have a precision of a few microseconds, they can deviate up to 500 microseconds. So if you need a timer with high accuracy, you'll need to use the hardware timer with only one timer channel. - -@note When module `esp_sw_timer` is used, the SDK version is automatically compiled (`USE_SDK=1`). +Software timers use SDK's timers to implement the timer device and the channels. +Although these SDK timers usually have a precision of a few microseconds, they +can deviate up to 500 microseconds. So if you need a timer with high accuracy, +you'll need to use the hardware timer with only one timer channel. ## SPIFFS Device  [[TOC](#esp8266_toc)] -If SPIFFS module is enabled (`USEMODULE += esp_spiffs`), the implemented MTD system drive `mtd0` for the on-board SPI flash memory is used together with modules `spiffs` and `vfs` to realize a persistent file system. +If SPIFFS module is enabled (`USEMODULE += esp_spiffs`), the implemented +MTD system drive #mtd0 for the on-board SPI flash memory is used together +with modules `spiffs` and `vfs` to realize a persistent file system. -For this purpose, the flash memory is formatted as SPIFFS starting at the address `0x80000` (512 kByte) on first boot. All sectors up to the last 5 sectors of the flash memory are then used for the file system. With a fixed sector size of 4096 bytes, the top address of the SPIFF is `flash_size - 5 * 4096`, e.g., `0xfb000` for a flash memory of 1 MByte. The size of the SPIFF then results from: +For this purpose, the flash memory is formatted as SPIFFS starting at the +address `0x80000` (512 kByte) on first boot. All sectors up to the last +5 sectors of the flash memory are then used for the file system. With a +fixed sector size of 4096 bytes, the top address of the SPIFF is +`flash_size - 5 * 4096`, e.g., `0xfb000` for a flash memory of 1 MByte. +The size of the SPIFF then results from: ``` flash_size - 5 * 4096 - 512 kByte ``` -Please refer file `$RIOTBASE/tests/unittests/test-spiffs/tests-spiffs.c` for more information on how to use SPIFFS and VFS together with a MTD device `mtd0` alias `MTD_0`. +Please refer file `$RIOTBASE/tests/unittests/test-spiffs/tests-spiffs.c` +for more information on how to use SPIFFS and VFS together with a MTD +device #mtd0 alias `MTD_0`. ## Other Peripherals  [[TOC](#esp8266_toc)] @@ -650,19 +661,18 @@ RTC is not yet implemented. ESP8266 provides different built-in possibilities to realize network devices: -- ESP WiFi, usual AP-based infrastructure mode wireless LAN -- ESP-NOW, a WiFi based AP-less and connectionless peer to peer communication protocol +- ESP WiFi, usual AP-based wireless LAN (not yet supported) +- ESP-NOW, a WiFi based AP-less and connectionless peer to + peer communication protocol \anchor esp8266_wifi_network_interface ## WiFi Network Interface  [[TOC](#esp8266_toc)] -The RIOT port for ESP8266 implements in module `esp_wifi` a `netdev` driver for +The RIOT port for ESP8266 implements in module `esp_wifi` a `netdev` +driver for the built-in WiFi interface. -@note Due to symbol conflicts with the `crypto` and `hash` modules of RIOT -in vendor library `libwpa.so`, which is required by module -`esp_wifi`, `esp_wifi` cannot be used for applications that use these modules. -Therefore, module **`esp_wifi` is not automatically enabled** when module +@note Module `esp_wifi` is not automatically enabled when module `netdev_default` is used. Instead, if necessary, the application has to add the module `esp_wifi` in the Makefile. @@ -674,17 +684,18 @@ Furthermore, the following configuration parameters have to be defined:
-Parameter | Default | Description -:------------------|:--------------------------|:------------ -ESP_WIFI_SSID | "RIOT_AP" | SSID of the AP to be used. -ESP_WIFI_PASS | "ThisistheRIOTporttoESP" | Passphrase used for the AP as clear text (max. 64 chars). -ESP_WIFI_STACKSIZE | 1536 | Stack size used for the WiFi netdev driver thread. +Parameter | Default | Description +:-------------------|:--------------------------|:------------ +#ESP_WIFI_SSID | "RIOT_AP" | SSID of the AP to be used. +#ESP_WIFI_PASS | "ThisistheRIOTporttoESP" | Passphrase used for the AP as clear text (max. 64 chars). +#ESP_WIFI_STACKSIZE | #THREAD_STACKSIZE_DEFAULT |Stack size used for the WiFi netdev driver thread.
These configuration parameter definitions, as well as enabling the `esp_wifi` module, can be done either in the makefile of the project or at make command line, e.g.: + ``` USEMODULE=esp_wifi \ CFLAGS='-DESP_WIFI_SSID=\"MySSID\" -DESP_WIFI_PASS=\"MyPassphrase\"' \ @@ -702,18 +713,17 @@ border router for a mesh network which uses ESP-NOW. With ESP-NOW, the ESP8266 provides a connectionless communication technology, featuring short packet transmission. It applies the IEEE802.11 Action Vendor frame technology, along with the IE function developed by Espressif, and CCMP -encryption technology, realizing a secure, connectionless communication solution. +encryption technology, realizing a secure, connectionless communication +solution. The RIOT port for ESP8266 implements in module `esp_now` a `netdev` driver which uses ESP-NOW to provide a link layer interface to a meshed network of ESP8266 nodes. In this network, each node can send short packets with up to 250 data bytes to all other nodes that are visible in its range. -@note Due to symbol conflicts in vendor library `libwpa.so` used by the -`esp_now` with RIOT's `crypto` and `hashes` modules, ESP-NOW cannot be used -for application that use these modules. Therefore, the module **`esp_now` is -not enabled automatically** if the `netdev_default` module is used. Instead, -the application has to add the `esp_now` module in its makefile when needed.
+@note Module `esp_now` is not enabled automatically if the `netdev_default` +module is used. Instead, the application has to add the `esp_now` module in +its makefile when needed.
``` USEMODULE += esp_now ``` @@ -725,30 +735,19 @@ its SoftAP WiFi interface. The driver periodically scans all visible ESP8266 nodes. The following parameters are defined for ESP-NOW nodes. These parameters can -be overriden by [application-specific board configurations](#esp8266_application_specific_board_configuration). +be overridden by [application-specific board configurations](#esp8266_application_specific_board_configuration).
Parameter | Default | Description :---------|:--------|:----------- -ESP_NOW_SCAN_PERIOD | 10000000UL | Defines the period in us at which an node scans for other nodes in its range. The default period is 10 s. -ESP_NOW_SOFT_AP_PASS | "ThisistheRIOTporttoESP" | Defines the passphrase as clear text (max. 64 chars) that is used for the SoftAP interface of ESP-NOW nodes. It has to be same for all nodes in one network. -ESP_NOW_CHANNEL | 6 | Defines the channel that is used as the broadcast medium by all nodes together. -ESP_NOW_KEY | NULL | Defines a key that is used for encrypted communication between nodes. If it is NULL, encryption is disabled. The key has to be of type `uint8_t[16]` and has to be exactly 16 bytes long. -ESP_WIFI_STACKSIZE | @ref THREAD_STACKSIZE_DEFAULT | Stack size used for the WiFi netdev driver thread. +#ESP_NOW_SCAN_PERIOD | 10000000UL | Defines the period in us at which an node scans for other nodes in its range. The default period is 10 s. +#ESP_NOW_SOFT_AP_PASS | "ThisistheRIOTporttoESP" | Defines the passphrase as clear text (max. 64 chars) that is used for the SoftAP interface of ESP-NOW nodes. It has to be same for all nodes in one network. +#ESP_NOW_CHANNEL | 6 | Defines the channel that is used as the broadcast medium by all nodes together. +#ESP_NOW_KEY | NULL | Defines a key that is used for encrypted communication between nodes. If it is NULL, encryption is disabled. The key has to be of type `uint8_t[16]` and has to be exactly 16 bytes long.
-These configuration parameter definitions, as well as enabling the `esp_wifi` -module, can be done either in the makefile of the project or at make command -line, e.g.: - -``` -USEMODULE=esp_now \ -CFLAGS='-DESP_NOW_CHANNEL=8 -DESP_NOW_SOFT_AP_PASS=\"MyPassphrase\"' \ -make -C examples/gnrc_networking BOARD=... -``` - @note The ESP-NOW network interface (module `esp_now`) and the [Wifi network interface](#esp8266_wifi_network_interface) (module `esp_wifi`) can be used simultaneously, for example, to realize a border router for @@ -756,42 +755,52 @@ a mesh network which uses ESP-NOW. # Preconfigured Devices  [[TOC](#esp8266_toc)] -The ESP8266 port of RIOT has been tested with several common external devices that can be connected to ESP8266 boards and are preconfigured accordingly. +The ESP8266 port of RIOT has been tested with several common external +devices that can be connected to ESP8266 boards and are preconfigured +accordingly. ## Network Devices  [[TOC](#esp8266_toc)] -RIOT provides a number of driver modules for different types of network devices, e.g., IEEE 802.15.4 radio modules and Ethernet modules. The RIOT port for ESP8266 has been tested with the following network devices: +RIOT provides a number of driver modules for different types of network +devices, e.g., IEEE 802.15.4 radio modules and Ethernet modules. The RIOT +port for ESP8266 has been tested with the following network devices: -- [mrf24j40](https://riot-os.org/api/group__drivers__mrf24j40.html) (driver for Microchip MRF24j40 based IEEE 802.15.4 -- [enc28j60](https://riot-os.org/api/group__drivers__enc28j60.html) (driver for Microchip ENC28J60 based Ethernet modules) +- [mrf24j40](https://riot-os.org/api/group__drivers__mrf24j40.html) + (driver for Microchip MRF24j40 based IEEE 802.15.4 +- [enc28j60](https://riot-os.org/api/group__drivers__enc28j60.html) + (driver for Microchip ENC28J60 based Ethernet modules) ### Using MRF24J40 (module `mrf24j40`)  [[TOC](#esp8266_toc)] -To use MRF24J40 based IEEE 802.15.4 modules as network device, the `mrf24j40` driver module has to be added to the makefile of the application: +To use MRF24J40 based IEEE 802.15.4 modules as network device, the +`mrf24j40` driver module has to be added to the makefile of the application: ``` USEMODULE += mrf24j40 ``` -The `mrf24j40` driver module uses the following preconfigured interface parameters for ESP8266 boards: +The `mrf24j40` driver module uses the following preconfigured interface +parameters for ESP8266 boards:
-Parameter | Default | Remarks ------------------------|--------------|---------------------------- -MRF24J40_PARAM_SPI | SPI_DEV(0) | fixed, see section [SPI Interfaces](#esp8266_spi_interfaces) -MRF24J40_PARAM_SPI_CLK | SPI_CLK_1MHZ | fixed -MRF24J40_PARAM_CS | GPIO16 | can be overridden -MRF24J40_PARAM_INT | GPIO0 | can be overridden -MRF24J40_PARAM_RESET | GPIO2 | can be overridden +Parameter | Default | Remarks +------------------------|--------------|---------------------------- +#MRF24J40_PARAM_SPI | SPI_DEV(0) | fixed, see section [SPI Interfaces](#esp8266_spi_interfaces) +#MRF24J40_PARAM_SPI_CLK | SPI_CLK_1MHZ | fixed +#MRF24J40_PARAM_CS | GPIO16 | can be overridden +#MRF24J40_PARAM_INT | GPIO0 | can be overridden +#MRF24J40_PARAM_RESET | GPIO2 | can be overridden

-The GPIOs in this configuration can be overridden by [application-specific board configurations](#esp8266_application_specific_board_configuration). +The GPIOs in this configuration can be overridden by +[application-specific board configurations](#esp8266_application_specific_board_configuration). ### Using ENC28J60 (module `enc28j60`)  [[TOC](#esp8266_toc)] -To use ENC28J60 Ethernet modules as network device, the `enc28j60` driver module has to be added to the makefile of the application: +To use ENC28J60 Ethernet modules as network device, the `enc28j60` driver +module has to be added to the makefile of the application: ``` USEMODULE += enc28j60 @@ -801,65 +810,91 @@ The `enc28j60` driver module uses the following preconfigured interface paramete
-Parameter | Default | Remarks ----------------------|--------------|---------------------------- -ENC28J60_PARAM_SPI | SPI_DEV(0) | fixed, see section [SPI Interfaces](#esp8266_spi_interfaces) -ENC28J60_PARAM_CS | GPIO4 | can be overridden -ENC28J60_PARAM_INT | GPIO9 | can be overridden -ENC28J60_PARAM_RESET | GPIO10 | can be overridden +Parameter | Default | Remarks +----------------------|--------------|---------------------------- +#ENC28J60_PARAM_SPI | SPI_DEV(0) | fixed, see section [SPI Interfaces](#esp8266_spi_interfaces) +#ENC28J60_PARAM_CS | GPIO4 | can be overridden +#ENC28J60_PARAM_INT | GPIO9 | can be overridden +#ENC28J60_PARAM_RESET | GPIO10 | can be overridden
-The GPIOs in this configuration can be overridden by [application-specific board configurations](#esp8266_application_specific_board_configuration). +The GPIOs in this configuration can be overridden by +[application-specific board configurations](#esp8266_application_specific_board_configuration). ## SD-Card Device  [[TOC](#esp8266_toc)] -ESP8266 port of RIOT is preconfigured for RIOT applications that use the [SPI SD-Card driver](https://riot-os.org/api/group__drivers__sdcard__spi.html). To use SPI SD-Card driver, the `sdcard_spi` module has to be added to a makefile: +ESP8266 port of RIOT is preconfigured for RIOT applications that use the +[SPI SD-Card driver](https://riot-os.org/api/group__drivers__sdcard__spi.html). +To use SPI SD-Card driver, the `sdcard_spi` module has to be added to +a makefile: ``` USEMODULE += sdcard_spi ``` -The `sdcard_spi` driver module uses the following preconfigured interface parameters for ESP8266 boards: +The `sdcard_spi` driver module uses the following preconfigured interface +parameters for ESP8266 boards:
-Parameter | Default | Remarks ------------------------|---------------|---------------------------- -SDCARD_SPI_PARAM_SPI | SPI0_DEV | fix, see section [SPI Interfaces](#esp8266_spi_interfaces) -SDCARD_SPI_PARAM_CS | SPI0_CS0_GPIO | can be overridden +Parameter | Default | Remarks +------------------------|-------------|---------------------------- +#SDCARD_SPI_PARAM_SPI | #SPI_DEV(0) | fix, see section [SPI Interfaces](#esp8266_spi_interfaces) +#SDCARD_SPI_PARAM_CS | #SPI0_CS0 | can be overridden
-The GPIO used as CS signal can be overridden by [application-specific board configurations](#esp8266_application_specific_board_configuration). +The GPIO used as CS signal can be overridden by +[application-specific board configurations](#esp8266_application_specific_board_configuration). \anchor esp8266_app_spec_conf # Application-Specific Configurations  [[TOC](#esp8266_toc)] -The board-specific configuration files `board.h` and `periph_conf.h` as well as the driver parameter configuration files `_params.h` define the default configurations for peripherals and device driver modules. These are, for example, the GPIOs used, bus interfaces used or available bus speeds. Because there are many possible configurations and many different application requirements, these default configurations are usually only a compromise between different requirements. +The board-specific configuration files `board.h` and `periph_conf.h` as +well as the driver parameter configuration files `_params.h` +define the default configurations for peripherals and device driver +modules. These are, for example, the GPIOs used, bus interfaces used +or available bus speeds. Because there are many possible configurations +and many different application requirements, these default configurations +are usually only a compromise between different requirements. -Therefore, it is often necessary to change some of these default configurations for individual applications. For example, while many PWM channels are needed in one application, another application does not need PWM channels, but many ADC channels. +Therefore, it is often necessary to change some of these default +configurations for individual applications. For example, while many +PWM channels are needed in one application, another application does +not need PWM channels, but many ADC channels. ## Application-Specific Board Configuration  [[TOC](#esp8266_toc)] -To override default board configurations, simply create an application-specific board configuration file `$APPDIR/board.h` in the source directory `$APPDIR` of the application and add the definitions to be overridden. To force the preprocessor to include board's original `board.h` after that, add the `include_next` preprocessor directive as the last line. +To override default board configurations, simply create an +application-specific board configuration file `$APPDIR/board.h` in +the source directory `$APPDIR` of the application and add the +definitions to be overridden. To force the preprocessor to include +board's original `board.h` after that, add the `include_next` +preprocessor directive as the last line. -For example to override the default definition of the GPIOs that are used as PWM channels, the application-specific board configuration file `$APPDIR/board.h` could look like the following: +For example to override the default definition of the GPIOs that are +used as PWM channels, the application-specific board configuration +file `$APPDIR/board.h` could look like the following: ``` #ifdef CPU_ESP8266 -#define PWM0_CHANNEL_GPIOS { GPIO12, GPIO13, GPIO14, GPIO15 } +#define PWM0_GPIOS { GPIO12, GPIO13, GPIO14, GPIO15 } #endif #include_next "board.h" ``` -It is important to ensure that the application-specific board configuration `$APPDIR/board.h` is included first. Insert the following line as the first line to the application makefile `$APPDIR/Makefile`. +It is important to ensure that the application-specific board +configuration `$APPDIR/board.h` is included first. Insert the following +line as the first line to the application makefile `$APPDIR/Makefile`. ``` INCLUDES += -I$(APPDIR) ``` -@note To make such application-specific board configurations dependent on the ESP8266 MCU or a particular ESP8266 board, you should always enclose these definitions in the following constructs +@note To make such application-specific board configurations dependent +on the ESP8266 MCU or a particular ESP8266 board, you should always +enclose these definitions in the following constructs ``` #ifdef CPU_ESP8266 ... @@ -872,9 +907,18 @@ INCLUDES += -I$(APPDIR) ## Application-Specific Driver Configuration  [[TOC](#esp8266_toc)] -Using the approach for overriding board configurations, the parameters of drivers that are typically defined in `drivers//include/_params.h` can be overridden. For that purpose just create an application-specific driver parameter file `$APPDIR/_params.h` in the source directory `$APPDIR` of the application and add the definitions to be overridden. To force the preprocessor to include driver's original `_params.h` after that, add the `include_next` preprocessor directive as the last line. +Using the approach for overriding board configurations, the parameters +of drivers that are typically defined in +`drivers//include/_params.h` can be overridden. For that +purpose just create an application-specific driver parameter file +`$APPDIR/_params.h` in the source directory `$APPDIR` of the +application and add the definitions to be overridden. To force the +preprocessor to include driver's original `_params.h` after +that, add the `include_next` preprocessor directive as the last line. -For example, to override a GPIO used for LIS3DH sensor, the application-specific driver parameter file `$APPDIR/_params.h` could look like the following: +For example, to override a GPIO used for LIS3DH sensor, the +application-specific driver parameter file `$APPDIR/_params.h` +could look like the following: ``` #ifdef CPU_ESP8266 #define LIS3DH_PARAM_INT2 (GPIO_PIN(0, 4)) @@ -883,12 +927,16 @@ For example, to override a GPIO used for LIS3DH sensor, the application-specific #include_next "lis3dh_params.h" ``` -It is important to ensure that the application-specific driver parameter file `$APPDIR/_params.h` is included first. Insert the following line as the first line to the application makefile `$APPDIR/Makefile`. +It is important to ensure that the application-specific driver parameter +file `$APPDIR/_params.h` is included first. Insert the following +line as the first line to the application makefile `$APPDIR/Makefile`. ``` INCLUDES += -I$(APPDIR) ``` -**Pleae note:** To make such application-specific board configurations dependent on the ESP8266 MCU or a particular ESP8266 board, you should always enclose these definitions in the following constructs: +**Please note:** To make such application-specific board configurations +dependent on the ESP8266 MCU or a particular ESP8266 board, you should +always enclose these definitions in the following constructs: ``` #ifdef CPU_ESP8266 ... @@ -899,53 +947,76 @@ INCLUDES += -I$(APPDIR) #endif ``` -# SDK Task Handling  [[TOC](#esp8266_toc)] +# SDK Specific Information  [[TOC](#esp8266_toc)] + +## SDK Tasks  [[TOC](#esp8266_toc)] + +ESP8266 RTOS SDK libraries create a number of high-priority threads, see the +listing below, which handle high priority interrupts from SoC and WiFi +hardware. These threads are also created, if the WiFi hardware is not used. + +``` + pid | name | state Q | pri | stack ( used) | base addr | current + - | isr_stack | - - | - | 2048 ( 832) | 0x3ffe8420 | 0x3ffe8c20 + 1 | ppT | bl rx _ | 2 | 3632 ( 1296) | 0x3fff5df0 | 0x3fff6ac0 + 2 | pmT | bl rx _ | 4 | 1072 ( 320) | 0x3fff6c70 | 0x3fff6f70 + 3 | rtT | bl rx _ | 3 | 2096 ( 1376) | 0x3fff70b0 | 0x3fff77b0 + 4 | esp_events | bl rx _ | 5 | 2096 ( 864) | 0x3fff7f20 | 0x3fff8600 +``` + +## SDK Heap Implementation  [[TOC](#esp8266_toc)] -With make command variable `USE_SDK=1`, the Espressif SDK is used. This is -necessary, for example, if you want to use the built-in WLAN module. The -SDK is also used automatically when software timers are used by activating -the `esp_sw_timer` module. +Using module `esp_idf_heap` enables the compilation of SDK heap handling +instead of memory management provided by `newlibc`. + +Normally, the remaining ESP8266 DRAM, which is not used by static variables, +is provided as heap memory. The SDK heap implementation also provides the unused +ESP8266 IRAM (Command RAM) as the additional heap memory region. + +@note The heap in IRAM allows only 32-bit-aligned word access. + +The following example shows the heap when the `esp_idf_heap` is used: + +``` +Heap region 0 @40107690: 18800 (used 8, free 18792) [bytes] +Heap region 1 @3fff1760: 59552 (used 8520, free 51032) [bytes] +``` -Internally, the SDK uses its own priority-based multitasking sytsem, -the **ETS**, to handle hardware components such as the WiFi interface, or to -implement event-driven functions such as software timers. ETS periodically -executes all ETS tasks with pending events in an infinite loop with the ROM -function `ets_run`. +In this example, heap region 0 at address `0x401xxxxx` is located in IRAM and +heap region 1 at address `0x3fffxxxx` in DRAM. While memory management +functions of `newlibc` use always heap region 1 in DRAM, functions of +binary SDK libraries like the WiFi stack can also also heap region 0 +for 32-bit aligned data. -ETS doesn't process interrupts directly in interrupt service routines. -Instead, they use the `ets_post` ROM function to send an event to one of the -ETS tasks, which then processes the interrupts asynchronously. Context -switches are not possible in interrupt service routines. +# Debugging  [[TOC](#esp8266_toc)] -To use SDK functions and keep the system alive, ETS tasks with pending events -have to be handled. For that purpose +There are two options to debug your RIOT application for ESP8266 either -- the `ets_task_func` RIOT thread with highest possible priority is used -- the ROM functions `ets_run` and `ets_post` are overwritten. +- using `QEMU` and module `esp_gdb`, see [QEMU Mode andB](#esp8266_qemu_mode_and_gdb) or +- using module `esp_gdbstub`, see [Module esp_gdbstub](#esp8266_esp_gdbstub). -The `ets_task_func` RIOT thread is waiting for a thread flag, which is set -by the `ets_post` function at the end of an ETS interrupt service routine. -The flag indicates that there are ETS tasks with pending events that need -to be executed. The `ets_task_func` RIOT thread then calls the `ets_run` -function, which performs all ETS tasks with pending events exactly once. +## QEMU Mode and GDB  [[TOC](#esp8266_toc)] -Thus, when a hardware component used by the SDK triggers an interrupt, e.g. -the WiFi interface, the interrupt sevice routine posts an event to the ETS -task by calling the `ets_post` function. The overwritten version of this -function sets the thread flag of the `ets_task_func` thread. The thread -then calls function `ets_run` to process pending events. +### Compilation for `QEMU` -@note Since the non-SDK version of RIOT is much smaller and faster than the -SDK version, you should always compile your application without the SDK -(`USE_SDK=0`, the default) if you don't need the built-in WiFi module. +When `QEMU` mode is enabled by using the `esp_qemu` module, `make flash` does +not try to download the image of your RIOT application to the target hardware. +Instead, a binary image `$ELFFILE.bin` as well as the 1 MByte flash image +`esp8266flash.bin` is created in the application build directory `$(BINDIR)`. +This flash image can be used together with `QEMU` and `GDB` to debug the +application. -# QEMU Mode and GDB  [[TOC](#esp8266_toc)] +For debugging purposes, the application should be compiled with debugging +information. This can either be done by using the `esp_gdb` module, for example: -When QEMU mode is enabled (`QEMU=1`), instead of loading the image to the target hardware, a binary image `$ELFFILE.bin` is created in the target directory. This binary image file can be used together with QEMU to debug the code in GDB. +``` +USEMODULE=esp_gdb make flash BOARD=esp8266-esp-12x -C tests/shell +``` -The binary image can be compiled with debugging information (`ENABLE_GDB=1` or module `esp_gdb`) or optimized without debugging information (`ENABLE_GDB=0`). The latter one is the default. The version with debugging information can be debugged in source code while the optimized version can only be debugged in assembler mode. +### Installation of `QEMU` -To use QEMU, you have to install QEMU for Xtensa with ESP8266 machine implementation as following. +To use `QEMU`, you have to install `QEMU` for Xtensa with ESP8266 machine +implementation first as following. ``` cd /my/source/dir @@ -958,27 +1029,152 @@ make make install ``` -Once the compilation has been finished, QEMU for Xtensa with ESP8266 machine implementation should be available in `/path/to/esp/qemu/bin` and you can start it with +### Start Debugging with `QEMU` + +Once the compilation has been finished, `QEMU` for Xtensa with ESP8266 +machine implementation should be available in `/path/to/esp/qemu/bin` and +you can start it in first terminal with ``` -$QEMU/bin/qemu-system-xtensa -M esp8266 -nographic -serial stdio -monitor none -s -S -kernel /path/to/the/target/image.elf.bin +term1> $QEMU/bin/qemu-system-xtensa -M esp8266 -nographic -serial stdio -monitor none -s -S \ + -kernel /path/to/build/dir/esp8266flash.bin ``` -where `/path/to/the/target/image.elf.bin` is the path to the binary image as generated by the `make` command as `$ELFFILE.bin`. After that you can start GDB in another terminal window using command: +where `/path/to/build/dir` is the path to the application build directory +`$(BINDIR)` where `$ELFFILE.bin` is generated by the `make` command, for example +`$(RIOTBASE)/tests/shell/bin/esp8266-esp-12x`. After that you can +start `GDB` in second terminal window using command: ``` -xtensa-lx106-elf-gdb +term2> xtensa-esp8266-elf-gdb /path/to/build/dir/image.elf +``` + +To start debugging, you have to connect to `QEMU` from `GDB` with command: ``` +(gdb) target remote :1234 +``` + +@note: `QEMU` does not support the emulation of hardware interrupts or +special hardware modules like the WiFi module. Applications that rely on +interrupts or the WiFi interface can only be debugged with restrictions +with `QEMU` and `GDB`. + +## Module `esp_gdbstub`  [[TOC](#esp8266_toc)] + +### Compilation with `esp_gdbstub` -If you have compiled your binary image with debugging information, you can load the ELF file in gdb with: +Using the `esp_gdbstub` module enables the compilation of the `gdbstub` +interface for ESP8266. This interface implements the target side of the +[GDB Remote Protocol](https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html#Remote-Protocol). +The initial `gdbstub` implementation for ESP8266 was provided by +[Espressif](https://github.com/espressif/esp-gdbstub). However, for using it +with RIOT it had to be changed a lot. + +@note Enabling the `gdbstub` interface automatically enables the compilation +with debug information (module `esp_gdb`) `gdbstub`. + +### Start Debugging with `esp_gdbstub` + +To start debugging, the application has to be compiled using +module `esp_gdbstub`, for example: ``` -(gdb) file /path/to/the/target/image.elf +USEMODULE=esp_gdbstub make flash BOARD=esp8266-esp-12x -C tests/shell ``` -To start debugging, you have to connect to QEMU with command: +Once, the application is flashed to ESP82666, debugging can be started as +following. + +1. Start in first terminal window a terminal program which connects to the +port of the ESP8266 module as console window: ``` -(gdb) target remote :1234 +term1> python -m serial.tools.miniterm <port> 115200 +``` +where `<port>` is the serial interface to which the ESP8266 module is connected, +e.g., `/dev/ttyUSB0`. + +2. Start GDB with the application in a second terminal window: +``` +term2> xtensa-esp8266-elf-gdb /path/to/the/build/dir/image.elf +``` +where `/path/to/build/dir` is the path to the application build directory +`$(BINDIR)` where `$ELFFILE.bin` is generated by the `make` command, for example +`$(RIOTBASE)/tests/shell/bin/esp8266-esp-12x`. + +3. Connect from `GDB` to the ESP8266 module with command: ``` +(gdb) target remote <port> +``` +where `<port>` is the serial interface to which the ESP8266 module is connected, +e.g., `/dev/ttyUSB0`. + +By default, `gdbstub` stops the execution automatically using function +`gdbstub_do_break` after the board initialization and before the kernel +is initialized. + +``` +(gdb) tar rem /dev/ttyUSB0 +Remote debugging using /dev/ttyUSB0 +gdbstub_do_break_breakpoint_addr () at cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.S:400 +400 break 0,0 +(gdb) bt +#0 gdbstub_do_break_breakpoint_addr () at cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.S:400 +#1 0x40100f89 in gdbstub_init () at cpu/esp8266/vendor/esp-gdbstub/gdbstub.c:985 +``` +At this time, you can set breakpoints, execute +the application stepwise or just continue the execution using the `continue` +command. Please note the limitations below. Once you have started the execution +in `GDB`, you can use `Ctrl-C` in `GDB` or the console window to break it anytime. + +If your application uses console inputs (stdio), such as the `tests/shell` +application, you can type characters in the console window that gdbstub will +forward to the application. However, the echo of these inputs occur in `GDB`. + +@note Since the terminal program and `GDB` are using the same serial port, +typed characters can be lost sporadically. + +When you reset the ESP8266 module, you will observe a message such as the +following after boot messages in the console window. +``` +$T05#b9 +``` +This is simply the first GDB Remote Protocol packet that is generated as a +result of the automatic break during the initialization when the GDB is not +yet connected to the ESP8266 module. + +### Limitations of `esp_gdbstub` + +Due to hardware limitations of the Xtensa architecture, `esp_gdbstub` +debugging has the following limitations: + +- Software breakpoints (command `br`) only work for code in IRAM with + addresses `0x4010xxxx`, see below. +- Code in IROM (flash) with addresses `0x402xxxxx` require a hardware + breakpoint (command `hbr`), see below. +- There is only one hardware breakpoint (command `hbr`). +- There is only one hardware watchpoint (command `watch`). +- Stepwise execution on source code level is only possible in IRAM with + addresses `0x4010xxxx`, see below. + +If you want to use multiple software breakpoints or execute stepwise on +source code level, you have to ensure that the function you want to debug is +located in RAM. For that purpose, add the `IRAM` attribute to that function, +for example: + +``` +#include "esp/common_macros.h" +... +voir IRAM my_func(void) +{ + ... +} +``` + +Then you should be able to set a breakpoint to this function using command `bp` +and to execute it stepwise after break. + +Another option is to use `gdbstub_do_break()` wherever you want to break the +execution. If you know where you want to break before downloading the program +to the target, you can use `gdbstub_do_break()` as much as you want. */ diff --git a/cpu/esp8266/esp-wifi/Makefile b/cpu/esp8266/esp-wifi/Makefile index 1aee4b75d3ca..1b6125f2d9f5 100644 --- a/cpu/esp8266/esp-wifi/Makefile +++ b/cpu/esp8266/esp-wifi/Makefile @@ -1,3 +1,7 @@ MODULE=esp_wifi +# we have to do it in that way to avoid that pkg/lwip is found first +CFLAGS += -I$(ESP8266_RTOS_SDK_DIR)/components/lwip/lwip/src/include +CFLAGS += -I$(ESP8266_RTOS_SDK_DIR)/components/lwip/port/esp8266/include/ + include $(RIOTBASE)/Makefile.base diff --git a/cpu/esp8266/esp-wifi/doc.txt b/cpu/esp8266/esp-wifi/doc.txt index d61731b17dfc..97031d3a76a6 100644 --- a/cpu/esp8266/esp-wifi/doc.txt +++ b/cpu/esp8266/esp-wifi/doc.txt @@ -34,7 +34,7 @@ make -C examples/gnrc_networking BOARD=... ``` @note The Wifi network interface (module `esp_wifi`) and the -\ref esp32_esp_now_network_interface "ESP-NOW network interface" (module `esp_now`) +\ref esp8266_esp_now_network_interface "ESP-NOW network interface" (module `esp_now`) can be used simultaneously, for example, to realize a border router for a mesh network which uses ESP-NOW. */ diff --git a/cpu/esp8266/esp-wifi/esp_wifi_netdev.c b/cpu/esp8266/esp-wifi/esp_wifi_netdev.c index ef616ac25225..e299e1689232 100644 --- a/cpu/esp8266/esp-wifi/esp_wifi_netdev.c +++ b/cpu/esp8266/esp-wifi/esp_wifi_netdev.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -16,226 +16,348 @@ * @author Gunar Schorcht */ -#include "log.h" -#include "tools.h" +#ifdef MODULE_ESP_WIFI +#include #include #include -#include -#include -#include "net/ethernet.h" -#include "net/ipv4/addr.h" #include "net/gnrc/netif/ethernet.h" +#include "net/gnrc/netif/raw.h" +#include "net/gnrc.h" +#include "net/ethernet.h" #include "net/netdev/eth.h" #include "od.h" #include "xtimer.h" -#include "common.h" -#include "espressif/c_types.h" -#include "espnow.h" -#include "esp/common_macros.h" +#include "esp_common.h" +#include "esp_attr.h" +#include "esp_event_loop.h" +#include "esp_now.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_wifi_internal.h" #include "irq_arch.h" -#include "sdk/sdk.h" +#include "tools.h" -#include "lwip/igmp.h" -#include "lwip/udp.h" +#include "nvs_flash/include/nvs_flash.h" #include "esp_wifi_params.h" #include "esp_wifi_netdev.h" -#define ENABLE_DEBUG (0) +#define ENABLE_DEBUG_HEXDUMP (0) +#define ENABLE_DEBUG (0) #include "debug.h" +#include "log.h" + +#define SYSTEM_EVENT_WIFI_RX_DONE (SYSTEM_EVENT_MAX + 3) +#define SYSTEM_EVENT_WIFI_TX_DONE (SYSTEM_EVENT_MAX + 4) #define ESP_WIFI_DEBUG(f, ...) \ DEBUG("[esp_wifi] %s: " f "\n", __func__, ## __VA_ARGS__) #define ESP_WIFI_LOG_INFO(f, ...) \ - LOG_INFO("[esp_wifi] " f "\n", ## __VA_ARGS__) + LOG_TAG_INFO("esp_wifi", f "\n", ## __VA_ARGS__) #define ESP_WIFI_LOG_ERROR(f, ...) \ - LOG_ERROR("[esp_wifi] " f "\n", ## __VA_ARGS__) + LOG_TAG_ERROR("esp_wifi", f "\n", ## __VA_ARGS__) -#define ESP_WIFI_STATION_MODE (STATION_MODE) -#define ESP_WIFI_AP_MODE (SOFTAP_MODE) -#define ESP_WIFI_STATION_AP_MODE (STATIONAP_MODE) -#define ESP_WIFI_MODE (STATIONAP_MODE) +#define MAC_STR "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC_STR_ARG(m) m[0], m[1], m[2], m[3], m[4], m[5] -#define ESP_WIFI_STATION_IF (STATION_IF) -#define ESP_WIFI_SOFTAP_IF (SOFTAP_IF) +#ifdef MCU_ESP8266 -#define ESP_WIFI_RECONNECT_TIME (20 * US_PER_SEC) -#define ESP_WIFI_HEAP_MARGIN (2 * ETHERNET_MAX_LEN) +#include "esp_socket.h" +#include "net/sockio.h" +#include "xtensa/xtensa_context.h" -#define MAC_STR "%02x:%02x:%02x:%02x:%02x:%02x" -#define MAC_STR_ARG(m) m[0], m[1], m[2], m[3], m[4], m[5] +#define CONFIG_TCP_OVERSIZE_MSS 1 +#define LL_ALIGN(s) (((uint32_t)s + 3) & 0xfffffffcU) -#define PBUF_IEEE80211_HLEN (36) +#include "lwip/pbuf.h" -/** Timer used to reconnect automatically after 20 seconds if not connected */ -static xtimer_t _esp_wifi_reconnect_timer; +#endif /* MCU_ESP8266 */ /** - * There is only one ESP WIFI device. We define it as static device variable - * to have accesss to the device inside ESP WIFI interrupt routines which do - * not provide an argument that could be used as pointer to the ESP WIFI + * There is only one ESP WiFi device. We define it as static device variable + * to have access to the device inside ESP WiFi interrupt routines which do + * not provide an argument that could be used as pointer to the ESP WiFi * device which triggers the interrupt. */ -static esp_wifi_netdev_t _esp_wifi_dev; - -/** forward declaration of the driver functions structure */ +esp_wifi_netdev_t _esp_wifi_dev; static const netdev_driver_t _esp_wifi_driver; -/** Stack for the netif thread */ +/* device thread stack */ static char _esp_wifi_stack[ESP_WIFI_STACKSIZE]; -/** Static station configuration used for the WiFi interface */ -static const struct station_config station_cfg = { - .bssid_set = 0, /* no check of MAC address of AP */ - .ssid = ESP_WIFI_SSID, - .password = ESP_WIFI_PASS, -}; +/** guard variable to avoid reentrance to _esp_wifi_send function */ +static bool _esp_wifi_send_is_in = false; + +/** guard variable to to decive when receive buffer can be overwritten */ +static bool _esp_wifi_rx_in_progress = false; + +extern esp_err_t esp_system_event_add_handler (system_event_cb_t handler, + void *arg); + +#ifdef MCU_ESP8266 -#ifndef MODULE_ESP_NOW /** - * Static const configuration for the SoftAP which is used to configure the - * SoftAP interface if ESP-NOW is not enabled. - * - * Since we need to use the WiFi interface in SoftAP + Station mode for - * stability reasons, although in fact only the station interface is required, - * we make the SoftAP interface invisible and unusable. This configuration - * - * - uses the same hidden SSID that the station interface uses to - * connect to the AP, - * - uses the same channel that the station interface uses to connect to the AP, - * - defines a very long beacon interval - * - doesn't allow any connection. + * The low level WiFi driver function expects a lwIP pbuf data structure as + * input. To avoid the integration of the whole lwIP package from ESP8266 RTOS + * SDK, only the pbuf allocation function is realized with a very restricted + * functionality. It uses malloc to allocate a packet buffer of type PBUF_RAM + * for layer PBUF_RAW_TX. */ -static const struct softap_config softap_cfg = { - .ssid = ESP_WIFI_SSID, - .ssid_len = ARRAY_SIZE(ESP_WIFI_SSID), - .ssid_hidden = 1, /* don't make the AP visible */ - .password = ESP_WIFI_PASS, - .authmode = AUTH_WPA2_PSK, - .max_connection = 0, /* don't allow connections */ - .beacon_interval = 60000, /* send beacon only every 60 s */ -}; -#endif +static struct pbuf *_esp_wifi_pbuf_alloc(size_t size) +{ + /* Low level WiFi driver can only use 32-bit aligned DRAM memory */ + size_t mem_size = LL_ALIGN(sizeof(struct pbuf)) + LL_ALIGN(size + PBUF_LINK_ENCAPSULATION_HLEN); + struct pbuf *pb = heap_caps_malloc(mem_size, MALLOC_CAP_8BIT); + if (pb == NULL) { + ESP_WIFI_LOG_ERROR("no space left for packet buffer allocation"); + return NULL; + } + memset(pb, 0, mem_size); + + /* initialize pbuf data structure */ + pb->next = NULL; + pb->payload = (void *)LL_ALIGN((uint8_t *)pb + sizeof(struct pbuf) + PBUF_LINK_ENCAPSULATION_HLEN); + pb->tot_len = size; + pb->len = size; + pb->type = PBUF_RAM; + pb->flags = 0; + pb->ref = 1; -extern struct netif * eagle_lwip_getif(uint8 index); + ESP_WIFI_DEBUG("pb=%p size=%d", pb, size); + + return (struct pbuf*)pb; +} -/** guard variable to avoid reentrance to _send */ -static bool _in_send = false; +/** + * Free function for pbuf allocation + */ +static int _esp_wifi_pbuf_free(struct pbuf *pb) +{ + assert(pb != NULL); -/** guard variable to avoid reentrance to _esp_wifi_recv_cb */ -static bool _in_esp_wifi_recv_cb = false; + ESP_WIFI_DEBUG("pb=%p ref=%d", pb, pb->ref); + + if (pb->ref > 1) { + pb->ref--; + } + else if (pb->ref == 1) { + pb->ref = 0; + heap_caps_free(pb); + return 1; + } + return 0; +} + +/** + * Socket used for interaction with low level WiFi driver, -1 if not opened. + * Since we have only one WiFi interface, it has not to be a member of the + * netdev data structures. We can use a static variable instead. + */ +static int _esp_wifi_socket = -1; /** - * @brief Reconnect function called back by the reconnect timer + * Function called when transmission of a packet has been finished. */ -static void IRAM _esp_wifi_reconnect_timer_cb(void* arg) +static int _esp_wifi_tx_cb(esp_aio_t* aio) { - DEBUG("%s\n", __func__); + assert(aio != NULL); - esp_wifi_netdev_t* dev = (esp_wifi_netdev_t*)arg; + ESP_WIFI_DEBUG("aio=%p buf=%p", aio, aio->pbuf); - if (dev->state == ESP_WIFI_DISCONNECTED || - dev->state == ESP_WIFI_CONNECTING) { - ESP_WIFI_LOG_INFO("trying to reconnect to ssid " ESP_WIFI_SSID); + struct pbuf* pbuf = aio->arg; + _esp_wifi_pbuf_free(pbuf); + _esp_wifi_send_is_in = false; + _esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, NETDEV_EVENT_TX_COMPLETE); - wifi_station_disconnect(); - wifi_station_connect(); - dev->state = ESP_WIFI_CONNECTING; + return 0; +} + +/** + * Function for source code compatibility with ESP-IDF for ESP32 + */ +int esp_wifi_internal_tx(wifi_interface_t wifi_if, void *buf, uint16_t len) +{ + ESP_WIFI_DEBUG("buf=%p len=%u", buf, len); + + struct pbuf *pb = _esp_wifi_pbuf_alloc(len); + if (pb == NULL) { + return ERR_MEM; + } + if (len) { + memcpy(pb->payload, buf, len); } - /* set the time for next connection check */ - xtimer_set(&_esp_wifi_reconnect_timer, ESP_WIFI_RECONNECT_TIME); + esp_aio_t aio; + aio.fd = wifi_if; + aio.pbuf = pb->payload; + aio.len = pb->len; + aio.cb = _esp_wifi_tx_cb; + aio.arg = pb; + aio.ret = 0; + + if (esp_aio_sendto(&aio, NULL, 0) != 0) { + return ERR_IF; + } + + ESP_WIFI_DEBUG("done"); + + return ERR_OK; } /** - * @brief Callback when ethernet frame is received. Has to run in IRAM. + * Function for source code compatibility with ESP-IDF for ESP32 */ -void IRAM _esp_wifi_recv_cb(struct pbuf *pb, struct netif *netif) +void esp_wifi_internal_free_rx_buffer(const char* buf) { - assert(pb != NULL); - assert(netif != NULL); + assert(buf != NULL); + assert(_esp_wifi_socket != -1); + + ESP_WIFI_DEBUG("buf=%p sock=%d", buf, _esp_wifi_socket); + + esp_free_pbuf(_esp_wifi_socket, (void *)buf); +} + +/** + * Type definition for source code compatibility with ESP-IDF for ESP32 + */ +typedef int (*wifi_rxcb_t)(struct esp_aio *aio); + +/** + * Function for source code compatibility with ESP-IDF for ESP32 + */ +esp_err_t esp_wifi_internal_reg_rxcb(wifi_interface_t ifx, wifi_rxcb_t fn) +{ + assert(ifx == ESP_IF_WIFI_STA); + + ESP_WIFI_DEBUG("%d %p", ifx, fn); + + extern int8_t wifi_get_netif(uint8_t fd); + + /* if function is NULL, it is deregistered */ + if (fn == NULL) { + /* if socket is allocated, it has to be closed */ + if (_esp_wifi_socket != -1 && esp_close(_esp_wifi_socket) < 0) { + return ESP_FAIL; + } + _esp_wifi_socket = -1; + return ESP_OK; + } + + /* if socket is already allocated we have to close it to register a function */ + if (_esp_wifi_socket != -1 && esp_close(_esp_wifi_socket) < 0) { + return ESP_FAIL; + } + + /* now, we have to allocate a new socket and register the function */ + _esp_wifi_socket = esp_socket(AF_PACKET, SOCK_RAW, ETH_P_ALL); + + if (_esp_wifi_socket < 0) { + ESP_WIFI_LOG_ERROR("create socket of (AF_PACKET, SOCK_RAW, ETH_P_ALL) error"); + return ESP_FAIL; + } + if (esp_ioctl(_esp_wifi_socket, SIOCGIFINDEX, "sta0") < 0) { + ESP_WIFI_LOG_ERROR("bind socket %d to netcard %s error", _esp_wifi_socket, "sta0"); + esp_close(_esp_wifi_socket); + return ESP_FAIL; + } + if (esp_aio_event(_esp_wifi_socket, ESP_SOCKET_RECV_EVENT, fn, &_esp_wifi_dev) < 0) { + ESP_WIFI_LOG_ERROR("socket %d register receive callback function %p error", + _esp_wifi_socket, fn); + esp_close(_esp_wifi_socket); + return ESP_FAIL; + } + return ESP_OK; +} + +#endif /* MCU_ESP8266 */ + +#ifdef MCU_ESP8266 + +/* Prolog for source code compatibility with ESP-IDF for ESP32 */ +static int _esp_wifi_rx_cb(struct esp_aio *aio) +{ + assert(aio != NULL); + + const char *eb = aio->pbuf; + const char *buffer = aio->pbuf; + uint16_t len = aio->len; + +#else /* MCU_ESP8266 */ + +esp_err_t _esp_wifi_rx_cb(void *buffer, uint16_t len, void *eb) +{ +#endif /* MCU_ESP8266 */ /* - * Function `esp_wifi_recv_cb` is executed in the context of the `ets` - * thread. ISRs which handle hardware interrupts from the WiFi interface - * simply pass events to a message queue of the `ets` thread which are then - * sequentially processed by the `ets` thread to asynchronously execute - * callback functions such as `esp_wifi_recv_cb`. - * - * It should be therefore not possible to reenter function - * `esp_wifi_recv_cb`. If it does occur inspite of that, we use a - * guard variable to avoid inconsistencies. This can not be realized - * by a mutex because `esp_wifi_recv_cb` would be reentered from same - * thread context. + * This callback function is not executed in interrupt context but in the + * context of the low level WiFi driver thread. That is, mutex_lock or + * msg_send functions could block. */ - if (_in_esp_wifi_recv_cb) { - pbuf_free(pb); - return; - } - _in_esp_wifi_recv_cb = true; + + assert(buffer != NULL); + assert(len <= ETHERNET_MAX_LEN); critical_enter(); - /* first, check packet buffer for the minimum packet size */ - if (pb->tot_len < sizeof(ethernet_hdr_t)) { - ESP_WIFI_DEBUG("frame length is less than the size of an Ethernet" - "header (%u < %u)", pb->tot_len, sizeof(ethernet_hdr_t)); - pbuf_free(pb); - _in_esp_wifi_recv_cb = false; - critical_exit(); - return; - } + ESP_WIFI_DEBUG("buf=%p len=%d eb=%p", buffer, len, eb); - /* check whether the receive buffer is already holding a frame */ - if (_esp_wifi_dev.rx_len) { - ESP_WIFI_DEBUG("buffer used, dropping incoming frame of %d bytes", - pb->tot_len); - pbuf_free(pb); - _in_esp_wifi_recv_cb = false; + /* + * The ring buffer uses a single byte for the pkt length, followed by the mac address, + * followed by the actual packet data. The MTU for ESP-NOW is 250 bytes, so len will never + * exceed the limits of a byte as the mac address length is not included. + */ + if (ringbuffer_get_free(&_esp_wifi_dev.rx_buf) < len + sizeof(uint16_t)) { + ESP_WIFI_DEBUG("buffer full, dropping incoming packet of %d bytes", len); + /* free the receive buffer */ + if (eb) { + esp_wifi_internal_free_rx_buffer(eb); + } + /* + * we must not return a failure code in this case, otherwise, + * the WiFi driver hangs up + */ critical_exit(); - return; + return ESP_OK; } - /* check whether packet buffer fits into receive buffer */ - if (pb->tot_len > ETHERNET_MAX_LEN) { - ESP_WIFI_DEBUG("frame length is greater than the maximum size of an " - "Ethernet frame (%u > %u)", pb->tot_len, ETHERNET_MAX_LEN); - pbuf_free(pb); - _in_esp_wifi_recv_cb = false; - critical_exit(); - return; - } + /* store length information as first two bytes */ + ringbuffer_add(&_esp_wifi_dev.rx_buf, (char *)&len, sizeof(uint16_t)); - /* we have to store the frame in the buffer and free lwIP pbuf immediatly */ - _esp_wifi_dev.rx_len = pb->tot_len; - pbuf_copy_partial(pb, _esp_wifi_dev.rx_buf, _esp_wifi_dev.rx_len, 0); - pbuf_free(pb); + /* copy the buffer and free WiFi driver buffer */ + ringbuffer_add(&_esp_wifi_dev.rx_buf, (char *)buffer, len); + if (eb) { + esp_wifi_internal_free_rx_buffer(eb); + } /* - * Since _esp_wifi_recv_cb is not executed in interrupt context but in - * the context of the `ets` thread, it is not necessary to pass the - * `NETDEV_EVENT_ISR` event first. Instead, the receive function can be - * called directly which result in much faster handling, a less frame lost - * rate and more robustness. There is no need for a mutex anymore to - * synchronize the access to the receive buffer between _esp_wifi_recv_cb - * and _recv function. + * Because this function is not executed in interrupt context but in thread + * context, following msg_send could block on heavy network load, if frames + * are coming in faster than the ISR events can be handled. To avoid + * blocking during msg_send, we pretend we are in an ISR by incrementing + * the IRQ nesting counter. If IRQ nesting counter is greater 0, function + * irq_is_in returns true and the non-blocking version of msg_send is used. */ - if (_esp_wifi_dev.netdev.event_callback) { - _esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, - NETDEV_EVENT_RX_COMPLETE); - } + irq_interrupt_nesting++; + + /* trigger netdev event to read the data */ + _esp_wifi_dev.event_recv++; + _esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, NETDEV_EVENT_ISR); + + /* reset IRQ nesting counter */ + irq_interrupt_nesting--; - _in_esp_wifi_recv_cb = false; critical_exit(); + return ESP_OK; } -#define BEACON_TIMEOUT (200) -#define HANDSHAKE_TIMEOUT (204) +#define REASON_BEACON_TIMEOUT (200) +#define REASON_HANDSHAKE_TIMEOUT (204) +#define INDEX_BEACON_TIMEOUT (REASON_BEACON_TIMEOUT - 24) static const char *_esp_wifi_disc_reasons [] = { "INVALID", /* 0 */ @@ -269,217 +391,178 @@ static const char *_esp_wifi_disc_reasons [] = { "HANDSHAKE_TIMEOUT" /* 204 */ }; -/** - * @brief Event handler for esp system events. +/* + * Event handler for esp system events. */ -static void _esp_wifi_handle_event_cb(System_Event_t *evt) +static esp_err_t IRAM_ATTR _esp_system_event_handler(void *ctx, system_event_t *event) { - ESP_WIFI_DEBUG("event %d", evt->event); + assert(event != NULL); + + esp_err_t result; uint8_t reason; const char* reason_str = "UNKNOWN"; - switch (evt->event) { - case EVENT_STAMODE_CONNECTED: + switch(event->event_id) { + case SYSTEM_EVENT_STA_START: + ESP_WIFI_DEBUG("WiFi started"); + result = esp_wifi_connect(); + if (result != ESP_OK) { + ESP_WIFI_LOG_ERROR("esp_wifi_connect failed with return " + "value %d", result); + } + break; + + case SYSTEM_EVENT_SCAN_DONE: + ESP_WIFI_DEBUG("WiFi scan done"); + break; + + case SYSTEM_EVENT_STA_CONNECTED: ESP_WIFI_LOG_INFO("connected to ssid %s, channel %d", - evt->event_info.connected.ssid, - evt->event_info.connected.channel); - _esp_wifi_dev.state = ESP_WIFI_CONNECTED; - _esp_wifi_dev.event = EVENT_STAMODE_CONNECTED; + event->event_info.connected.ssid, + event->event_info.connected.channel); + + /* register RX callback function */ + esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, _esp_wifi_rx_cb); + + _esp_wifi_dev.connected = true; + _esp_wifi_dev.event_conn++; _esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, NETDEV_EVENT_ISR); + break; - case EVENT_STAMODE_DISCONNECTED: - reason = evt->event_info.disconnected.reason; + case SYSTEM_EVENT_STA_DISCONNECTED: + reason = event->event_info.disconnected.reason; if (reason < REASON_BEACON_TIMEOUT) { reason_str = _esp_wifi_disc_reasons[reason]; } else if (reason <= REASON_HANDSHAKE_TIMEOUT) { - reason_str = _esp_wifi_disc_reasons[reason - REASON_BEACON_TIMEOUT]; + reason_str = _esp_wifi_disc_reasons[reason - INDEX_BEACON_TIMEOUT]; } ESP_WIFI_LOG_INFO("disconnected from ssid %s, reason %d (%s)", - evt->event_info.disconnected.ssid, - evt->event_info.disconnected.reason, reason_str); - _esp_wifi_dev.state = ESP_WIFI_DISCONNECTED; - _esp_wifi_dev.event = EVENT_STAMODE_DISCONNECTED; + event->event_info.disconnected.ssid, + event->event_info.disconnected.reason, reason_str); + + /* unregister RX callback function */ + esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, NULL); + + _esp_wifi_dev.connected = false; + _esp_wifi_dev.event_disc++; _esp_wifi_dev.netdev.event_callback(&_esp_wifi_dev.netdev, NETDEV_EVENT_ISR); - break; - case EVENT_SOFTAPMODE_STACONNECTED: - ESP_WIFI_LOG_INFO("station " MACSTR " join, aid %d", - MAC2STR(evt->event_info.sta_connected.mac), - evt->event_info.sta_connected.aid); + /* call disconnect to reset internal state */ + result = esp_wifi_disconnect(); + if (result != ESP_OK) { + ESP_WIFI_LOG_ERROR("esp_wifi_disconnect failed with " + "return value %d", result); + return result; + } + + /* try to reconnect */ + result = esp_wifi_connect(); + if (result != ESP_OK) { + ESP_WIFI_LOG_ERROR("esp_wifi_connect failed with " + "return value %d", result); + } + break; default: + ESP_WIFI_DEBUG("event %d", event->event_id); break; } + return ESP_OK; } -static int _init(netdev_t *netdev) +static int _esp_wifi_send(netdev_t *netdev, const iolist_t *iolist) { - ESP_WIFI_DEBUG("%p", netdev); - - return 0; -} - -#if ENABLE_DEBUG -/** buffer for sent packet dump */ -uint8_t _send_pkt_buf[ETHERNET_MAX_LEN]; -#endif - -/** function used to send an ethernet frame over WiFi */ -extern err_t ieee80211_output_pbuf(struct netif *netif, struct pbuf *p); - -/** function to get free heap */ -unsigned int IRAM get_free_heap_size (void); - -static int IRAM _send(netdev_t *netdev, const iolist_t *iolist) -{ - ESP_WIFI_DEBUG("%p %p", netdev, iolist); + ESP_WIFI_DEBUG("netdev=%p iolist=%p", netdev, iolist); assert(netdev != NULL); assert(iolist != NULL); - if (_in_send) { + if (_esp_wifi_send_is_in) { return 0; } - _in_send = true; + _esp_wifi_send_is_in = true; - esp_wifi_netdev_t *dev = (esp_wifi_netdev_t*)netdev; + esp_wifi_netdev_t* dev = (esp_wifi_netdev_t*)netdev; - critical_enter(); - if (dev->state != ESP_WIFI_CONNECTED) { + if (!_esp_wifi_dev.connected) { ESP_WIFI_DEBUG("WiFi is still not connected to AP, cannot send"); - _in_send = false; - critical_exit(); - return -EIO; - } - -#ifndef MODULE_ESP_NOW - if (wifi_get_opmode() != ESP_WIFI_MODE) { - ESP_WIFI_DEBUG("WiFi is not in correct mode, cannot send"); - _in_send = false; - critical_exit(); - return -EIO; - } -#endif - - const iolist_t *iol = iolist; - size_t iol_len = 0; - - /* determine the frame size */ - while (iol) { - iol_len += iol->iol_len; - iol = iol->iol_next; + _esp_wifi_send_is_in = false; + return -ENODEV; } - /* limit checks */ - if (iol_len > ETHERNET_MAX_LEN) { - ESP_WIFI_DEBUG("frame length exceeds the maximum (%u > %u)", - iol_len, ETHERNET_MAX_LEN); - _in_send = false; - critical_exit(); - return -EBADMSG; - } - - if (iol_len < sizeof(ethernet_hdr_t)) { - ESP_WIFI_DEBUG("frame length is less than the size of an Ethernet" - "header (%u < %u)", iol_len, sizeof(ethernet_hdr_t)); - _in_send = false; - critical_exit(); - return -EBADMSG; - } - - struct netif *sta_netif = (struct netif *)eagle_lwip_getif(ESP_WIFI_STATION_IF); - netif_set_default(sta_netif); - - struct pbuf *pb; - - if (get_free_heap_size() < ESP_WIFI_HEAP_MARGIN || - (pb = pbuf_alloc(PBUF_LINK, iol_len, PBUF_RAM)) == NULL || - (pb->tot_len < iol_len)) { - ESP_WIFI_LOG_ERROR("could not allocate buffer to send %d bytes ", iol_len); - /* - * The memory of EPS8266 is quite small. Therefore, it may happen on - * heavy network load that we run into out of memory and we have - * to wait until lwIP pbuf has been flushed. We slow down sending a bit. - */ - critical_exit(); - /* wait 20 ms */ - xtimer_usleep(20 * US_PER_MS); - - _in_send = false; - return -EIO; - } - - struct pbuf *pbi = pb; - uint8_t *pbi_payload = pb->payload; - size_t pbi_pos = 0; - - /* prepare lwIP packet buffer direct from iolist without any buffer */ - for (const iolist_t *iol = iolist; iol && pbi; iol = iol->iol_next) { - uint8_t *iol_base = iol->iol_base; - for (unsigned i = 0; i < iol->iol_len && pbi; i++) { - pbi_payload[pbi_pos++] = iol_base[i]; - if (pbi_pos >= pbi->len) { - pbi = pbi->next; - } + critical_enter(); + dev->tx_len = 0; + + /* load packet data into TX buffer */ + for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) { + if (dev->tx_len + iol->iol_len > ETHERNET_MAX_LEN) { + _esp_wifi_send_is_in = false; + critical_exit(); + return -EOVERFLOW; + } + if (iol->iol_len) { + memcpy (dev->tx_buf + dev->tx_len, iol->iol_base, iol->iol_len); + dev->tx_len += iol->iol_len; } } #if ENABLE_DEBUG - pbi = pb; - pbi_pos = 0; - - for (; pbi; pbi = pbi->next) { - memcpy(_send_pkt_buf + pbi_pos, pbi->payload, pbi->len); - pbi_pos += pbi->len; - } - - const ethernet_hdr_t* hdr = (const ethernet_hdr_t *)_send_pkt_buf; - - ESP_WIFI_DEBUG("send %u byte to " MAC_STR, - (unsigned)iol_len, MAC_STR_ARG(hdr->dst)); -#if MODULE_OD - od_hex_dump(_send_pkt_buf, iol_len, OD_WIDTH_DEFAULT); -#endif /* MODULE_OD */ -#endif /* ENABLE_DEBUG */ - + ESP_WIFI_DEBUG("send %d byte", dev->tx_len); +#if MODULE_OD && ENABLE_DEBUG_HEXDUMP + od_hex_dump(dev->tx_buf, dev->tx_le, OD_WIDTH_DEFAULT); +#endif /* MODULE_OD && ENABLE_DEBUG_HEXDUMP */ +#endif critical_exit(); - /* sta_netif->linkoutput = ieee80211_output_pbuf */ - err_t res = sta_netif->linkoutput(sta_netif, pb); - pbuf_free(pb); - if (res == ERR_OK) { - /* There was no ieee80211_output_pbuf error and no send timeout. */ + int ret = 0; + + /* send the the packet to the peer(s) mac address */ + if (esp_wifi_internal_tx(ESP_IF_WIFI_STA, dev->tx_buf, dev->tx_len) == ESP_OK) { +#ifdef MCU_ESP32 + /* for ESP8266 it is done in _esp_wifi_tx_cb */ + _esp_wifi_send_is_in = false; netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE); - _in_send = false; - return iol_len; +#endif } else { - /* There was either a ieee80211_output_pbuf error or send timed out. */ - _in_send = false; - return -EIO; + _esp_wifi_send_is_in = false; + ESP_WIFI_DEBUG("sending WiFi packet failed"); + ret = -EIO; } + + return ret; } -static int _recv(netdev_t *netdev, void *buf, size_t len, void *info) +static int _esp_wifi_recv(netdev_t *netdev, void *buf, size_t len, void *info) { ESP_WIFI_DEBUG("%p %p %u %p", netdev, buf, len, info); assert(netdev != NULL); esp_wifi_netdev_t* dev = (esp_wifi_netdev_t*)netdev; + uint16_t size; - uint16_t size = dev->rx_len ? dev->rx_len : 0; + critical_enter(); + + _esp_wifi_rx_in_progress = true; + + if (ringbuffer_peek(&dev->rx_buf, (char *)&size, sizeof(uint16_t)) < sizeof(uint16_t)) { + critical_exit(); + return 0; + } if (!buf) { /* get the size of the frame */ if (len > 0 && size) { /* if len > 0, drop the frame */ - dev->rx_len = 0; + ringbuffer_remove(&dev->rx_buf, sizeof(uint16_t) + size); + _esp_wifi_rx_in_progress = false; } + critical_exit(); return size; } @@ -487,84 +570,74 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info) /* buffer is smaller than the number of received bytes */ ESP_WIFI_DEBUG("not enough space in receive buffer"); /* newest API requires to drop the frame in that case */ - dev->rx_len = 0; + ringbuffer_remove(&dev->rx_buf, sizeof(uint16_t) + size); + _esp_wifi_rx_in_progress = false; + critical_exit(); return -ENOBUFS; } - /* copy the buffer and free */ - memcpy(buf, dev->rx_buf, dev->rx_len); - dev->rx_len = 0; + /* remove length bytes, copy the buffer to the ringbuffer and free it */ + ringbuffer_remove(&dev->rx_buf, sizeof(uint16_t)); + ringbuffer_get(&dev->rx_buf, buf, size); #if ENABLE_DEBUG ethernet_hdr_t *hdr = (ethernet_hdr_t *)buf; ESP_WIFI_DEBUG("received %u byte from addr " MAC_STR, size, MAC_STR_ARG(hdr->src)); -#if MODULE_OD +#if MODULE_OD && ENABLE_DEBUG_HEXDUMP od_hex_dump(buf, size, OD_WIDTH_DEFAULT); -#endif /* MODULE_OD */ +#endif /* MODULE_OD && ENABLE_DEBUG_HEXDUMP */ #endif /* ENABLE_DEBUG */ + critical_exit(); return size; } -static int _get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len) +static int _esp_wifi_get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len) { ESP_WIFI_DEBUG("%s %p %p %u", netopt2str(opt), netdev, val, max_len); assert(netdev != NULL); assert(val != NULL); - esp_wifi_netdev_t *dev = (esp_wifi_netdev_t*)netdev; + esp_wifi_netdev_t* dev = (esp_wifi_netdev_t*)netdev; switch (opt) { - case NETOPT_IS_WIRED: return -ENOTSUP; - + case NETOPT_ADDRESS: + assert(max_len >= ETHERNET_ADDR_LEN); + esp_wifi_get_mac(ESP_MAC_WIFI_STA,(uint8_t *)val); + return ETHERNET_ADDR_LEN; case NETOPT_LINK_CONNECTED: assert(max_len == 1); - if (dev->state == ESP_WIFI_CONNECTED) { - *((netopt_enable_t *)val) = NETOPT_ENABLE; - } - else { - *((netopt_enable_t *)val) = NETOPT_DISABLE; - } + *((netopt_enable_t *)val) = (dev->connected) ? NETOPT_ENABLE + : NETOPT_DISABLE; return 1; - - case NETOPT_ADDRESS: - assert(max_len >= sizeof(dev->mac)); - memcpy(val, dev->mac, sizeof(dev->mac)); - return sizeof(dev->mac); - default: return netdev_eth_get(netdev, opt, val, max_len); - } } -static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t max_len) +static int _esp_wifi_set(netdev_t *netdev, netopt_t opt, const void *val, size_t max_len) { ESP_WIFI_DEBUG("%s %p %p %u", netopt2str(opt), netdev, val, max_len); assert(netdev != NULL); assert(val != NULL); - esp_wifi_netdev_t *dev = (esp_wifi_netdev_t *) netdev; - switch (opt) { - case NETOPT_ADDRESS: - assert(max_len >= sizeof(dev->mac)); - memcpy(dev->mac, val, sizeof(dev->mac)); - return sizeof(dev->mac); - + assert(max_len == ETHERNET_ADDR_LEN); + esp_wifi_set_mac(ESP_MAC_WIFI_STA, (uint8_t *)val); + return ETHERNET_ADDR_LEN; default: return netdev_eth_set(netdev, opt, val, max_len); } } -static void _isr(netdev_t *netdev) +static void _esp_wifi_isr(netdev_t *netdev) { ESP_WIFI_DEBUG("%p", netdev); @@ -572,131 +645,186 @@ static void _isr(netdev_t *netdev) esp_wifi_netdev_t *dev = (esp_wifi_netdev_t *) netdev; - switch (dev->event) { - case EVENT_STAMODE_CONNECTED: - dev->netdev.event_callback(netdev, NETDEV_EVENT_LINK_UP); - break; - case EVENT_STAMODE_DISCONNECTED: - dev->netdev.event_callback(netdev, NETDEV_EVENT_LINK_DOWN); - break; - default: - break; + while (dev->event_recv) { + dev->event_recv--; + dev->netdev.event_callback(netdev, NETDEV_EVENT_RX_COMPLETE); + } + if (dev->event_conn) { + dev->event_conn--; + dev->netdev.event_callback(netdev, NETDEV_EVENT_LINK_UP); + } + else if (dev->event_disc) { + dev->event_disc--; + dev->netdev.event_callback(netdev, NETDEV_EVENT_LINK_DOWN); } - _esp_wifi_dev.event = EVENT_MAX; /* no event */ return; } -/** override lwIP ethernet_intput to get ethernet frames */ -extern err_t __real_ethernet_input(struct pbuf *pb, struct netif* netif); +static int _esp_wifi_init(netdev_t *netdev) +{ + ESP_WIFI_DEBUG("%p", netdev); + + return 0; +} -err_t __wrap_ethernet_input(struct pbuf *pb, struct netif* netif) +static const netdev_driver_t _esp_wifi_driver = { - ESP_WIFI_DEBUG("%p %p", pb, netif); - if (_esp_wifi_dev.state == ESP_WIFI_CONNECTED) { - _esp_wifi_recv_cb(pb, netif); - } - else { - __real_ethernet_input(pb, netif); + .send = _esp_wifi_send, + .recv = _esp_wifi_recv, + .init = _esp_wifi_init, + .isr = _esp_wifi_isr, + .get = _esp_wifi_get, + .set = _esp_wifi_set, +}; + +/* + * Static configuration for the Station interface + */ +static wifi_config_t wifi_config_sta = { + .sta = { + .ssid = ESP_WIFI_SSID, + .password = ESP_WIFI_PASS, + .channel = 0, + .scan_method = WIFI_ALL_CHANNEL_SCAN, + .sort_method = WIFI_CONNECT_AP_BY_SIGNAL, + .threshold.rssi = -127, + .threshold.authmode = WIFI_AUTH_WPA_WPA2_PSK } - return ERR_OK; -} +}; -static const netdev_driver_t _esp_wifi_driver = { - .send = _send, - .recv = _recv, - .init = _init, - .isr = _isr, - .get = _get, - .set = _set, +#ifndef MODULE_ESP_NOW +/** + * Static configuration for the SoftAP interface if ESP-NOW is not enabled. + * + * Although only the Station interface is needed, the SoftAP interface must + * also be enabled for stability reasons to prevent the Station interface + * from being shut down by power management in the event of silence. + * Otherwise, the WLAN module and the WLAN task will hang sporadically. + * + * Since the SoftAP interface is not required, we make it invisible and + * unusable. This configuration + * + * - uses the same hidden SSID that the Station interface uses to + * connect to the AP, + * - uses the same channel that the Station interface uses to connect to the AP, + * - defines a very long beacon interval + * - doesn't allow any connection. + */ +static wifi_config_t wifi_config_ap = { + .ap = { + .ssid = ESP_WIFI_SSID, + .ssid_len = ARRAY_SIZE(ESP_WIFI_SSID), + .ssid_hidden = 1, /* don't make the AP visible */ + .password = ESP_WIFI_PASS, + .authmode = WIFI_AUTH_WPA2_PSK, + .max_connection = 0, /* don't allow connections */ + .beacon_interval = 60000, /* send beacon only every 60 s */ + } }; +#endif -static void _esp_wifi_setup(void) +void esp_wifi_setup (esp_wifi_netdev_t* dev) { - esp_wifi_netdev_t* dev = &_esp_wifi_dev; - - ESP_WIFI_DEBUG("%p", dev); + ESP_WIFI_DEBUG("dev=%p", dev); - if (dev->netdev.driver) { - ESP_WIFI_DEBUG("early returning previously initialized device"); - return; - } + /* initialize buffer */ + ringbuffer_init(&dev->rx_buf, (char*)dev->rx_mem, sizeof(dev->rx_mem)); - /* initialize netdev data structure */ - dev->rx_len = 0; - dev->state = ESP_WIFI_DISCONNECTED; - dev->event = EVENT_MAX; + /* set the event handler */ + esp_system_event_add_handler(_esp_system_event_handler, NULL); - /* set the netdev driver */ - dev->netdev.driver = &_esp_wifi_driver; + /* + * Init the WiFi driver. TODO It is not only required before ESP_WIFI is + * initialized but also before other WiFi functions are used. Once other + * WiFi functions are realized it has to be moved to a more common place. + */ + esp_err_t result; #ifndef MODULE_ESP_NOW - /* set the WiFi interface mode */ - if (!wifi_set_opmode_current(ESP_WIFI_MODE)) { - ESP_WIFI_LOG_ERROR("could not set WiFi working mode"); + /* if module esp_now is used, the following part is already done */ +#if MCU_ESP32 + extern portMUX_TYPE g_intr_lock_mux; + mutex_init(&g_intr_lock_mux); +#endif + +#if CONFIG_ESP32_WIFI_NVS_ENABLED + result = nvs_flash_init(); + if (result != ESP_OK) { + ESP_WIFI_LOG_ERROR("nfs_flash_init failed with return value %d", result); return; } +#endif /* CONFIG_ESP32_WIFI_NVS_ENABLED */ - /* set the WiFi SoftAP configuration */ - if (!wifi_softap_set_config_current((struct softap_config *)&softap_cfg)) { - ESP_WIFI_LOG_ERROR("could not set WiFi configuration"); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + result = esp_wifi_init(&cfg); + if (result != ESP_OK) { + ESP_WIFI_LOG_ERROR("esp_wifi_init failed with return value %d", result); return; } + +#ifdef CONFIG_WIFI_COUNTRY + /* TODO */ #endif - /* set the WiFi station configuration */ - if (!wifi_station_set_config_current((struct station_config *)&station_cfg)) { - ESP_WIFI_LOG_ERROR("could not set WiFi configuration"); + /* activate the Station and the SoftAP interface */ + result = esp_wifi_set_mode(WIFI_MODE_APSTA); + if (result != ESP_OK) { + ESP_WIFI_LOG_ERROR("esp_wifi_set_mode failed with return value %d", result); return; } - /* get station mac address and store it in device address */ - if (!wifi_get_macaddr(ESP_WIFI_STATION_IF, dev->mac)) { - ESP_WIFI_LOG_ERROR("could not get MAC address of WiFi interface"); + /* set the SoftAP configuration */ + result = esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config_ap); + if (result != ESP_OK) { + ESP_WIFI_LOG_ERROR("esp_wifi_set_config softap failed with return value %d", result); return; } - ESP_WIFI_DEBUG("own MAC addr is " MAC_STR, MAC_STR_ARG(dev->mac)); - /* set auto reconnect policy */ - wifi_station_set_reconnect_policy(true); - wifi_station_set_auto_connect(true); +#endif /* MODULE_ESP_NOW */ - /* register callbacks */ - wifi_set_event_handler_cb(_esp_wifi_handle_event_cb); - - /* reconnect timer initialization */ - _esp_wifi_reconnect_timer.callback = &_esp_wifi_reconnect_timer_cb; - _esp_wifi_reconnect_timer.arg = dev; + /* set the Station configuration */ + result = esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config_sta); + if (result != ESP_OK) { + ESP_WIFI_LOG_ERROR("esp_wifi_set_config station failed with return value %d", result); + return; + } - /* set the the reconnect timer */ - xtimer_set(&_esp_wifi_reconnect_timer, ESP_WIFI_RECONNECT_TIME); + /* start the WiFi driver */ + result = esp_wifi_start(); + if (result != ESP_OK) { + ESP_WIFI_LOG_ERROR("esp_wifi_start failed with return value %d", result); + return; + } - /* avoid the WiFi modem going into sleep mode */ - wifi_set_sleep_type(NONE_SLEEP_T); + /* register RX callback function */ + esp_wifi_internal_reg_rxcb(ESP_IF_WIFI_STA, _esp_wifi_rx_cb); - /* connect */ - wifi_station_connect(); - _esp_wifi_dev.state = ESP_WIFI_CONNECTING; + /* set the netdev driver */ + dev->netdev.driver = &_esp_wifi_driver; - return; + /* initialize netdev data structure */ + dev->connected = false; + dev->event_recv = 0; + dev->event_conn = 0; + dev->event_disc = 0; } -void auto_init_esp_wifi(void) +void auto_init_esp_wifi (void) { - ESP_WIFI_DEBUG("auto initializing netdev\n"); - - /* setup netdev device */ - _esp_wifi_setup(); + ESP_WIFI_DEBUG("initializing ESP WiFi device"); - /* create netif */ - gnrc_netif_ethernet_create(_esp_wifi_stack, ESP_WIFI_STACKSIZE, + esp_wifi_setup(&_esp_wifi_dev); + _esp_wifi_dev.netif = gnrc_netif_ethernet_create(_esp_wifi_stack, + ESP_WIFI_STACKSIZE, #ifdef MODULE_ESP_NOW - ESP_WIFI_PRIO - 1, + ESP_WIFI_PRIO - 1, #else - ESP_WIFI_PRIO, + ESP_WIFI_PRIO, #endif - "esp-wifi", - (netdev_t *)&_esp_wifi_dev); + "esp_wifi", + (netdev_t *)&_esp_wifi_dev); } -/** @} */ +#endif /* MODULE_ESP_WIFI */ +/**@}*/ diff --git a/cpu/esp8266/esp-wifi/esp_wifi_netdev.h b/cpu/esp8266/esp-wifi/esp_wifi_netdev.h index 05d317d70cff..756bc3e2db1e 100644 --- a/cpu/esp8266/esp-wifi/esp_wifi_netdev.h +++ b/cpu/esp8266/esp-wifi/esp_wifi_netdev.h @@ -11,7 +11,7 @@ * @{ * * @file - * @brief Network device driver for the ESP8266 WiFi interface + * @brief Network device driver for the ESP32 WiFi interface * * @author Gunar Schorcht */ @@ -20,35 +20,46 @@ #define ESP_WIFI_NETDEV_H #include "net/netdev.h" +#include "ringbuffer.h" #ifdef __cplusplus extern "C" { #endif /** - * @brief State of the WiFi interface + * @brief Buffer size used for RX buffering */ -typedef enum { - ESP_WIFI_NOT_WORKING, /**< interface is not working correctly */ - ESP_WIFI_DISCONNECTED, /**< interface is not associated to the AP */ - ESP_WIFI_CONNECTING, /**< interface is trying an association to the AP */ - ESP_WIFI_CONNECTED /**< interface is not associated to the AP */ -} esp_wifi_state_t; +#ifndef ESP_WIFI_BUFSIZE +#define ESP_WIFI_BUFSIZE (ETHERNET_MAX_LEN << 1) +#endif + +/** + * @brief Reference to the netdev device driver struct + */ +extern const netdev_driver_t esp_wifi_driver; /** - * @brief Device descriptor for ESP infrastructure mode WIFI device + * @brief Device descriptor for ESP WiFi devices */ typedef struct { - netdev_t netdev; /**< netdev parent struct */ + netdev_t netdev; /**< netdev parent struct */ + + uint8_t rx_mem[ESP_WIFI_BUFSIZE]; /**< memory holding incoming packages */ + ringbuffer_t rx_buf; /**< ringbuffer for incoming packages */ + + uint16_t tx_len; /**< number of bytes in transmit buffer */ + uint8_t tx_buf[ETHERNET_MAX_LEN]; /**< transmit buffer */ + + uint8_t event_recv; /**< number of frame received events */ + uint8_t event_conn; /**< number of pending connect events */ + uint8_t event_disc; /**< number of pending disc events */ - uint8_t mac[ETHERNET_ADDR_LEN]; /**< MAC address of the device */ + bool connected; /**< indicates whether connected to AP */ - uint8_t rx_buf[ETHERNET_MAX_LEN]; /**< receive buffer */ - uint16_t rx_len; /**< number of bytes received from lwIP */ + gnrc_netif_t* netif; /**< reference to the corresponding netif */ - esp_wifi_state_t state; /**< indicates the interface state */ - uint32_t event; /**< received event */ + mutex_t dev_lock; /**< device is already in use */ } esp_wifi_netdev_t; diff --git a/cpu/esp8266/esp-wifi/esp_wifi_params.h b/cpu/esp8266/esp-wifi/esp_wifi_params.h index 90dab212bba4..9298c2d4a30d 100644 --- a/cpu/esp8266/esp-wifi/esp_wifi_params.h +++ b/cpu/esp8266/esp-wifi/esp_wifi_params.h @@ -12,7 +12,7 @@ * @{ * * @file - * @brief Parameters for the ESP8266 WiFi netdev interface + * @brief Parameters for the ESP32 WiFi netdev interface * * @author Gunar Schorcht */ @@ -20,10 +20,10 @@ #ifndef ESP_WIFI_PARAMS_H #define ESP_WIFI_PARAMS_H -#if MODULE_ESP_WIFI || DOXYGEN +#if defined(MODULE_ESP_WIFI) || defined(DOXYGEN) /** - * @name Set default configuration parameters for the ESP WIFI netdev driver + * @name Set default configuration parameters for the ESP WiFi netdev driver * @{ */ @@ -31,30 +31,32 @@ * @brief The size of the stack used for the ESP WIFI netdev driver thread. */ #ifndef ESP_WIFI_STACKSIZE -#define ESP_WIFI_STACKSIZE (1536) +#define ESP_WIFI_STACKSIZE (THREAD_STACKSIZE_DEFAULT) #endif /** * @brief The priority of the ESP WiFi netdev driver thread. Should not be changed. */ #ifndef ESP_WIFI_PRIO -#define ESP_WIFI_PRIO (GNRC_NETIF_PRIO) +#define ESP_WIFI_PRIO (GNRC_NETIF_PRIO) #endif /** * @brief SSID of the AP to be used. */ #ifndef ESP_WIFI_SSID -#define ESP_WIFI_SSID "RIOT_AP" +#define ESP_WIFI_SSID "RIOT_AP" #endif /** - * @brief Passphrase used for the AP (max. 64 chars). + * @brief Passphrase used for the AP as clear text (max. 64 chars). */ #ifndef ESP_WIFI_PASS -#define ESP_WIFI_PASS "ThisistheRIOTporttoESP" +#define ESP_WIFI_PASS "ThisistheRIOTporttoESP" #endif +/**@}*/ + #ifdef __cplusplus extern "C" { #endif diff --git a/cpu/esp8266/esp_events.c b/cpu/esp8266/esp_events.c new file mode 100644 index 000000000000..13a6bfb00a44 --- /dev/null +++ b/cpu/esp8266/esp_events.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_esp8266 + * @{ + * + * @file + * @brief ESP system event handler + * + * @author Gunar Schorcht + * + * @} + */ + +#if defined(MODULE_ESP_WIFI_ANY) || defined(MODULE_ESP_ETH) + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#include + +#include "esp_common.h" +#include "log.h" + +#include "esp_attr.h" +#include "esp_event_loop.h" +#include "irq_arch.h" + +#define MAX_HANDLER_NUM 5 + +static system_event_cb_t _handler[MAX_HANDLER_NUM] = {}; +static void* _handler_arg[MAX_HANDLER_NUM] = {}; + +esp_err_t esp_system_event_add_handler (system_event_cb_t handler, void *arg) +{ + int i; + + /* determine next free handler entry */ + for (i = 0; i < MAX_HANDLER_NUM; i++) { + if (_handler[i] == NULL) { + break; + } + } + + /* return if there is no free entry */ + if (i == MAX_HANDLER_NUM) { + return ESP_FAIL; + } + + /* set the handler and argument entry */ + _handler[i] = handler; + _handler_arg[i] = arg; + + return ESP_OK; +} + +esp_err_t esp_system_event_del_handler (system_event_cb_t handler) +{ + int i; + + /* determine the handler entry */ + for (i = 0; i < MAX_HANDLER_NUM; i++) { + if (_handler[i] == handler) { + break; + } + } + + /* return if entry was not found */ + if (i == MAX_HANDLER_NUM) { + return ESP_FAIL; + } + + /* clean handler and arg entry */ + _handler[i] = NULL; + _handler_arg[i] = NULL; + + return ESP_OK; +} + +static esp_err_t esp_system_event_handler(void *ctx, system_event_t *event) +{ + for (int i = 0; i < MAX_HANDLER_NUM; i++) { + if (_handler[i] != NULL) { + _handler[i](_handler_arg[i], event); + } + } + return ESP_OK; +} + +#endif + +void esp_event_handler_init(void) +{ + #if defined(MODULE_ESP_WIFI_ANY) || defined(MODULE_ESP_ETH) + esp_event_loop_init(esp_system_event_handler, NULL); + #endif +} diff --git a/cpu/esp8266/exceptions.c b/cpu/esp8266/exceptions.c index 9d00b41baeac..a81efb41fd32 100644 --- a/cpu/esp8266/exceptions.c +++ b/cpu/esp8266/exceptions.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -17,87 +17,144 @@ * @} */ -#define ENABLE_DEBUG 0 +#define ENABLE_DEBUG (0) #include "debug.h" +#include #include #include -#include "common.h" #include "log.h" #include "periph/pm.h" #include "ps.h" +#include "esp_common.h" #include "esp/common_macros.h" #include "esp/xtensa_ops.h" #include "sdk/ets.h" -#include "tools.h" #include "xtensa/corebits.h" #include "xtensa/xtensa_api.h" +extern void heap_stats(void); + static const char* exception_names [] = { - "IllegalInstructionCause", /* 0 */ - "SyscallCause", /* 1 */ - "InstructionFetchErrorCause", /* 2 */ - "LoadStoreErrorCause", /* 3 */ - "Level1InterruptCause", /* 4 */ - "AllocaCause", /* 5 */ - "IntegerDivideByZeroCause", /* 6 */ - "", /* 7 - reserved */ - "PrivilegedCause", /* 8 */ - "LoadStoreAlignmentCause", /* 9 */ - "", /* 10 - reserved */ - "", /* 11 - reserved */ - "InstrPIFDataErrorCause", /* 12 */ - "LoadStorePIFDataErrorCause", /* 13 */ - "InstrPIFAddrErrorCause", /* 14 */ - "LoadStorePIFAddrErrorCause", /* 15 */ - "InstTLBMissCause", /* 16 */ - "InstTLBMultiHitCause", /* 17 */ - "InstFetchPrivilegeCause", /* 18 */ - "", /* 19 - reserved */ - "InstFetchProhibitedCause", /* 20 */ - "", /* 21 - reserved */ - "", /* 22 - reserved */ - "", /* 23 - reserved */ - "LoadStoreTLBMissCause", /* 24 */ - "LoadStoreTLBMultiHitCause", /* 25 */ - "LoadStorePrivilegeCause", /* 26 */ - "", /* 27 - reserved */ - "LoadProhibitedCause", /* 28 */ - "StoreProhibitedCause", /* 29 */ - "", /* 30 - reserved */ - "", /* 31 - reserved */ - "Coprocessor0Disabled", /* 32 */ - "Coprocessor1Disabled", /* 33 */ - "Coprocessor2Disabled", /* 34 */ - "Coprocessor3Disabled", /* 35 */ - "Coprocessor4Disabled", /* 36 */ - "Coprocessor5Disabled", /* 37 */ - "Coprocessor6Disabled", /* 38 */ - "Coprocessor7Disabled", /* 39 */ + "IllegalInstructionCause", /* 0 */ + "SyscallCause", /* 1 */ + "InstructionFetchErrorCause", /* 2 */ + "LoadStoreErrorCause", /* 3 */ + "Level1InterruptCause", /* 4 */ + "AllocaCause", /* 5 */ + "IntegerDivideByZeroCause", /* 6 */ + "", /* 7 - reserved */ + "PrivilegedCause", /* 8 */ + "LoadStoreAlignmentCause", /* 9 */ + "", /* 10 - reserved */ + "", /* 11 - reserved */ + "InstrPIFDataErrorCause", /* 12 */ + "LoadStorePIFDataErrorCause", /* 13 */ + "InstrPIFAddrErrorCause", /* 14 */ + "LoadStorePIFAddrErrorCause", /* 15 */ + "InstTLBMissCause", /* 16 */ + "InstTLBMultiHitCause", /* 17 */ + "InstFetchPrivilegeCause", /* 18 */ + "", /* 19 - reserved */ + "InstFetchProhibitedCause", /* 20 */ + "", /* 21 - reserved */ + "", /* 22 - reserved */ + "", /* 23 - reserved */ + "LoadStoreTLBMissCause", /* 24 */ + "LoadStoreTLBMultiHitCause", /* 25 */ + "LoadStorePrivilegeCause", /* 26 */ + "", /* 27 - reserved */ + "LoadProhibitedCause", /* 28 */ + "StoreProhibitedCause", /* 29 */ + "", /* 30 - reserved */ + "", /* 31 - reserved */ + "Coprocessor0Disabled", /* 32 */ + "Coprocessor1Disabled", /* 33 */ + "Coprocessor2Disabled", /* 34 */ + "Coprocessor3Disabled", /* 35 */ + "Coprocessor4Disabled", /* 36 */ + "Coprocessor5Disabled", /* 37 */ + "Coprocessor6Disabled", /* 38 */ + "Coprocessor7Disabled", /* 39 */ }; void IRAM NORETURN exception_handler (XtExcFrame *frame) { uint32_t excsave1; + uint32_t epc1; + uint32_t epc2; + uint32_t epc3; RSR(excsave1, excsave1); + RSR(epc1, epc1); + RSR(epc2, epc2); + RSR(epc3, epc3); + +#ifdef MCU_ESP32 + uint32_t epc4; + RSR(epc4, epc4); +#endif - ets_printf("EXCEPTION!! exccause=%d (%s) @%08lx excvaddr=%08lx\n", + ets_printf("EXCEPTION!! exccause=%d (%s) @%08x excvaddr=%08x\n", frame->exccause, exception_names[frame->exccause], excsave1, frame->excvaddr); - #if defined(DEVELHELP) - #if defined(MODULE_PS) + +#if defined(DEVELHELP) + +#if defined(MODULE_PS) + ets_printf("processes:\n"); ps(); - #endif - print_meminfo(); - #endif - /* flushing the buffer */ - ets_printf(" \n"); - ets_printf(" \n"); - ets_printf(" \n"); + ets_printf("\n"); +#endif /* MODULE_PS */ + + heap_stats(); + + ets_printf("\nregister set\n"); + ets_printf("pc : %08x\t", frame->pc); + ets_printf("ps : %08x\t", frame->ps); + ets_printf("exccause: %08x\t", frame->exccause); + ets_printf("excvaddr: %08x\n", frame->excvaddr); + ets_printf("epc1 : %08x\t", epc1); + ets_printf("epc2 : %08x\t", epc2); + ets_printf("epc3 : %08x\t", epc3); +#ifdef MCU_ESP32 + ets_printf("epc4 : %08x\n", epc4); +#else /* MCU_ESP32 */ + ets_printf("epc3 : %08x\n", epc3); +#endif /* MCU_ESP32 */ + ets_printf("a0 : %08x\t", frame->a0); + ets_printf("a1 : %08x\t", frame->a1); + ets_printf("a2 : %08x\t", frame->a2); + ets_printf("a3 : %08x\n", frame->a3); + ets_printf("a4 : %08x\t", frame->a4); + ets_printf("a5 : %08x\t", frame->a5); + ets_printf("a6 : %08x\t", frame->a6); + ets_printf("a7 : %08x\n", frame->a7); + ets_printf("a8 : %08x\t", frame->a8); + ets_printf("a9 : %08x\t", frame->a9); + ets_printf("a10 : %08x\t", frame->a10); + ets_printf("a11 : %08x\n", frame->a11); + ets_printf("a12 : %08x\t", frame->a12); + ets_printf("a13 : %08x\t", frame->a13); + ets_printf("a14 : %08x\t", frame->a14); + ets_printf("a15 : %08x\n", frame->a15); +#if XCHAL_HAVE_LOOPS + ets_printf("lbeg : %08x\t", frame->lbeg); + ets_printf("lend : %08x\t", frame->lend); + ets_printf("lcount : %08x\n", frame->lcount); +#endif /* XCHAL_HAVE_LOOPS */ +#endif /* DEVELHELP */ + /* restart */ + /* TODO: Improvement + Normally, we should try to restart the system. However, this + will not work after some exceptions, e.g., the LoadStoreErrorCause. + One option is to break the execution and wait for the WDT reset. Maybe + there is better way. If debugger is active, 'break 0,0' stops the + execution in debugger. */ + /* __asm__ volatile ("break 0,0"); */ /* hard reset */ __asm__ volatile (" call0 0x40000080 "); @@ -118,9 +175,7 @@ void init_exceptions (void) void IRAM NORETURN panic_arch(void) { #if defined(DEVELHELP) - print_meminfo(); - ets_printf(" \n"); - ets_printf(" \n"); + heap_stats(); #endif /* hard reset */ @@ -128,3 +183,10 @@ void IRAM NORETURN panic_arch(void) UNREACHABLE(); } + +void _panic_handler(uint32_t addr) +{ + ets_printf("#! _xt_panic called from 0x%08x: powering off\n", addr); + pm_off(); + while (1) { }; +} diff --git a/cpu/esp8266/vendor/esp/Makefile b/cpu/esp8266/freertos/Makefile similarity index 63% rename from cpu/esp8266/vendor/esp/Makefile rename to cpu/esp8266/freertos/Makefile index 5db2d2121ce9..94a83b376970 100644 --- a/cpu/esp8266/vendor/esp/Makefile +++ b/cpu/esp8266/freertos/Makefile @@ -1,3 +1,3 @@ -MODULE=esp +MODULE=esp_freertos include $(RIOTBASE)/Makefile.base diff --git a/cpu/esp8266/freertos/event_groups.c b/cpu/esp8266/freertos/event_groups.c new file mode 100644 index 000000000000..34ba654ad0f9 --- /dev/null +++ b/cpu/esp8266/freertos/event_groups.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef DOXYGEN + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include + +#include "rom/ets_sys.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" + +EventGroupHandle_t xEventGroupCreate (void) +{ + printf("%s is not supported\n", __func__); + return NULL; +} + +void vEventGroupDelete (EventGroupHandle_t xEventGroup) +{ + printf("%s is not supported\n", __func__); +} + +EventBits_t xEventGroupSetBits (EventGroupHandle_t xEventGroup, + const EventBits_t uxBitsToSet) +{ + printf("%s is not supported\n", __func__); + return 0; +} + +EventBits_t xEventGroupClearBits (EventGroupHandle_t xEventGroup, + const EventBits_t uxBitsToClear ) +{ + printf("%s is not supported\n", __func__); + return 0; +} + +EventBits_t xEventGroupWaitBits (const EventGroupHandle_t xEventGroup, + const EventBits_t uxBitsToWaitFor, + const BaseType_t xClearOnExit, + const BaseType_t xWaitForAllBits, + TickType_t xTicksToWait) +{ + printf("%s is not supported\n", __func__); + return 0; +} + +#endif /* DOXYGEN */ diff --git a/cpu/esp8266/freertos/portable.c b/cpu/esp8266/freertos/portable.c new file mode 100644 index 000000000000..0bbfa4326e29 --- /dev/null +++ b/cpu/esp8266/freertos/portable.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef DOXYGEN + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include + +#include "esp_common.h" +#include "log.h" +#ifdef MCU_ESP8266 +#include "esp_attr.h" +#include "irq.h" +#include "rom/ets_sys.h" +#endif + +#include "freertos/FreeRTOS.h" + +uint32_t xPortGetTickRateHz(void) { + return MSEC_PER_SEC / portTICK_PERIOD_MS; +} + +BaseType_t xPortInIsrContext(void) +{ + /* is working on single core in that way */ + return irq_is_in(); +} + +#ifdef MCU_ESP8266 + +unsigned _xt_tick_divisor = 0; /* cached number of cycles per tick */ + +extern void vTaskEnterCritical( portMUX_TYPE *mux ); +extern void vTaskExitCritical( portMUX_TYPE *mux ); + +void vPortEnterCritical(void) +{ + vTaskEnterCritical(0); +} + +extern void vPortExitCritical(void) +{ + vTaskExitCritical(0); +} + +/* source: /path/to/esp8266-rtos-sdk/components/freertos/port/esp8266/port.c */ +void IRAM_ATTR vPortETSIntrLock(void) +{ + ETS_INTR_LOCK(); +} + +/* source: /path/to/esp8266-rtos-sdk/components/freertos/port/esp8266/port.c */ +void IRAM_ATTR vPortETSIntrUnlock(void) +{ + ETS_INTR_UNLOCK(); +} + +/* source: /path/to/esp8266-rtos-sdk/components/freertos/port/esp8266/port.c */ +void ResetCcountVal(unsigned int cnt_val) +{ + asm volatile("wsr a2, ccount"); +} + +#endif /* MCU_ESP8266 */ + +#endif /* DOXYGEN */ diff --git a/cpu/esp8266/freertos/queue.c b/cpu/esp8266/freertos/queue.c new file mode 100644 index 000000000000..6d1c07290411 --- /dev/null +++ b/cpu/esp8266/freertos/queue.c @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef DOXYGEN + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include + +#include "esp_common.h" +#include "esp_attr.h" +#include "irq_arch.h" +#include "log.h" +#include "mutex.h" +#include "rmutex.h" +#include "syscalls.h" +#include "thread.h" + +#include "rom/ets_sys.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "freertos/task.h" + +/* + * In FreeRTOS different types of semaphores, mutexes and queues are all + * mapped to a single generic queue type. With all these different types, + * single functions for send, receive, give and take are then used. To be + * able to dsitinguish between these different types in RIOT, we need typed + * objects. + */ +typedef struct { + uint8_t type; /* type of the queue, MUST be the first element */ + list_node_t sending; /* threads that are waiting to send */ + list_node_t receiving; /* threads that are waiting to receive */ + uint8_t* queue; /* the queue of waiting items */ + uint32_t item_size; /* size of each item in the queue */ + uint32_t item_num; /* num of items that can be stored in queue */ + uint32_t item_front; /* first item in queue */ + uint32_t item_tail; /* last item in queue */ + uint32_t item_level; /* num of items stored in queue */ +} _queue_t; + +QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, + const UBaseType_t uxItemSize, + const uint8_t ucQueueType ) +{ + DEBUG("%s pid=%d len=%u size=%u type=%u ", __func__, + thread_getpid(), uxQueueLength, uxItemSize, ucQueueType); + + uint32_t queue_size = uxQueueLength * uxItemSize; + _queue_t* queue = malloc(sizeof(_queue_t) + queue_size); + + if (!queue) { + return NULL; + } + + queue->type = ucQueueType; + queue->receiving.next = NULL; + queue->sending.next = NULL; + queue->queue = (queue_size) ? (uint8_t*)queue + sizeof(_queue_t) : NULL; + queue->item_num = uxQueueLength; + queue->item_size = uxItemSize; + queue->item_front = 0; + queue->item_tail = 0; + queue->item_level = 0; + + DEBUG("queue=%p\n", queue); + + return queue; +} + +#define queueSEMAPHORE_QUEUE_ITEM_LENGTH ( ( UBaseType_t ) 0 ) + +QueueHandle_t xQueueCreateCountingSemaphore (const UBaseType_t uxMaxCount, + const UBaseType_t uxInitialCount) +{ + _queue_t* queue; + + assert(uxMaxCount != 0); + assert(uxInitialCount <= uxMaxCount); + + queue = xQueueGenericCreate(uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH, + queueQUEUE_TYPE_COUNTING_SEMAPHORE); + + DEBUG("%s pid=%d queue=%p\n", __func__, thread_getpid(), queue); + + if (queue != NULL) { + queue->item_level = uxInitialCount; + queue->item_tail = (queue->item_front + queue->item_level) % queue->item_num; + } + + return queue; +} + +void vQueueDelete( QueueHandle_t xQueue ) +{ + DEBUG("%s pid=%d queue=%p\n", __func__, thread_getpid(), xQueue); + + assert(xQueue != NULL); + free(xQueue); +} + +BaseType_t IRAM_ATTR _queue_generic_send(QueueHandle_t xQueue, + const void * const pvItemToQueue, + const BaseType_t xCopyPosition, + TickType_t xTicksToWait, + BaseType_t * const pxHigherPriorityTaskWoken) +{ + DEBUG("%s pid=%d prio=%d queue=%p pos=%d wait=%u woken=%p isr=%d\n", __func__, + thread_getpid(), sched_threads[thread_getpid()]->priority, + xQueue, xCopyPosition, xTicksToWait, pxHigherPriorityTaskWoken, + irq_is_in()); + + assert(xQueue != NULL); + + _queue_t* queue = (_queue_t*)xQueue; + + while (1) { + vTaskEnterCritical(0); + + /* is there still space in the queue */ + if (queue->item_level < queue->item_num || xCopyPosition == queueOVERWRITE) { + uint32_t write_pos; + /* determine the write position in the queue and update positions */ + if (xCopyPosition == queueSEND_TO_BACK) { + write_pos = queue->item_tail; + queue->item_tail = (queue->item_tail + 1) % queue->item_num; + queue->item_level++; + } + else if (xCopyPosition == queueSEND_TO_FRONT) { + queue->item_front = (queue->item_front - 1) % queue->item_num; + queue->item_level++; + write_pos = queue->item_front; + } + else { /* queueOVERWRITE */ + write_pos = queue->item_front; + if (queue->item_level == 0) { + queue->item_level++; + } + } + + /* if the item has no 0 size, copy it to the according place in queue */ + if (queue->item_size && queue->queue && pvItemToQueue) { + memcpy(queue->queue + write_pos * queue->item_size, + pvItemToQueue, queue->item_size); + } + + /* indicates a required context switch */ + bool ctx_switch = false; + + /* unlock waiting receiving thread */ + if (queue->receiving.next != NULL) { + list_node_t *next = list_remove_head(&queue->receiving); + thread_t *proc = container_of((clist_node_t*)next, thread_t, rq_entry); + sched_set_status(proc, STATUS_PENDING); + ctx_switch = proc->priority < sched_threads[thread_getpid()]->priority; + + DEBUG("%s pid=%d queue=%p unlock waiting pid=%d switch=%d\n", + __func__, thread_getpid(), xQueue, proc->pid, ctx_switch); + } + + if (ctx_switch && pxHigherPriorityTaskWoken) { + *pxHigherPriorityTaskWoken = pdTRUE; + vTaskExitCritical(0); + } + else if (ctx_switch) { + vTaskExitCritical(0); + /* sets only the sched_context_switch_request in ISRs */ + thread_yield_higher(); + } + else { + vTaskExitCritical(0); + } + + DEBUG("%s pid=%d queue=%p return pdPASS\n", __func__, + thread_getpid(), xQueue); + + /* in all cases vTaskExitCritical has been called already */ + return pdPASS; + } + else if (xTicksToWait == 0 || irq_is_in()) { + /* if there was no space and timeout = 0, return with error */ + DEBUG("%s pid=%d queue=%p return errQUEUE_FULL\n", __func__, + thread_getpid(), xQueue); + vTaskExitCritical(0); + return errQUEUE_FULL; + } + else { + /* suspend the calling thread to wait for space in the queue */ + thread_t *me = (thread_t*)sched_active_thread; + sched_set_status(me, STATUS_SEND_BLOCKED); + /* waiting list is sorted by priority */ + thread_add_to_list(&queue->sending, me); + + DEBUG("%s pid=%d queue=%p suspended calling thread\n", __func__, + thread_getpid(), xQueue); + vTaskExitCritical(0); + thread_yield_higher(); + + /* TODO timeout handling with xTicksToWait */ + DEBUG("%s pid=%d queue=%p continue calling thread\n", __func__, + thread_getpid(), xQueue); + } + /* in all cases vTaskExitCritical has been called already */ + } + return errQUEUE_FULL; +} + +BaseType_t IRAM_ATTR _queue_generic_recv (QueueHandle_t xQueue, + void * const pvBuffer, + TickType_t xTicksToWait, + const BaseType_t xJustPeeking, + BaseType_t * const pxHigherPriorityTaskWoken) +{ + DEBUG("%s pid=%d prio=%d queue=%p wait=%u peek=%u woken=%p isr=%d\n", __func__, + thread_getpid(), sched_threads[thread_getpid()]->priority, + xQueue, xTicksToWait, xJustPeeking, pxHigherPriorityTaskWoken, + irq_is_in()); + + assert(xQueue != NULL); + + _queue_t* queue = (_queue_t*)xQueue; + + while (1) { + vTaskEnterCritical(0); + + /* if there is at least one item in the queue */ + if (queue->item_level > 0) { + /* if the item has no 0 size, copy it from queue to buffer */ + if (queue->item_size && queue->item_num && queue->queue && pvBuffer) { + memcpy(pvBuffer, + queue->queue + queue->item_front * queue->item_size, + queue->item_size); + } + + + /* when only peeking leave the element in queue */ + if (xJustPeeking == pdTRUE) { + DEBUG("%s pid=%d queue=%p return pdPASS\n", __func__, + thread_getpid(), xQueue); + vTaskExitCritical(0); + return pdPASS; + } + + /* remove element from queue */ + queue->item_front = (queue->item_front + 1) % queue->item_num; + queue->item_level--; + + /* return if there is no waiting sending thread */ + if (queue->sending.next == NULL) { + DEBUG("%s pid=%d queue=%p return pdPASS\n", __func__, + thread_getpid(), xQueue); + vTaskExitCritical(0); + return pdPASS; + } + + /* otherwise unlock the waiting sending thread */ + list_node_t *next = list_remove_head(&queue->sending); + thread_t *proc = container_of((clist_node_t*)next, thread_t, rq_entry); + sched_set_status(proc, STATUS_PENDING); + + /* test whether context switch is required */ + bool ctx_switch = proc->priority < sched_threads[thread_getpid()]->priority; + + DEBUG("%s pid=%d queue=%p unlock waiting pid=%d switch=%d\n", + __func__, thread_getpid(), xQueue, proc->pid, ctx_switch); + + if (ctx_switch && pxHigherPriorityTaskWoken) { + *pxHigherPriorityTaskWoken = pdTRUE; + vTaskExitCritical(0); + } + else if (ctx_switch) { + vTaskExitCritical(0); + /* sets only the sched_context_switch_request in ISRs */ + sched_switch(proc->priority); + } + else { + vTaskExitCritical(0); + } + + DEBUG("%s pid=%d queue=%p return pdPASS\n", __func__, + thread_getpid(), xQueue); + + /* in all cases vTaskExitCritical has been called already */ + return pdPASS; + } + else if (xTicksToWait == 0 || irq_is_in()) { + /* if there was no item in the queue and timeout is 0, return with error */ + DEBUG("%s pid=%d queue=%p return errQUEUE_EMPTY\n", __func__, + thread_getpid(), xQueue); + vTaskExitCritical(0); + return errQUEUE_EMPTY; + } + else { + /* suspend the calling thread to wait for an item in the queue */ + thread_t *me = (thread_t*)sched_active_thread; + sched_set_status(me, STATUS_RECEIVE_BLOCKED); + /* waiting list is sorted by priority */ + thread_add_to_list(&queue->receiving, me); + + DEBUG("%s pid=%d queue=%p suspended calling thread\n", __func__, + thread_getpid(), xQueue); + + vTaskExitCritical(0); + thread_yield_higher(); + + /* TODO timeout handling with xTicksToWait */ + DEBUG("%s pid=%d queue=%p continue calling thread\n", __func__, + thread_getpid(), xQueue); + } + /* in all cases vTaskExitCritical has been called already */ + } +} + +BaseType_t IRAM_ATTR xQueueGenericSend( QueueHandle_t xQueue, + const void * const pvItemToQueue, + TickType_t xTicksToWait, + const BaseType_t xCopyPosition ) +{ + DEBUG("%s pid=%d prio=%d queue=%p wait=%u pos=%d\n", __func__, + thread_getpid(), sched_threads[thread_getpid()]->priority, + xQueue, xTicksToWait, xCopyPosition); + + return _queue_generic_send(xQueue, pvItemToQueue, xCopyPosition, + xTicksToWait, NULL); +} + +BaseType_t IRAM_ATTR xQueueGenericSendFromISR( QueueHandle_t xQueue, + const void * const pvItemToQueue, + BaseType_t * const pxHigherPriorityTaskWoken, + const BaseType_t xCopyPosition ) +{ + DEBUG("%s pid=%d prio=%d queue=%p pos=%d woken=%p\n", __func__, + thread_getpid(), sched_threads[thread_getpid()]->priority, + xQueue, xCopyPosition, pxHigherPriorityTaskWoken); + + return _queue_generic_send(xQueue, pvItemToQueue, xCopyPosition, + 0, pxHigherPriorityTaskWoken); +} + +BaseType_t IRAM_ATTR xQueueGenericReceive (QueueHandle_t xQueue, + void * const pvBuffer, + TickType_t xTicksToWait, + const BaseType_t xJustPeeking) +{ + DEBUG("%s pid=%d prio=%d queue=%p wait=%u peek=%d\n", __func__, + thread_getpid(), sched_threads[thread_getpid()]->priority, + xQueue, xTicksToWait, xJustPeeking); + + return _queue_generic_recv(xQueue, pvBuffer, xTicksToWait, + xJustPeeking, NULL); +} + +BaseType_t IRAM_ATTR xQueueReceiveFromISR (QueueHandle_t xQueue, + void * const pvBuffer, + BaseType_t * const pxHigherPriorityTaskWoken) +{ + DEBUG("%s pid=%d prio=%d queue=%p woken=%p\n", __func__, + thread_getpid(), sched_threads[thread_getpid()]->priority, + xQueue, pxHigherPriorityTaskWoken); + + return _queue_generic_recv(xQueue, pvBuffer, 0, + 0, pxHigherPriorityTaskWoken); +} + +UBaseType_t uxQueueMessagesWaiting( QueueHandle_t xQueue ) +{ + assert(xQueue != NULL); + + _queue_t* queue = (_queue_t*)xQueue; + return queue->item_level; +} + +BaseType_t xQueueGiveFromISR (QueueHandle_t xQueue, + BaseType_t * const pxHigherPriorityTaskWoken) +{ + /* this function only satisfies the linker and should not be called */ + assert(0); + + DEBUG("%s\n", __func__); + return pdFALSE; +} + +#endif /* DOXYGEN */ diff --git a/cpu/esp8266/freertos/semphr.c b/cpu/esp8266/freertos/semphr.c new file mode 100644 index 000000000000..8769624b8869 --- /dev/null +++ b/cpu/esp8266/freertos/semphr.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef DOXYGEN + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include + +#include "esp_common.h" +#include "irq_arch.h" +#include "log.h" +#include "mutex.h" +#include "rmutex.h" + +#include "freertos/FreeRTOS.h" + +/* + * In FreeRTOS different types of semaphores, mutexes and queues are all + * mapped to a single generic queue type. With all these different types, + * single functions for send, receive, give and take are then used. To be + * able to dsitinguish between these different types in RIOT, we need typed + * objects. + */ +typedef struct { + uint8_t type; /* type of the mutex, MUST be the first element */ + mutex_t mutex; /* the mutex */ +} _mutex_t; + +typedef struct { + uint8_t type; /* type of the mutex, MUST be the first element */ + rmutex_t rmutex; /* the mutex */ +} _rmutex_t; + +SemaphoreHandle_t xSemaphoreCreateMutex(void) +{ + _mutex_t* _tmp = (_mutex_t*)malloc (sizeof(_mutex_t)); + _tmp->type = queueQUEUE_TYPE_MUTEX; + mutex_init(&_tmp->mutex); + + DEBUG("%s mutex=%p\n", __func__, _tmp); + return _tmp; +} + +void vSemaphoreDelete( SemaphoreHandle_t xSemaphore ) +{ + DEBUG("%s mutex=%p\n", __func__, xSemaphore); + + assert(xSemaphore != NULL); + free(xSemaphore); +} + +BaseType_t xSemaphoreGive (SemaphoreHandle_t xSemaphore) +{ + DEBUG("%s mutex=%p\n", __func__, xSemaphore); + + assert(xSemaphore != NULL); + + uint8_t type = ((_mutex_t*)xSemaphore)->type; + mutex_t* mutex= &((_mutex_t*)xSemaphore)->mutex; + + switch (type) { + case queueQUEUE_TYPE_MUTEX: + mutex_unlock(mutex); + break; + case queueQUEUE_TYPE_RECURSIVE_MUTEX: + return xSemaphoreGiveRecursive (xSemaphore); + default: + return xQueueGenericSend(xSemaphore, NULL, 0, queueSEND_TO_BACK); + } + + return pdTRUE; +} + +BaseType_t xSemaphoreTake (SemaphoreHandle_t xSemaphore, + TickType_t xTicksToWait) +{ + DEBUG("%s mutex=%p wait=%u\n", __func__, xSemaphore, xTicksToWait); + + assert(xSemaphore != NULL); + + uint8_t type = ((_mutex_t*)xSemaphore)->type; + mutex_t* mutex= &((_mutex_t*)xSemaphore)->mutex; + + switch (type) { + case queueQUEUE_TYPE_MUTEX: + { + if (xTicksToWait == 0) { + return (mutex_trylock(mutex) == 1) ? pdPASS : pdFAIL; + } + else { + mutex_lock(mutex); + /* TODO timeout handling */ + return pdTRUE; + } + break; + } + case queueQUEUE_TYPE_RECURSIVE_MUTEX: + return xSemaphoreTakeRecursive (xSemaphore, xTicksToWait); + + default: + return xQueueGenericReceive(xSemaphore, NULL, xTicksToWait, pdFALSE); + } +} + +SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void) +{ + _rmutex_t* _tmp = (_rmutex_t*)malloc (sizeof(_rmutex_t)); + _tmp->type = queueQUEUE_TYPE_RECURSIVE_MUTEX; + rmutex_init(&_tmp->rmutex); + + DEBUG("%s rmutex=%p\n", __func__, _tmp); + + return _tmp; +} + +BaseType_t xSemaphoreGiveRecursive (SemaphoreHandle_t xSemaphore) +{ + DEBUG("%s rmutex=%p\n", __func__, xSemaphore); + + assert(xSemaphore != NULL); + assert(((_rmutex_t*)xSemaphore)->type == queueQUEUE_TYPE_RECURSIVE_MUTEX); + + rmutex_unlock(&((_rmutex_t*)xSemaphore)->rmutex); + return pdTRUE; +} + +BaseType_t xSemaphoreTakeRecursive (SemaphoreHandle_t xSemaphore, + TickType_t xTicksToWait) +{ + DEBUG("%s rmutex=%p wait=%u\n", __func__, xSemaphore, xTicksToWait); + + assert(xSemaphore != NULL); + assert(((_rmutex_t*)xSemaphore)->type == queueQUEUE_TYPE_RECURSIVE_MUTEX); + + BaseType_t ret = pdTRUE; + rmutex_t* rmutex = &((_rmutex_t*)xSemaphore)->rmutex; + + if (xTicksToWait == 0) { + ret = (rmutex_trylock(rmutex) == 1) ? pdPASS : pdFAIL; + } + else { + rmutex_lock(&((_rmutex_t*)xSemaphore)->rmutex); + /* TODO timeout handling */ + } + + return ret; +} + +void vPortCPUAcquireMutex(portMUX_TYPE *mux) +{ + DEBUG("%s pid=%d prio=%d mux=%p\n", __func__, + thread_getpid(), sched_threads[thread_getpid()]->priority, mux); + critical_enter(); + mutex_lock(mux); /* lock the mutex with interrupts disabled */ + critical_exit(); +} + +void vPortCPUReleaseMutex(portMUX_TYPE *mux) +{ + DEBUG("%s pid=%d prio=%d mux=%p\n", __func__, + thread_getpid(), sched_threads[thread_getpid()]->priority, mux); + critical_enter(); + mutex_unlock(mux); /* unlock the mutex with interrupts disabled */ + critical_exit(); +} + +#endif /* DOXYGEN */ diff --git a/cpu/esp8266/freertos/task.c b/cpu/esp8266/freertos/task.c new file mode 100644 index 000000000000..36ed86a08897 --- /dev/null +++ b/cpu/esp8266/freertos/task.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef DOXYGEN + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include + +#include "esp_common.h" +#include "esp_attr.h" +#include "log.h" +#include "syscalls.h" +#include "thread.h" +#include "xtimer.h" + +#ifdef MCU_ESP32 +#include "soc/soc.h" +#endif + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#define MHZ 1000000 + +#ifdef MCU_ESP8266 +#include "rom/ets_sys.h" + +#define PRO_CPU_NUM (0) +#endif + +/** + * @brief Architecture specific data of thread control blocks + */ +typedef struct { + uint32_t saved_int_state; + uint32_t critical_nesting; +} thread_arch_ext_t; + +volatile thread_arch_ext_t threads_arch_exts[KERNEL_PID_LAST + 1] = {}; + +BaseType_t xTaskCreatePinnedToCore (TaskFunction_t pvTaskCode, + const char * const pcName, + const uint32_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pvCreatedTask, + const BaseType_t xCoreID) +{ + /* FreeRTOS priority values have to be inverted */ + uxPriority = SCHED_PRIO_LEVELS - uxPriority - 1; + + DEBUG("%s name=%s size=%d prio=%d pvCreatedTask=%p ", + __func__, pcName, usStackDepth, uxPriority, pvCreatedTask); + + char* stack = malloc(usStackDepth + sizeof(thread_t)); + + if (!stack) { + LOG_TAG_ERROR("freertos", "not enough memory to create task %s with " + "stack size of %d bytes\n", pcName, usStackDepth); + abort(); + return pdFALSE; + } + kernel_pid_t pid = thread_create(stack, + usStackDepth + sizeof(thread_t), + uxPriority, + THREAD_CREATE_WOUT_YIELD | + THREAD_CREATE_STACKTEST, + (thread_task_func_t)pvTaskCode, + pvParameters, pcName); + DEBUG("pid=%d\n", pid); + + if (pvCreatedTask) { + *pvCreatedTask = (TaskHandle_t)(0L + pid); + } + + return (pid < 0) ? pdFALSE : pdTRUE; +} + +BaseType_t xTaskCreate (TaskFunction_t pvTaskCode, + const char * const pcName, + const uint32_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pvCreatedTask) +{ + return xTaskCreatePinnedToCore (pvTaskCode, + pcName, + usStackDepth, + pvParameters, + uxPriority, + pvCreatedTask, + PRO_CPU_NUM); +} + +void vTaskDelete (TaskHandle_t xTaskToDelete) +{ + DEBUG("%s pid=%d task=%p\n", __func__, thread_getpid(), xTaskToDelete); + + assert(xTaskToDelete != NULL); + + uint32_t pid = (uint32_t)xTaskToDelete; + + /* remove old task from scheduling */ + thread_t* thread = (thread_t*)sched_threads[pid]; + sched_set_status(thread, STATUS_STOPPED); + sched_threads[pid] = NULL; + sched_num_threads--; + sched_active_thread = NULL; + + /* determine the new running task */ + sched_run(); +} + +TaskHandle_t xTaskGetCurrentTaskHandle(void) +{ + DEBUG("%s pid=%d\n", __func__, thread_getpid()); + + uint32_t pid = thread_getpid(); + return (TaskHandle_t)pid; +} + +void vTaskDelay( const TickType_t xTicksToDelay ) +{ + DEBUG("%s xTicksToDelay=%d\n", __func__, xTicksToDelay); +#if defined(MCU_ESP8266) && defined(MODULE_ESP_WIFI_ANY) + uint64_t us = xTicksToDelay * MHZ / xPortGetTickRateHz(); + xtimer_usleep(us); +#endif +} + +TickType_t xTaskGetTickCount (void) +{ + return system_get_time() / USEC_PER_MSEC / portTICK_PERIOD_MS; +} + +void vTaskEnterCritical( portMUX_TYPE *mux ) +{ +#ifdef MCU_ESP8266 + /* we have to return on NMI */ + if (NMIIrqIsOn) { + return; + } +#endif /* MCU_ESP8266 */ + + /* disable interrupts */ + uint32_t state = irq_disable(); + + /* determine calling thread pid (can't fail) */ + kernel_pid_t my_pid = thread_getpid(); + + DEBUG("%s pid=%d prio=%d mux=%p\n", __func__, + my_pid, sched_threads[my_pid]->priority, mux); + + /* acquire the mutex with interrupts disabled */ + if (mux) { + mutex_lock(mux); /* TODO should be only a spin lock */ + } + + /* increment nesting counter and save old interrupt level */ + threads_arch_exts[my_pid].critical_nesting++; + if (threads_arch_exts[my_pid].critical_nesting == 1) { + threads_arch_exts[my_pid].saved_int_state = state; + } +} + +void vTaskExitCritical( portMUX_TYPE *mux ) +{ +#ifdef MCU_ESP8266 + /* we have to return on NMI */ + if (NMIIrqIsOn) { + return; + } +#endif /* MCU_ESP8266 */ + + /* determine calling thread pid (can't fail) */ + kernel_pid_t my_pid = thread_getpid(); + + DEBUG("%s pid=%d prio=%d mux=%p\n", __func__, + my_pid, sched_threads[my_pid]->priority, mux); + + /* release the mutex with interrupts disabled */ + if (mux) { + mutex_unlock(mux); /* TODO should be only a spin lock */ + } + + /* decrement nesting counter and restore old interrupt level */ + if (threads_arch_exts[my_pid].critical_nesting) { + threads_arch_exts[my_pid].critical_nesting--; + if (threads_arch_exts[my_pid].critical_nesting == 0) { + irq_restore(threads_arch_exts[my_pid].saved_int_state); + } + } +} + +void vTaskStepTick(const TickType_t xTicksToJump) +{ + DEBUG("%s xTicksToJump=%d\n", __func__, xTicksToJump); + /* + * TODO: + * At the moment, only the calling task is set to sleep state. Usually, the + * complete system should sleep but not only the task. + */ + vTaskDelay(xTicksToJump); +} + +TickType_t prvGetExpectedIdleTime(void) +{ + DEBUG("%s\n", __func__); + /* + * TODO: + * Since we are not able to estimate the time the system will be idle, + * we simply return 0. + */ + return 0; +} + +#endif /* DOXYGEN */ diff --git a/cpu/esp8266/freertos/timers.c b/cpu/esp8266/freertos/timers.c new file mode 100644 index 000000000000..b134de96c1db --- /dev/null +++ b/cpu/esp8266/freertos/timers.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef DOXYGEN + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include + +#include "esp_common.h" +#include "esp_attr.h" +#include "log.h" +#include "xtimer.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/timers.h" + +typedef struct { + xtimer_t xtimer; /* xtimer object */ + const char* name; /* FreeRTOS timer name */ + uint32_t period; /* in us */ + bool autoreload; /* FreeRTOS timer reload indicator */ + const void* timerid; /* FreeRTOS timer id */ + TimerCallbackFunction_t cb; /* FreeRTOS callback function */ +} freertos_xtimer_t; + +static void IRAM_ATTR _xtimer_callback (void *arg) +{ + assert(arg != NULL); + + freertos_xtimer_t* timer = (freertos_xtimer_t*)arg; + + if (timer->autoreload) { + xtimer_set(&timer->xtimer, timer->period); + } + + if (timer->cb) { + timer->cb(arg); + } +} + +TimerHandle_t xTimerCreate (const char * const pcTimerName, + const TickType_t xTimerPeriod, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction) +{ + freertos_xtimer_t* timer = malloc(sizeof(freertos_xtimer_t)); + if (timer == NULL) { + return NULL; + } + + /* FreeRTOS timer parameter */ + timer->name = pcTimerName; + timer->period = xTimerPeriod * portTICK_PERIOD_MS * USEC_PER_MSEC; + timer->autoreload = uxAutoReload; + timer->timerid = pvTimerID; + timer->cb = pxCallbackFunction; + + /* xtimer parameter */ + timer->xtimer.callback = _xtimer_callback; + timer->xtimer.arg = timer; + + DEBUG("%s %p %s %d %u\n", __func__, timer, pcTimerName, xTimerPeriod, uxAutoReload); + return timer; +} + +BaseType_t xTimerDelete(TimerHandle_t xTimer, TickType_t xBlockTime) +{ + DEBUG("%s %p %d\n", __func__, xTimer, xBlockTime); + assert(xTimer != NULL); + + freertos_xtimer_t* timer = (freertos_xtimer_t*)xTimer; + xtimer_remove(&timer->xtimer); + free(timer); + + return pdTRUE; +} + +BaseType_t xTimerStart (TimerHandle_t xTimer, TickType_t xBlockTime) +{ + DEBUG("%s %p %d\n", __func__, xTimer, xBlockTime); + assert(xTimer != NULL); + + freertos_xtimer_t* timer = (freertos_xtimer_t*)xTimer; + xtimer_set(&timer->xtimer, timer->period); + + return pdTRUE; +} + +BaseType_t xTimerStop (TimerHandle_t xTimer, TickType_t xBlockTime) +{ + DEBUG("%s %p %d\n", __func__, xTimer, xBlockTime); + assert(xTimer != NULL); + + freertos_xtimer_t* timer = (freertos_xtimer_t*)xTimer; + xtimer_remove(&timer->xtimer); + + return pdTRUE; +} + +BaseType_t xTimerReset (TimerHandle_t xTimer, TickType_t xBlockTime) +{ + DEBUG("%s %p %d\n", __func__, xTimer, xBlockTime); + assert(xTimer != NULL); + + freertos_xtimer_t* timer = (freertos_xtimer_t*)xTimer; + xtimer_set(&timer->xtimer, xBlockTime * portTICK_PERIOD_MS * USEC_PER_MSEC); + + return pdTRUE; +} + +void *pvTimerGetTimerID(const TimerHandle_t xTimer) +{ + assert(xTimer != NULL); + + freertos_xtimer_t* timer = (freertos_xtimer_t*)xTimer; + return (void*)timer->timerid; +} + +#endif /* DOXYGEN */ diff --git a/cpu/esp8266/include/common.h b/cpu/esp8266/include/common.h deleted file mode 100644 index d006cba14845..000000000000 --- a/cpu/esp8266/include/common.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2018 Gunar Schorcht - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup cpu_esp8266 - * @{ - * - * @file - * @brief Common helper macros - * - * @author Gunar Schorcht - * - */ - -#ifndef COMMON_H -#define COMMON_H - -#ifndef DOXYGEN - -#ifdef __cplusplus -extern "C" { -#endif - -/** string representation of x */ -#ifndef XTSTR -#define _XTSTR(x) # x -#define XTSTR(x) _XTSTR(x) -#endif -#endif - -#if !defined(ICACHE_FLASH) || defined (DOXYGEN) - -#ifndef ICACHE_RAM_ATTR -/** Places the code with this attribute in the IRAM. */ -#define ICACHE_RAM_ATTR __attribute__((section(".iram.text"))) -#endif -#else -#ifndef ICACHE_RAM_ATTR -#define ICACHE_RAM_ATTR -#endif -#endif - -/** Print out a message that function is not yet implementd */ -#define NOT_YET_IMPLEMENTED() LOG_INFO("%s not yet implemented\n", __func__) -/** Print out a message that function is not supported */ -#define NOT_SUPPORTED() LOG_INFO("%s not supported\n", __func__) - - -#if defined(ENABLE_DEBUG) || defined(DOXYGEN) -/** - * @brief Parameter check with return a value. - * - * If ENABLE_DEBUG is true, the macro checks a condition and returns with a value - * if the condition is not fulfilled. - * @param cond the condition - * @param err the return value in the case the condition is not fulfilled. - */ -#define CHECK_PARAM_RET(cond,err) if (!(cond)) \ - { \ - DEBUG("%s\n", "parameter condition (" #cond ") not fulfilled"); \ - return err; \ - } - -/** - * @brief Parameter check without return value. - * - * If ENABLE_DEBUG is true, the macro checks a condition and returns without a - * value if the condition is not fulfilled. - * @param cond the condition - */ -#define CHECK_PARAM(cond) if (!(cond)) \ - { \ - DEBUG("%s\n", "parameter condition (" #cond ") not fulfilled"); \ - return; \ - } -#else -#define CHECK_PARAM_RET(cond,err) if (!(cond)) return err; -#define CHECK_PARAM(cond) if (!(cond)) return; -#endif - - -#define LOG_TAG_ERROR(tag, fmt, ...) LOG_ERROR("[%s] " fmt, tag, ##__VA_ARGS__) -#define LOG_TAG_WARNING(tag, fmt, ...) LOG_WARNING("[%s] " fmt, tag, ##__VA_ARGS__) -#define LOG_TAG_INFO(tag, fmt, ...) LOG_INFO("[%s] " fmt, tag, ##__VA_ARGS__) -#define LOG_TAG_DEBUG(tag, fmt, ...) LOG_DEBUG("[%s] " fmt, tag, ##__VA_ARGS__) - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif /* COMMON_H */ diff --git a/cpu/esp8266/include/cpu.h b/cpu/esp8266/include/cpu.h index e0e7747f7da1..021d0a624732 100644 --- a/cpu/esp8266/include/cpu.h +++ b/cpu/esp8266/include/cpu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level diff --git a/cpu/esp8266/include/cpu_conf.h b/cpu/esp8266/include/cpu_conf.h index 11160e13d10f..0f20079216aa 100644 --- a/cpu/esp8266/include/cpu_conf.h +++ b/cpu/esp8266/include/cpu_conf.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -29,7 +29,16 @@ extern "C" { #endif /** - * @name Stack size configuration + * @brief Defines the CPU frequency in MHz + * + * Possible values are 80 and 160 MHz. + */ +#ifndef ESP8266_CPU_FREQUENCY +#define ESP8266_CPU_FREQUENCY (80) +#endif + +/** + * @name Stack size configurations * @{ */ #ifndef THREAD_EXTRA_STACKSIZE_PRINTF @@ -49,16 +58,12 @@ extern "C" { #define GNRC_IPV6_STACK_SIZE (1536) #endif #ifndef GNRC_PKTDUMP_STACKSIZE -#define GNRC_PKTDUMP_STACKSIZE (THREAD_STACKSIZE_DEFAULT) +#define GNRC_PKTDUMP_STACKSIZE (THREAD_STACKSIZE_DEFAULT << 1) #endif #ifndef ESP_NOW_STACKSIZE #define ESP_NOW_STACKSIZE (2560) #endif - -#ifndef ETS_THREAD_STACKSIZE -#define ETS_THREAD_STACKSIZE (1536) -#endif /** @} */ /** @@ -66,16 +71,6 @@ extern "C" { */ #define PRINTF_BUFSIZ 256 -/* Following include is neccessary to overwrite newlib's PRI*8 and PRI*32. */ -/* PLEASE NOTE: ets_vprintf does not understand %i %li, or %hi */ -#ifndef DOXYGEN -#include -#undef __INT8 -#define __INT8 -#undef __INT32 -#define __INT32 -#endif - #ifdef __cplusplus } #endif diff --git a/cpu/esp8266/include/esp_common.h b/cpu/esp8266/include/esp_common.h new file mode 100644 index 000000000000..f81d80eb6a9e --- /dev/null +++ b/cpu/esp8266/include/esp_common.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_esp8266 + * @{ + * + * @file + * @brief Common helper macros + * + * @author Gunar Schorcht + * + */ + +#ifndef ESP_COMMON_H +#define ESP_COMMON_H + +#ifndef DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif + +#include "log.h" +#include "esp_common_log.h" + +#define asm __asm__ + +/** string representation of x */ +#ifndef XTSTR +#define _XTSTR(x) # x +#define XTSTR(x) _XTSTR(x) +#endif /* XSTR */ + +#if !defined(ICACHE_FLASH) +#ifndef ICACHE_RAM_ATTR +/** Places the code with this attribute in the IRAM. */ +#define ICACHE_RAM_ATTR __attribute__((section(".iram0.text"))) +#endif +#else /* ICACHE_FLASH */ +#ifndef ICACHE_RAM_ATTR +#define ICACHE_RAM_ATTR +#endif +#endif /* ICACHE_FLASH */ + +/** Print out a message that function is not yet implementd */ +#define NOT_YET_IMPLEMENTED() LOG_INFO("%s not yet implemented\n", __func__) +/** Print out a message that function is not supported */ +#define NOT_SUPPORTED() LOG_INFO("%s not supported\n", __func__) + +#if ENABLE_DEBUG +/** + * @brief Parameter check with return a value. + * + * If ENABLE_DEBUG is true, the macro checks a condition and returns with a value + * if the condition is not fulfilled. + * @param cond the condition + * @param err the return value in the case the condition is not fulfilled. + */ +#define CHECK_PARAM_RET(cond,err) if (!(cond)) \ + { \ + DEBUG("%s parameter condition (" #cond ") " \ + "not fulfilled\n", __func__); \ + return err; \ + } + +/** + * @brief Parameter check without return value. + * + * If ENABLE_DEBUG is true, the macro checks a condition and returns without a + * value if the condition is not fulfilled. + * @param cond the condition + */ +#define CHECK_PARAM(cond) if (!(cond)) \ + { \ + DEBUG("%s parameter condition (" #cond ") " \ + "not fulfilled\n", __func__); \ + return; \ + } + +#else /* ENABLE_DEBUG */ + +#define CHECK_PARAM_RET(cond,err) if (!(cond)) return err; +#define CHECK_PARAM(cond) if (!(cond)) return; + +#endif /* ENABLE_DEBUG */ + +/** gives the minimum of a and b */ +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/** gives the maximum of a and b */ +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +/** + * @brief function name mappings for source code compatibility with ESP8266 port + * @{ + */ +#ifdef MCU_ESP32 +#define system_get_cpu_freq ets_get_cpu_frequency +#define system_update_cpu_freq ets_update_cpu_frequency +#endif /* MCU_ESP32 */ +/** @} */ + +/** @} */ + +/** microseconds per millisecond */ +#ifndef USEC_PER_MSEC +#define USEC_PER_MSEC 1000UL +#endif + +#ifndef MSEC_PER_SEC +#define MSEC_PER_SEC 1000UL +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ + +#endif /* ESP_COMMON_H */ diff --git a/cpu/esp8266/include/esp_common_log.h b/cpu/esp8266/include/esp_common_log.h new file mode 100644 index 000000000000..a61e5349de50 --- /dev/null +++ b/cpu/esp8266/include/esp_common_log.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_esp8266 + * @{ + * + * @file + * @brief Common log macros + * + * @author Gunar Schorcht + * + */ + +#ifndef ESP_COMMON_LOG_H +#define ESP_COMMON_LOG_H + +#ifndef DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "log.h" + +extern uint32_t system_get_time_ms (void); +extern int ets_printf(const char *fmt, ...); + +#if MODULE_ESP_LOG_COLORED + +#define LOG_RESET_COLOR "\033[0m" +#define LOG_COLOR_E "\033[1;31m" +#define LOG_COLOR_W "\033[1;33m" +#define LOG_COLOR_I "\033[1m" +#define LOG_COLOR_D "\033[0;32m" +#define LOG_COLOR_V + +#else /* MODULE_ESP_LOG_COLORED */ + +#define LOG_RESET_COLOR +#define LOG_COLOR_E +#define LOG_COLOR_W +#define LOG_COLOR_I +#define LOG_COLOR_D +#define LOG_COLOR_V + +#endif /* MODULE_ESP_LOG_COLORED */ + +#if MODULE_ESP_LOG_TAGGED + +#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%d) [%s] " format LOG_RESET_COLOR + +#define LOG_TAG(level, letter, tag, format, ...) \ + do { \ + if ((unsigned)level <= (unsigned)LOG_LEVEL) { \ + printf(LOG_FORMAT(letter, format), system_get_time_ms(), tag, ##__VA_ARGS__); \ + fflush(stdout); \ + } \ + } while(0) + +#define LOG_TAG_EARLY(level, letter, tag, format, ...) \ + do { \ + if (LOG_LEVEL >= level) { \ + ets_printf(LOG_FORMAT(letter, format), system_get_time_ms(), tag, ##__VA_ARGS__); \ + } \ + } while(0) + +#else /* MODULE_ESP_LOG_TAGGED */ + +#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter format LOG_RESET_COLOR + +#define LOG_TAG(level, letter, tag, format, ...) \ + do { \ + (void)tag; \ + if ((unsigned)level <= (unsigned)LOG_LEVEL) { \ + printf(LOG_FORMAT(letter, format), ##__VA_ARGS__); \ + fflush(stdout); \ + } \ + } while (0U) + +#define LOG_TAG_EARLY(level, letter, tag, format, ...) \ + do { \ + (void)tag; \ + if ((unsigned)level <= (unsigned)LOG_LEVEL) { \ + ets_printf(LOG_FORMAT(letter, format), ##__VA_ARGS__); \ + } \ + } while (0U) + +#endif /* MODULE_ESP_LOG_TAGGED */ + +/** + * Override LOG_* definitions with a tagged version. By default the function + * name is used as tag. + */ +#ifndef MODULE_LOG_PRINTFNOFORMAT +#undef LOG_ERROR +#undef LOG_INFO +#undef LOG_WARNING +#undef LOG_DEBUG +#define LOG_ERROR(format, ...) LOG_TAG(LOG_ERROR , E, __func__, format, ##__VA_ARGS__) +#define LOG_WARNING(format, ...) LOG_TAG(LOG_WARNING, W, __func__, format, ##__VA_ARGS__) +#define LOG_INFO(format, ...) LOG_TAG(LOG_INFO , I, __func__, format, ##__VA_ARGS__) +#define LOG_DEBUG(format, ...) LOG_TAG(LOG_DEBUG , D, __func__, format, ##__VA_ARGS__) +#endif + +/** Tagged LOG_* definitions */ +#define LOG_TAG_ERROR(tag, format, ...) LOG_TAG(LOG_ERROR , E, tag, format, ##__VA_ARGS__) +#define LOG_TAG_WARNING(tag, format, ...) LOG_TAG(LOG_WARNING, W, tag, format, ##__VA_ARGS__) +#define LOG_TAG_INFO(tag, format, ...) LOG_TAG(LOG_INFO , I, tag, format, ##__VA_ARGS__) +#define LOG_TAG_DEBUG(tag, format, ...) LOG_TAG(LOG_DEBUG , D, tag, format, ##__VA_ARGS__) + +/** definitions for source code compatibility with ESP-IDF */ +#define ESP_EARLY_LOGE(tag, format, ...) LOG_TAG_EARLY(LOG_ERROR , E, tag, format "\n", ##__VA_ARGS__) +#define ESP_EARLY_LOGW(tag, format, ...) LOG_TAG_EARLY(LOG_WARNING, W, tag, format "\n", ##__VA_ARGS__) +#define ESP_EARLY_LOGI(tag, format, ...) LOG_TAG_EARLY(LOG_INFO , I, tag, format "\n", ##__VA_ARGS__) +#define ESP_LOGE(tag, format, ...) LOG_TAG(LOG_ERROR , E, tag, format "\n", ##__VA_ARGS__) +#define ESP_LOGW(tag, format, ...) LOG_TAG(LOG_WARNING, W, tag, format "\n", ##__VA_ARGS__) +#define ESP_LOGI(tag, format, ...) LOG_TAG(LOG_INFO , I, tag, format "\n", ##__VA_ARGS__) + +#if ENABLE_DEBUG + +#define ESP_EARLY_LOGD(tag, format, ...) LOG_TAG_EARLY(LOG_DEBUG, D, tag, format "\n", ##__VA_ARGS__) +#define ESP_EARLY_LOGV(tag, format, ...) LOG_TAG_EARLY(LOG_ALL , V, tag, format "\n", ##__VA_ARGS__) +#define ESP_LOGD(tag, format, ...) LOG_TAG(LOG_DEBUG, D, tag, format "\n", ##__VA_ARGS__) +#define ESP_LOGV(tag, format, ...) LOG_TAG(LOG_ALL , V, tag, format "\n", ##__VA_ARGS__) + +#else /* ENABLE_DEBUG */ + +#define ESP_EARLY_LOGD( tag, format, ... ) (void)tag +#define ESP_EARLY_LOGV( tag, format, ... ) (void)tag +#define ESP_LOGD( tag, format, ... ) (void)tag +#define ESP_LOGV( tag, format, ... ) (void)tag + +#endif /* ENABLE_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ + +#endif /* ESP_COMMON_LOG_H */ diff --git a/cpu/esp8266/include/exceptions.h b/cpu/esp8266/include/exceptions.h index e159bf1050e4..611647d076a1 100644 --- a/cpu/esp8266/include/exceptions.h +++ b/cpu/esp8266/include/exceptions.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -24,7 +24,7 @@ extern "C" { #endif -/** Initalize exception handler */ +/** Initialize exception handler */ extern void init_exceptions(void); #ifdef __cplusplus diff --git a/cpu/esp8266/include/freertos/FreeRTOS.h b/cpu/esp8266/include/freertos/FreeRTOS.h new file mode 100644 index 000000000000..e333cfd72249 --- /dev/null +++ b/cpu/esp8266/include/freertos/FreeRTOS.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef FREERTOS_FREERTOS_H +#define FREERTOS_FREERTOS_H + +#ifndef DOXYGEN + +#include "freertos/portmacro.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define configMAX_PRIORITIES SCHED_PRIO_LEVELS + +#ifndef configASSERT +#define configASSERT assert +#endif + +#define portTICK_PERIOD_MS 10 +#define portTickType TickType_t + +#define portTICK_RATE_MS portTICK_PERIOD_MS + +#define BaseType_t portBASE_TYPE +#define UBaseType_t unsigned portBASE_TYPE + +typedef uint32_t TickType_t; + +uint32_t xPortGetTickRateHz(void); +BaseType_t xPortInIsrContext(void); + +/* + * PLEASE NOTE: Following definitions were copied directly from the FreeRTOS + * distribution and are under the following copyright: + * + * FreeRTOS V8.2.0 - Copyright (C) 2015 Real Time Engineers Ltd. + * All rights reserved + * + * FreeRTOS is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License (version 2) as published by the + * Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + * + * Full license text is available on the following + * link: http://www.freertos.org/a00114.html + */ + +#define pdFALSE ( ( BaseType_t ) 0 ) +#define pdTRUE ( ( BaseType_t ) 1 ) +#define pdPASS ( pdTRUE ) +#define pdFAIL ( pdFALSE ) + +#ifdef __cplusplus +} +#endif + +#include "freertos/semphr.h" +#include "freertos/queue.h" + +#endif /* DOXYGEN */ +#endif /* FREERTOS_FREERTOS_H */ diff --git a/cpu/esp8266/include/freertos/event_groups.h b/cpu/esp8266/include/freertos/event_groups.h new file mode 100644 index 000000000000..1c70882f6c23 --- /dev/null +++ b/cpu/esp8266/include/freertos/event_groups.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef FREERTOS_EVENT_GROUPS_H +#define FREERTOS_EVENT_GROUPS_H + +#ifndef DOXYGEN + +#include "freertos/FreeRTOS.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void * EventGroupHandle_t; +typedef TickType_t EventBits_t; + +EventGroupHandle_t xEventGroupCreate (void); + +void vEventGroupDelete (EventGroupHandle_t xEventGroup); + +EventBits_t xEventGroupSetBits (EventGroupHandle_t xEventGroup, + const EventBits_t uxBitsToSet); + +EventBits_t xEventGroupClearBits (EventGroupHandle_t xEventGroup, + const EventBits_t uxBitsToClear ); + +EventBits_t xEventGroupWaitBits (const EventGroupHandle_t xEventGroup, + const EventBits_t uxBitsToWaitFor, + const BaseType_t xClearOnExit, + const BaseType_t xWaitForAllBits, + TickType_t xTicksToWait); + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* FREERTOS_EVENT_GROUPS_H */ diff --git a/cpu/esp8266/include/freertos/portmacro.h b/cpu/esp8266/include/freertos/portmacro.h new file mode 100644 index 000000000000..b0df76c65a60 --- /dev/null +++ b/cpu/esp8266/include/freertos/portmacro.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef FREERTOS_PORTMACRO_H +#define FREERTOS_PORTMACRO_H + +#ifndef DOXYGEN + +#include "stdint.h" + +#include "mutex.h" +#include "irq.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define portBASE_TYPE int +#define portUBASE_TYPE unsigned portBASE_TYPE + +#define portMAX_DELAY 0xFFFFFFFF + +#define portMUX_TYPE mutex_t +#define portMUX_INITIALIZER_UNLOCKED MUTEX_INIT + +#define portYIELD_FROM_ISR thread_yield_higher + +#ifdef MCU_ESP32 + +#define portNUM_PROCESSORS 2 +#define xPortGetCoreID() PRO_CPU_NUM + +#define portENTER_CRITICAL(pm) mutex_lock(pm) +#define portEXIT_CRITICAL(pm) mutex_unlock(pm) +#define portENTER_CRITICAL_NESTED irq_disable +#define portEXIT_CRITICAL_NESTED irq_restore + +#define portENTER_CRITICAL_ISR vTaskEnterCritical +#define portEXIT_CRITICAL_ISR vTaskExitCritical + +#else /* MCU_ESP32 */ + +#define portNUM_PROCESSORS 1 +#define xPortGetCoreID() PRO_CPU_NUM + +#define portENTER_CRITICAL vTaskEnterCritical +#define portEXIT_CRITICAL vTaskExitCritical + +#endif /* MCU_ESP32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* FREERTOS_PORTMACRO_H */ diff --git a/cpu/esp8266/include/freertos/queue.h b/cpu/esp8266/include/freertos/queue.h new file mode 100644 index 000000000000..f42b0b86af13 --- /dev/null +++ b/cpu/esp8266/include/freertos/queue.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef FREERTOS_QUEUE_H +#define FREERTOS_QUEUE_H + +#ifndef DOXYGEN + +#include "freertos/FreeRTOS.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define xQueueHandle QueueHandle_t + +typedef void* QueueHandle_t; + +QueueHandle_t xQueueGenericCreate (const UBaseType_t uxQueueLength, + const UBaseType_t uxItemSize, + const uint8_t ucQueueType); + +QueueHandle_t xQueueCreateCountingSemaphore (const UBaseType_t uxMaxCount, + const UBaseType_t uxInitialCount); + +void vQueueDelete (QueueHandle_t xQueue); + +BaseType_t xQueueGenericReset (QueueHandle_t xQueue, BaseType_t xNewQueue); + +BaseType_t xQueueGenericReceive (QueueHandle_t xQueue, + void * const pvBuffer, + TickType_t xTicksToWait, + const BaseType_t xJustPeeking); + +BaseType_t xQueueGenericSend (QueueHandle_t xQueue, + const void * const pvItemToQueue, + TickType_t xTicksToWait, + const BaseType_t xCopyPosition); + +BaseType_t xQueueReceiveFromISR (QueueHandle_t xQueue, void * const pvBuffer, + BaseType_t * const pxHigherPriorityTaskWoken); + +BaseType_t xQueueGenericSendFromISR (QueueHandle_t xQueue, + const void * const pvItemToQueue, + BaseType_t * const pxHigherPriorityTaskWoken, + const BaseType_t xCopyPosition ); + +BaseType_t xQueueGiveFromISR (QueueHandle_t xQueue, + BaseType_t * const pxHigherPriorityTaskWoken); + +UBaseType_t uxQueueMessagesWaiting( QueueHandle_t xQueue ); + +/* + * PLEASE NOTE: Following definitions were copied directly from the FreeRTOS + * distribution and are under the following copyright: + * + * FreeRTOS V8.2.0 - Copyright (C) 2015 Real Time Engineers Ltd. + * All rights reserved + * + * FreeRTOS is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License (version 2) as published by the + * Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + * + * Full license text is available on the following + * link: http://www.freertos.org/a00114.html + */ + +#define queueSEND_TO_BACK ( ( BaseType_t ) 0 ) +#define queueSEND_TO_FRONT ( ( BaseType_t ) 1 ) +#define queueOVERWRITE ( ( BaseType_t ) 2 ) + +#define queueQUEUE_TYPE_BASE ( ( uint8_t ) 0U ) +#define queueQUEUE_TYPE_SET ( ( uint8_t ) 0U ) +#define queueQUEUE_TYPE_MUTEX ( ( uint8_t ) 1U ) +#define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( ( uint8_t ) 2U ) +#define queueQUEUE_TYPE_BINARY_SEMAPHORE ( ( uint8_t ) 3U ) +#define queueQUEUE_TYPE_RECURSIVE_MUTEX ( ( uint8_t ) 4U ) + +#define errQUEUE_EMPTY ( ( BaseType_t ) 0 ) +#define errQUEUE_FULL ( ( BaseType_t ) 0 ) +#define errQUEUE_BLOCKED ( -4 ) +#define errQUEUE_YIELD ( -5 ) + +#define xQueueCreate( uxQueueLength, uxItemSize ) \ + xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) ) + +#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) \ + xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), \ + pdFALSE ) + +#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) \ + xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), \ + queueSEND_TO_BACK ) + +#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) \ + xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), \ + queueSEND_TO_BACK ) + +#define xQueueSendFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) \ + xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), \ + ( pxHigherPriorityTaskWoken ), \ + queueSEND_TO_BACK ) + +#define xQueueReset( xQueue ) xQueueGenericReset( xQueue, pdFALSE ) + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* FREERTOS_QUEUE_H */ diff --git a/cpu/esp8266/include/freertos/semphr.h b/cpu/esp8266/include/freertos/semphr.h new file mode 100644 index 000000000000..8b725b27e059 --- /dev/null +++ b/cpu/esp8266/include/freertos/semphr.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef FREERTOS_SEMPHR_H +#define FREERTOS_SEMPHR_H + +#ifndef DOXYGEN + +#include "freertos/FreeRTOS.h" + +#include +#include "mutex.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* SemaphoreHandle_t; + +SemaphoreHandle_t xSemaphoreCreateMutex(void); +SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void); + +void vSemaphoreDelete (SemaphoreHandle_t xSemaphore); + +BaseType_t xSemaphoreGive (SemaphoreHandle_t xSemaphore); +BaseType_t xSemaphoreTake (SemaphoreHandle_t xSemaphore, + TickType_t xTicksToWait); +BaseType_t xSemaphoreGiveRecursive (SemaphoreHandle_t xSemaphore); +BaseType_t xSemaphoreTakeRecursive (SemaphoreHandle_t xSemaphore, + TickType_t xTicksToWait); + +#define vPortCPUInitializeMutex(m) mutex_init(m) + +void vPortCPUAcquireMutex (portMUX_TYPE *mux); +void vPortCPUReleaseMutex (portMUX_TYPE *mux); + +/* + * PLEASE NOTE: Following definitions were copied directly from the FreeRTOS + * distribution and are under the following copyright: + * + * FreeRTOS V8.2.0 - Copyright (C) 2015 Real Time Engineers Ltd. + * All rights reserved + * + * FreeRTOS is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License (version 2) as published by the + * Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + * + * Full license text is available on the following + * link: http://www.freertos.org/a00114.html + */ + +#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( uint8_t ) 0U ) + +#define xSemaphoreCreateBinary() \ + xQueueGenericCreate( ( UBaseType_t ) 1, \ + semSEMAPHORE_QUEUE_ITEM_LENGTH, \ + queueQUEUE_TYPE_BINARY_SEMAPHORE ) +#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) \ + xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) ) + +#define xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken ) \ + xQueueReceiveFromISR( ( QueueHandle_t ) ( xSemaphore ), \ + NULL, ( pxHigherPriorityTaskWoken ) ) + +#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) \ + xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), \ + ( pxHigherPriorityTaskWoken ) ) + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* FREERTOS_SEMPHR_H */ diff --git a/cpu/esp8266/include/freertos/task.h b/cpu/esp8266/include/freertos/task.h new file mode 100644 index 000000000000..0f0a95839007 --- /dev/null +++ b/cpu/esp8266/include/freertos/task.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef FREERTOS_TASK_H +#define FREERTOS_TASK_H + +#ifndef DOXYGEN + +#include "thread.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define xTaskHandle TaskHandle_t +#define tskNO_AFFINITY INT_MAX + +#define taskDISABLE_INTERRUPTS portDISABLE_INTERRUPTS +#define taskENABLE_INTERRUPTS portENABLE_INTERRUPTS + +#define taskENTER_CRITICAL portENTER_CRITICAL +#define taskEXIT_CRITICAL portEXIT_CRITICAL + +typedef void (*TaskFunction_t)(void *); + +typedef void* TaskHandle_t; + +BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, + const char * const pcName, + const uint32_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pvCreatedTask); + +BaseType_t xTaskCreatePinnedToCore(TaskFunction_t pvTaskCode, + const char * const pcName, + const uint32_t usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pvCreatedTask, + const BaseType_t xCoreID); + +void vTaskDelete(TaskHandle_t xTaskToDelete); +void vTaskDelay(const TickType_t xTicksToDelay); + +TaskHandle_t xTaskGetCurrentTaskHandle(void); + +void vTaskEnterCritical(portMUX_TYPE *mux); +void vTaskExitCritical(portMUX_TYPE *mux); + +TickType_t xTaskGetTickCount (void); + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* FREERTOS_TASK_H */ diff --git a/cpu/esp8266/include/freertos/timers.h b/cpu/esp8266/include/freertos/timers.h new file mode 100644 index 000000000000..dbd37061bcb4 --- /dev/null +++ b/cpu/esp8266/include/freertos/timers.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef FREERTOS_TIMERS_H +#define FREERTOS_TIMERS_H + +#ifndef DOXYGEN + +#include "freertos/FreeRTOS.h" +#include "xtimer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* TimerHandle_t; + +#define TimerCallbackFunction_t xtimer_callback_t +#define tmrTIMER_CALLBACK TimerCallbackFunction_t + +TimerHandle_t xTimerCreate (const char * const pcTimerName, + const TickType_t xTimerPeriod, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction); +BaseType_t xTimerDelete(TimerHandle_t xTimer, TickType_t xBlockTime); +BaseType_t xTimerStart (TimerHandle_t xTimer, TickType_t xBlockTime); +BaseType_t xTimerStop (TimerHandle_t xTimer, TickType_t xBlockTime); +BaseType_t xTimerReset (TimerHandle_t xTimer, TickType_t xTicksToWait); + +void *pvTimerGetTimerID(const TimerHandle_t xTimer); + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* FREERTOS_TIMERS_H */ diff --git a/cpu/esp8266/include/freertos/xtensa_api.h b/cpu/esp8266/include/freertos/xtensa_api.h new file mode 100644 index 000000000000..61f53a76733c --- /dev/null +++ b/cpu/esp8266/include/freertos/xtensa_api.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + * + * FreeRTOS to RIOT-OS adaption module for source code compatibility + */ + +#ifndef FREERTOS_XTENSA_API_H +#define FREERTOS_XTENSA_API_H + +#include "xtensa/xtensa_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* FREERTOS_XTENSA_API_H */ diff --git a/cpu/esp8266/include/gpio_arch.h b/cpu/esp8266/include/gpio_arch.h new file mode 100644 index 000000000000..ece90ae81a7e --- /dev/null +++ b/cpu/esp8266/include/gpio_arch.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_esp8266 + * @{ + * + * @file + * @brief Architecture specific GPIO functions for ESP8266 + * + * @author Gunar Schorcht + * @} + */ + +#ifndef GPIO_ARCH_H +#define GPIO_ARCH_H + +#ifdef MCU_ESP32 +#include "periph/gpio.h" +#include "soc/io_mux_reg.h" +#include "soc/gpio_sig_map.h" +#endif /* MCU_ESP32 */ + +#ifndef DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif + +/** Definitions for source code compatibility with ESP-IDF */ +#define GPIO_MODE_INPUT GPIO_IN +#define GPIO_MODE_OUTPUT GPIO_OUT +#define GPIO_MODE_INPUT_OUTPUT GPIO_IN_OUT + +/** Definition of possible GPIO usage types (for internal use only) */ +typedef enum +{ + _GPIO = 0, /**< pin used as standard GPIO */ +#ifdef MCU_ESP32 + _ADC, /**< pin used as ADC input */ + _CAN, /**< pin used as CAN signal */ + _DAC, /**< pin used as DAC output */ + _EMAC, /**< pin used as EMAC signal */ +#endif /* MCU_ESP32 */ + _I2C, /**< pin used as I2C signal */ + _PWM, /**< pin used as PWM output */ + _SPI, /**< pin used as SPI interface */ + _SPIF, /**< pin used as SPI flash interface */ + _UART, /**< pin used as UART interface */ + _NOT_EXIST /**< pin cannot be used at all */ +} gpio_pin_usage_t; + + +#ifdef MCU_ESP32 + +/** Table of GPIO to IOMUX register mappings */ +extern const uint32_t _gpio_to_iomux_reg[]; +#define GPIO_PIN_MUX_REG _gpio_to_iomux_reg + +#else /* MCU_ESP32 */ + +/** Map of GPIO pin numbers to IOMUX pin numbers */ +extern const uint8_t _gpio_to_iomux[]; +/** Map of IOMUX pin numbers to GPIO pin numbers */ +extern const uint8_t _iomux_to_gpio[]; + +#endif /* MCU_ESP32 */ + +/** + * @brief Set the usage type of the pin + * @param pin GPIO pin + * @param usage GPIO pin usage type + * @return 0 on success + * -1 on error + */ +int gpio_set_pin_usage(gpio_t pin, gpio_pin_usage_t usage); + +/** + * @brief Get the usage type of the pin + * @param pin GPIO pin + * @return GPIO pin usage type on success + * _NOT_EXIST on error + */ +gpio_pin_usage_t gpio_get_pin_usage(gpio_t pin); + +/** + * @brief Get the usage type of the pin as string + * @param pin GPIO pin + * @return GPIO pin usage type string on success + * _NOT_EXIST on error + */ +const char* gpio_get_pin_usage_str(gpio_t pin); + +#ifdef MCU_ESP32 +/** + * @brief Disable the pullup of the pin + */ +void gpio_pullup_dis (gpio_t pin); + +/** + * @brief Returns the RTCIO pin number or -1 if the pin is not an RTCIO pin + */ +int8_t gpio_is_rtcio (gpio_t pin); + +/** + * @brief Configure sleep mode for an GPIO pin if the pin is an RTCIO pin + * @param pin GPIO pin + * @param mode active in sleep mode if true + * @param input as input if true, as output otherwise + * @return 0 on success + * @return -1 on invalid pin + */ +int gpio_config_sleep_mode (gpio_t pin, bool sleep_mode, bool input); + +/** + * @brief GPIO set direction init the pin calling gpio_init + * @param pin GPIO pin + * @param mode active in sleep mode if true + * @return 0 on success + * -1 on invalid argument + */ +int gpio_set_direction(gpio_t pin, gpio_mode_t mode); + +/** + * @brief extern declaration of ROM functions to avoid compilation problems + */ +void gpio_matrix_in (uint32_t gpio, uint32_t signal_idx, bool inv); +void gpio_matrix_out(uint32_t gpio, uint32_t signal_idx, bool out_inv, bool oen_inv); + +#endif /* MCU_ESP32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* GPIO_ARCH_H */ diff --git a/cpu/esp8266/include/gpio_common.h b/cpu/esp8266/include/gpio_common.h deleted file mode 100644 index 7e9116d1c60d..000000000000 --- a/cpu/esp8266/include/gpio_common.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2018 Gunar Schorcht - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup cpu_esp8266 - * @{ - * - * @file - * @brief Low-level GPIO driver implementation for ESP8266 - * - * @author Gunar Schorcht - * @} - */ - -#ifndef GPIO_COMMON_H -#define GPIO_COMMON_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** Map of GPIO pin numbers to IOMUX pin numbers */ -extern const uint8_t _gpio_to_iomux[]; -/** Map of IOMUX pin numbers to GPIO pin numbers */ -extern const uint8_t _iomux_to_gpio[]; - -/** - * @brief Definition of possible GPIO usage types - */ -typedef enum -{ - _GPIO = 0, /**< pin used as standard GPIO */ - _I2C, /**< pin used as I2C signal */ - _PWM, /**< pin used as PWM output */ - _SPI, /**< pin used as SPI interface */ - _SPIF, /**< pin used as SPI flash interface */ - _UART, /**< pin used as UART interface */ -} _gpio_pin_usage_t; - -/** - * Holds the usage type of each GPIO pin - */ -extern _gpio_pin_usage_t _gpio_pin_usage [GPIO_PIN_NUMOF]; - -#ifdef __cplusplus -} -#endif - -#endif /* GPIO_COMMON_H */ diff --git a/cpu/esp8266/include/irq_arch.h b/cpu/esp8266/include/irq_arch.h index b3dfbe807940..46626a081811 100644 --- a/cpu/esp8266/include/irq_arch.h +++ b/cpu/esp8266/include/irq_arch.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -39,9 +39,8 @@ extern uint32_t irq_interrupt_nesting; /** * @name Macros to enter and exit an ISR * - * In non-SDK interrupt handling all stuff is done in `_frxt_int_enter` - * and `_frxt_int_exit`. These macros do therefore nothing and are kept only - * for source code compatibility. + * Since all the stuff is done in `_frxt_int_enter` and `_frxt_int_exit`, these + * macros are doing nothing and are kept only for source code compatibility. * * @{ */ @@ -56,10 +55,28 @@ extern uint32_t irq_interrupt_nesting; * * @{ */ -#define critical_enter() int _irq_state = irq_disable () +#define critical_enter() int _irq_state = irq_disable() #define critical_exit() irq_restore(_irq_state) /** @} */ +/** + * @name Macros to enter and exit a critical region with state variable + * @{ + */ +#define critical_enter_var(m) m = irq_disable() +#define critical_exit_var(m) irq_restore(m) +/** @} */ + +/** + * @name Software interrupt types + * + * These definitions are used to distinguish different types of software + * interrupts in software interrupt handler. + */ +#define ETS_SOFT_INT_NONE 0 +#define ETS_SOFT_INT_YIELD 1 +#define ETS_SOFT_INT_HDL_MAC 2 + #ifdef __cplusplus } #endif diff --git a/cpu/esp8266/include/log_module.h b/cpu/esp8266/include/log_module.h new file mode 100644 index 000000000000..08f566b87a25 --- /dev/null +++ b/cpu/esp8266/include/log_module.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_esp8266 + * @{ + * + * @file + * @brief Log module to realize consistent log messages + * + * @author Gunar Schorcht + */ + +#ifndef LOG_MODULE_H +#define LOG_MODULE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "esp_common_log.h" + +#ifdef MODULE_LOG_PRINTFNOFORMAT + +static inline void log_write(unsigned level, const char *format, ...) { + (void)level; + puts(format); +} + +#else /* MODULE_LOG_PRINTFNOFORMAT */ + +#define log_write(level, ...) \ + do { \ + if (level == LOG_ERROR) { \ + LOG_TAG(LOG_ERROR, E, __func__, ##__VA_ARGS__); \ + } \ + else if (level == LOG_WARNING) { \ + LOG_TAG(LOG_WARNING, W, __func__, ##__VA_ARGS__); \ + } \ + else if (level == LOG_INFO) { \ + LOG_TAG(LOG_INFO, D, __func__, ##__VA_ARGS__); \ + } \ + else if (level == LOG_DEBUG) { \ + LOG_TAG(LOG_DEBUG, E, __func__, ##__VA_ARGS__); \ + } \ + } while (0) + +#endif /* MODULE_LOG_PRINTFNOFORMAT */ + +#ifdef __cplusplus +} +#endif +/**@}*/ +#endif /* LOG_MODULE_H */ diff --git a/cpu/esp8266/include/periph_cpu.h b/cpu/esp8266/include/periph_cpu.h index 09f0c0451c49..ae916c08dbdc 100644 --- a/cpu/esp8266/include/periph_cpu.h +++ b/cpu/esp8266/include/periph_cpu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -33,31 +33,55 @@ extern "C" { #define CPUID_LEN (4U) /** - * @name GPIO configuration of ESP8266 + * @name GPIO configuration * @{ */ /** - * @brief Available ports on the ESP8266 + * @brief Override the default gpio_t type definition + * + * This is required here to have gpio_t defined in this file. * @{ */ -#define PORT_GPIO 0 /**< port GPIO */ +#define HAVE_GPIO_T +typedef unsigned int gpio_t; /** @} */ /** * @brief Definition of a fitting UNDEF value */ -#define GPIO_UNDEF (GPIO_ID_NONE) +#define GPIO_UNDEF ((gpio_t)(UINT_MAX)) + +/** + * @brief Define a CPU specific GPIO pin generator macro + */ +#define GPIO_PIN(x, y) ((x & 0) | y) /** - * @brief Define CPU specific GPIO pin generator macro + * @brief Available GPIO ports on ESP8266 */ -#define GPIO_PIN(x, y) ((x << 4) | y) +#define PORT_GPIO (0) /** * @brief Define CPU specific number of GPIO pins */ -#define GPIO_PIN_NUMOF GPIO_PIN_COUNT+1 +#define GPIO_PIN_NUMOF (17) + +/** + * @brief Override flank selection values + * @{ + */ +#define HAVE_GPIO_FLANK_T +typedef enum { + GPIO_NONE = 0, + GPIO_RISING = 1, /**< emit interrupt on rising flank */ + GPIO_FALLING = 2, /**< emit interrupt on falling flank */ + GPIO_BOTH = 3, /**< emit interrupt on both flanks */ + GPIO_LOW = 4, /**< emit interrupt on low level */ + GPIO_HIGH = 5 /**< emit interrupt on low level */ +} gpio_flank_t; +/** @} */ +/** @} */ /** * @name Predefined GPIO names @@ -82,51 +106,64 @@ extern "C" { #define GPIO16 (GPIO_PIN(PORT_GPIO,16)) /** @} */ -#ifndef DOXYGEN -#define GPIO0_MASK (BIT(0)) -#define GPIO1_MASK (BIT(1)) -#define GPIO2_MASK (BIT(2)) -#define GPIO3_MASK (BIT(3)) -#define GPIO4_MASK (BIT(4)) -#define GPIO5_MASK (BIT(5)) -#define GPIO6_MASK (BIT(6)) -#define GPIO7_MASK (BIT(7)) -#define GPIO8_MASK (BIT(8)) -#define GPIO9_MASK (BIT(9)) -#define GPIO10_MASK (BIT(10)) -#define GPIO11_MASK (BIT(11)) -#define GPIO12_MASK (BIT(12)) -#define GPIO13_MASK (BIT(13)) -#define GPIO14_MASK (BIT(14)) -#define GPIO15_MASK (BIT(15)) -#define GPIO16_MASK (BIT(16)) +/** + * @name I2C configuration + * + * ESP8266 provides up to two bit-banging I2C interfaces. + * + * The board-specific configuration of the I2C interface I2C_DEV(n) requires + * the definition of + * + * I2Cn_SPEED, the bus speed, + * I2Cn_SCL, the GPIO used as SCL signal, and + * I2Cn_SDA, the GPIO used as SDA signal, + * + * where n can be 0 or 1. If they are not defined, the I2C interface + * I2C_DEV(n) is not used. + * + * @note The configuration of the I2C interfaces I2C_DEV(n) must be in + * continuous ascending order of n. + * + * I2C_NUMOF is determined automatically from board-specific peripheral + * definitions of I2Cn_SPEED, I2Cn_SCK, and I2Cn_SDA. + * + * @{ + */ /** - * @brief Override flank selection values + * @brief Override I2C clock speed values + * + * This is required here to have i2c_speed_t defined in this file. * @{ */ -#define HAVE_GPIO_FLANK_T +#define HAVE_I2C_SPEED_T typedef enum { - GPIO_NONE = 0, - GPIO_RISING = 1, /**< emit interrupt on rising flank */ - GPIO_FALLING = 2, /**< emit interrupt on falling flank */ - GPIO_BOTH = 3, /**< emit interrupt on both flanks */ - GPIO_LOW = 4, /**< emit interrupt on low level */ - GPIO_HIGH = 5 /**< emit interrupt on low level */ -} gpio_flank_t; + I2C_SPEED_LOW = 0, /**< 10 kbit/s */ + I2C_SPEED_NORMAL, /**< 100 kbit/s */ + I2C_SPEED_FAST, /**< 400 kbit/s */ + I2C_SPEED_FAST_PLUS, /**< 1 Mbit/s */ + I2C_SPEED_HIGH, /**< not supported */ +} i2c_speed_t; /** @} */ -#endif /* DOXYGEN */ -/** @} */ +/** + * @brief I2C configuration structure type + */ +typedef struct { + i2c_speed_t speed; /**< I2C bus speed */ + gpio_t scl; /**< GPIO used as SCL pin */ + gpio_t sda; /**< GPIO used as SDA pin */ +} i2c_conf_t; /** - * @name I2C configuration - * @{ + * @brief Maximum number of I2C interfaces that can be used by board definitions */ -#define PERIPH_I2C_NEED_READ_REG -#define PERIPH_I2C_NEED_READ_REGS -#define PERIPH_I2C_NEED_WRITE_REG -#define PERIPH_I2C_NEED_WRITE_REGS +#define I2C_NUMOF_MAX (2) + +#define PERIPH_I2C_NEED_READ_REG /**< i2c_read_reg required */ +#define PERIPH_I2C_NEED_READ_REGS /**< i2c_read_regs required */ +#define PERIPH_I2C_NEED_WRITE_REG /**< i2c_write_reg required */ +#define PERIPH_I2C_NEED_WRITE_REGS /**< i2c_write_regs required */ /** @} */ /** @@ -139,17 +176,85 @@ typedef enum { /** @} */ /** - * @name SPI configuration + * @name PWM configuration + * + * The hardware implementation of ESP8266 PWM supports only frequencies as + * power of two. Therefore a software implementation of one PWM device + * PWM_DEV(0) with up to 8 PWM channels (#PWM_CHANNEL_NUM_MAX) is used. The + * GPIOs that can be used as PWM channels are defined by #PWM0_GPIOS in board + * definition. + * + * @note The minimum PWM period that can be realized is 10 us or 100.000 PWM + * clock cycles per second. Therefore, the product of frequency and resolution + * should not be greater than 100.000. Otherwise the frequency is scaled down + * automatically. + * + * @{ + */ + +/** + * @brief Maximum number of PWM devices. + */ +#define PWM_NUMOF_MAX (1) + +/** + * @brief Maximum number of channels per PWM device. + */ +#define PWM_CHANNEL_NUM_MAX (8) + +/** @} */ + +/** + * @name SPI configuration + * + * ESP8266 has two SPI controllers: + * + * - _CSPI_ for caching and accessing the flash memory
+ * - _HSPI_ for peripherals + * + * Thus, _HSPI_ is the only SPI interface that is available for peripherals. + * It is exposed as RIOT's SPI_DEV(0). The pin configuration of the _HSPI_ + * interface is fixed as shown in following table. + * + * Signal | Pin + * -- --------|------- + * #SPI0_MISO | GPIO12 + * #SPI0_MOSI | GPIO13 + * #SPI0_SCK | GPIO14 + * #SPI0_CS0 | GPIOn with n = 0, 2, 4, 5, 15, 16 (additionally 9, 10 in DOUT flash mode) + * + * The only pin definition that can be overridden by an application-specific + * board configuration is the CS signal defined by #SPI0_CS0. + * * @{ */ -#if defined(MODULE_PERIPH_SPI) -#define PERIPH_SPI_NEEDS_TRANSFER_BYTE -#define PERIPH_SPI_NEEDS_TRANSFER_REG -#define PERIPH_SPI_NEEDS_TRANSFER_REGS +/** + * @brief SPI controllers that can be used for peripheral interfaces + */ +typedef enum { + HSPI = 1, /**< HSPI interface controller */ +} spi_ctrl_t; -#endif /* MODULE_PERIPH_SPI */ +/** + * @brief SPI configuration structure type + */ +typedef struct { + spi_ctrl_t ctrl; /**< SPI controller used for the interface */ + gpio_t sck; /**< GPIO used as SCK pin */ + gpio_t mosi; /**< GPIO used as MOSI pin */ + gpio_t miso; /**< GPIO used as MISO pin */ + gpio_t cs; /**< GPIO used as CS0 pin */ +} spi_conf_t; +/** + * @brief Maximum number of SPI interfaces + */ +#define SPI_NUMOF_MAX (1) + +#define PERIPH_SPI_NEEDS_TRANSFER_BYTE /**< requires function spi_transfer_byte */ +#define PERIPH_SPI_NEEDS_TRANSFER_REG /**< requires function spi_transfer_reg */ +#define PERIPH_SPI_NEEDS_TRANSFER_REGS /**< requires function spi_transfer_regs */ /** @} */ /** @@ -157,6 +262,28 @@ typedef enum { */ #define PERIPH_TIMER_PROVIDES_SET +/** + * @name UART configuration + * + * All ESP8266 boards have exactly one UART device with fixed pin mapping. + * + * @{ + */ + +/** + * @brief UART configuration structure type + */ +typedef struct { + gpio_t txd; /**< GPIO used as TxD pin */ + gpio_t rxd; /**< GPIO used as RxD pin */ +} uart_conf_t; + +/** + * @brief Maximum number of UART interfaces + */ +#define UART_NUMOF_MAX (1) +/** @} */ + #ifdef __cplusplus } #endif diff --git a/cpu/esp8266/include/sdk_conf.h b/cpu/esp8266/include/sdk_conf.h new file mode 100644 index 000000000000..67f8954e2290 --- /dev/null +++ b/cpu/esp8266/include/sdk_conf.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_esp8266 + * @{ + * + * @file + * @brief SDK configuration compatible to the ESP-IDF + * + * This file defines configuration parameters that are only required for source + * code compatibility with the SDK. These configuration parameters are not used + * directly to configure the compilation of RIOT-OS. However, some of them can + * be overrien overridden by application-specific board configuration. + * + * @author Gunar Schorcht + */ + +#ifndef SDK_CONF_H +#define SDK_CONF_H + +#ifndef DOXYGEN + +#include "board.h" +#include "esp_image_format.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief SDK version number + * + * Determined with `git describe --tags` in `$ESP8266_SDK_DIR` + */ +#define IDF_VER "v3.1-4-g08c234e" + +/** + * @name Default console configuration + * + * STDIO_UART_BAUDRATE is used as CONFIG_CONSOLE_UART_BAUDRATE and + * can be overridden by an application specific configuration. + * + * @{ + */ +#define CONFIG_CONSOLE_UART_NUM (0) +#ifndef CONFIG_CONSOLE_UART_BAUDRATE +#define CONFIG_CONSOLE_UART_BAUDRATE (STDIO_UART_BAUDRATE) +#endif +/** @} */ + +#define CONFIG_APP1_SIZE (0xf0000) +#define CONFIG_APP1_OFFSET (0x10000) + +#define CONFIG_SOC_IRAM_SIZE (0xc000) + +#define CONFIG_TASK_WDT_PANIC +#define CONFIG_TASK_WDT_TIMEOUT_S (15) + +#define CONFIG_WIFI_PPT_TASKSTACK_SIZE (3584) +#define CONFIG_MAIN_TASK_STACK_SIZE (2048) +#define CONFIG_EVENT_LOOP_STACK_SIZE (2048) + +#define CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE +#define CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION (0) + +#define CONFIG_SPI_FLASH_FREQ (ESP_IMAGE_SPI_SPEED_40M) /* 40 MHz */ +#define CONFIG_SPI_FLASH_MODE (ESP_IMAGE_SPI_MODE_DIO) /* DIO mode */ +#define CONFIG_SPI_FLASH_SIZE (0x100000) + +#define CONFIG_SCAN_AP_MAX (32) + +#define CONFIG_USING_NEW_ETS_VPRINTF +#define CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* SDK_CONF_H */ diff --git a/cpu/esp8266/include/stdio.h b/cpu/esp8266/include/stdio.h new file mode 100644 index 000000000000..4fc9320acf48 --- /dev/null +++ b/cpu/esp8266/include/stdio.h @@ -0,0 +1,748 @@ +/** + * This file is a modification of the original file to overwrite the *putchar* + * and *getchar* macros in the case the *uart_stdio* module is used. If the + * *uart_stdio* module is used, *putchar* and *getchar* are redirections to + * according *uart_stdio_* functions. + */ + +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#)stdio.h 5.3 (Berkeley) 3/15/86 + */ + +/* + * NB: to fit things in six character monocase externals, the + * stdio code uses the prefix `__s' for stdio objects, typically + * followed by a three-character attempt at a mnemonic. + */ + +#ifndef STDIO_H +#define STDIO_H + +#ifndef DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif + +#include "_ansi.h" + +#define _FSTDIO /* ``function stdio'' */ + +#define __need_size_t +#define __need_NULL +#include +#include + +#define __need___va_list +#include + +/* + * defines __FILE, _fpos_t. + * They must be defined there because struct _reent needs them (and we don't + * want reent.h to include this file. + */ + +#include +#include + +_BEGIN_STD_C + +typedef __FILE FILE; + +#ifdef __CYGWIN__ +typedef _fpos64_t fpos_t; +#else +typedef _fpos_t fpos_t; +#ifdef __LARGE64_FILES +typedef _fpos64_t fpos64_t; +#endif +#endif /* !__CYGWIN__ */ + +#include + +#define __SLBF 0x0001 /* line buffered */ +#define __SNBF 0x0002 /* unbuffered */ +#define __SRD 0x0004 /* OK to read */ +#define __SWR 0x0008 /* OK to write */ + /* RD and WR are never simultaneously asserted */ +#define __SRW 0x0010 /* open for reading & writing */ +#define __SEOF 0x0020 /* found EOF */ +#define __SERR 0x0040 /* found error */ +#define __SMBF 0x0080 /* _buf is from malloc */ +#define __SAPP 0x0100 /* fdopen()ed in append mode - so must write to end */ +#define __SSTR 0x0200 /* this is an sprintf/snprintf string */ +#define __SOPT 0x0400 /* do fseek() optimisation */ +#define __SNPT 0x0800 /* do not do fseek() optimisation */ +#define __SOFF 0x1000 /* set iff _offset is in fact correct */ +#define __SORD 0x2000 /* true => stream orientation (byte/wide) decided */ +#if defined(__CYGWIN__) +#define __SCLE 0x4000 /* convert line endings CR/LF <-> NL */ +#endif +#define __SL64 0x8000 /* is 64-bit offset large file */ + +/* _flags2 flags */ +#define __SNLK 0x0001 /* stdio functions do not lock streams themselves */ +#define __SWID 0x2000 /* true => stream orientation wide, false => byte, only valid if __SORD in _flags is true */ + +/* + * The following three definitions are for ANSI C, which took them + * from System V, which stupidly took internal interface macros and + * made them official arguments to setvbuf(), without renaming them. + * Hence, these ugly _IOxxx names are *supposed* to appear in user code. + * + * Although these happen to match their counterparts above, the + * implementation does not rely on that (so these could be renumbered). + */ +#define _IOFBF 0 /* setvbuf should set fully buffered */ +#define _IOLBF 1 /* setvbuf should set line buffered */ +#define _IONBF 2 /* setvbuf should set unbuffered */ + +#define EOF (-1) + +#ifdef __BUFSIZ__ +#define BUFSIZ __BUFSIZ__ +#else +#define BUFSIZ 1024 +#endif + +#ifdef __FOPEN_MAX__ +#define FOPEN_MAX __FOPEN_MAX__ +#else +#define FOPEN_MAX 20 +#endif + +#ifdef __FILENAME_MAX__ +#define FILENAME_MAX __FILENAME_MAX__ +#else +#define FILENAME_MAX 1024 +#endif + +#ifdef __L_tmpnam__ +#define L_tmpnam __L_tmpnam__ +#else +#define L_tmpnam FILENAME_MAX +#endif + +#ifndef __STRICT_ANSI__ +#define P_tmpdir "/tmp" +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 /* set file offset to offset */ +#endif +#ifndef SEEK_CUR +#define SEEK_CUR 1 /* set file offset to current plus offset */ +#endif +#ifndef SEEK_END +#define SEEK_END 2 /* set file offset to EOF plus offset */ +#endif + +#define TMP_MAX 26 + +#define stdin (_REENT->_stdin) +#define stdout (_REENT->_stdout) +#define stderr (_REENT->_stderr) + +#define _stdin_r(x) ((x)->_stdin) +#define _stdout_r(x) ((x)->_stdout) +#define _stderr_r(x) ((x)->_stderr) + +/* + * Functions defined in ANSI C standard. + */ + +#ifndef __VALIST +#ifdef __GNUC__ +#define __VALIST __gnuc_va_list +#else +#define __VALIST char* +#endif +#endif + +FILE * _EXFUN(tmpfile, (void)); +char * _EXFUN(tmpnam, (char *)); +#if __BSD_VISIBLE || __XSI_VISIBLE || __POSIX_VISIBLE >= 200112 +char * _EXFUN(tempnam, (const char *, const char *)); +#endif +int _EXFUN(fclose, (FILE *)); +int _EXFUN(fflush, (FILE *)); +FILE * _EXFUN(freopen, (const char *__restrict, const char *__restrict, FILE *__restrict)); +void _EXFUN(setbuf, (FILE *__restrict, char *__restrict)); +int _EXFUN(setvbuf, (FILE *__restrict, char *__restrict, int, size_t)); +int _EXFUN(fprintf, (FILE *__restrict, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__printf__, 2, 3)))); +int _EXFUN(fscanf, (FILE *__restrict, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__scanf__, 2, 3)))); +int _EXFUN(printf, (const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__printf__, 1, 2)))); +int _EXFUN(scanf, (const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__scanf__, 1, 2)))); +int _EXFUN(sscanf, (const char *__restrict, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__scanf__, 2, 3)))); +int _EXFUN(vfprintf, (FILE *__restrict, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 2, 0)))); +int _EXFUN(vprintf, (const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 1, 0)))); +int _EXFUN(vsprintf, (char *__restrict, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 2, 0)))); +int _EXFUN(fgetc, (FILE *)); +char * _EXFUN(fgets, (char *__restrict, int, FILE *__restrict)); +int _EXFUN(fputc, (int, FILE *)); +int _EXFUN(fputs, (const char *__restrict, FILE *__restrict)); +int _EXFUN(getc, (FILE *)); +int _EXFUN(getchar, (void)); +char * _EXFUN(gets, (char *)); +int _EXFUN(putc, (int, FILE *)); +int _EXFUN(putchar, (int)); +int _EXFUN(puts, (const char *)); +int _EXFUN(ungetc, (int, FILE *)); +size_t _EXFUN(fread, (_PTR __restrict, size_t _size, size_t _n, FILE *__restrict)); +size_t _EXFUN(fwrite, (const _PTR __restrict , size_t _size, size_t _n, FILE *)); +#ifdef _COMPILING_NEWLIB +int _EXFUN(fgetpos, (FILE *, _fpos_t *)); +#else +int _EXFUN(fgetpos, (FILE *__restrict, fpos_t *__restrict)); +#endif +int _EXFUN(fseek, (FILE *, long, int)); +#ifdef _COMPILING_NEWLIB +int _EXFUN(fsetpos, (FILE *, const _fpos_t *)); +#else +int _EXFUN(fsetpos, (FILE *, const fpos_t *)); +#endif +long _EXFUN(ftell, ( FILE *)); +void _EXFUN(rewind, (FILE *)); +void _EXFUN(clearerr, (FILE *)); +int _EXFUN(feof, (FILE *)); +int _EXFUN(ferror, (FILE *)); +void _EXFUN(perror, (const char *)); +#ifndef _REENT_ONLY +FILE * _EXFUN(fopen, (const char *__restrict _name, const char *__restrict _type)); +int _EXFUN(sprintf, (char *__restrict, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__printf__, 2, 3)))); +int _EXFUN(remove, (const char *)); +int _EXFUN(rename, (const char *, const char *)); +#ifdef _COMPILING_NEWLIB +int _EXFUN(_rename, (const char *, const char *)); +#endif +#endif +#if !defined(__STRICT_ANSI__) || defined(__USE_XOPEN2K) +#ifdef _COMPILING_NEWLIB +int _EXFUN(fseeko, (FILE *, _off_t, int)); +_off_t _EXFUN(ftello, ( FILE *)); +#else +int _EXFUN(fseeko, (FILE *, off_t, int)); +off_t _EXFUN(ftello, ( FILE *)); +#endif +#endif +#if __GNU_VISIBLE +int _EXFUN(fcloseall, (_VOID)); +#endif +#if !defined(__STRICT_ANSI__) || (__STDC_VERSION__ >= 199901L) || (__cplusplus >= 201103L) +#ifndef _REENT_ONLY +int _EXFUN(asiprintf, (char **, const char *, ...) + _ATTRIBUTE ((__format__ (__printf__, 2, 3)))); +char * _EXFUN(asniprintf, (char *, size_t *, const char *, ...) + _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); +char * _EXFUN(asnprintf, (char *__restrict, size_t *__restrict, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); +int _EXFUN(asprintf, (char **__restrict, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__printf__, 2, 3)))); +#ifndef diprintf +int _EXFUN(diprintf, (int, const char *, ...) + _ATTRIBUTE ((__format__ (__printf__, 2, 3)))); +#endif +int _EXFUN(fiprintf, (FILE *, const char *, ...) + _ATTRIBUTE ((__format__ (__printf__, 2, 3)))); +int _EXFUN(fiscanf, (FILE *, const char *, ...) + _ATTRIBUTE ((__format__ (__scanf__, 2, 3)))); +int _EXFUN(iprintf, (const char *, ...) + _ATTRIBUTE ((__format__ (__printf__, 1, 2)))); +int _EXFUN(iscanf, (const char *, ...) + _ATTRIBUTE ((__format__ (__scanf__, 1, 2)))); +int _EXFUN(siprintf, (char *, const char *, ...) + _ATTRIBUTE ((__format__ (__printf__, 2, 3)))); +int _EXFUN(siscanf, (const char *, const char *, ...) + _ATTRIBUTE ((__format__ (__scanf__, 2, 3)))); +int _EXFUN(snprintf, (char *__restrict, size_t, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); +int _EXFUN(sniprintf, (char *, size_t, const char *, ...) + _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); +int _EXFUN(vasiprintf, (char **, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 2, 0)))); +char * _EXFUN(vasniprintf, (char *, size_t *, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); +char * _EXFUN(vasnprintf, (char *, size_t *, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); +int _EXFUN(vasprintf, (char **, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 2, 0)))); +int _EXFUN(vdiprintf, (int, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 2, 0)))); +int _EXFUN(vfiprintf, (FILE *, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 2, 0)))); +int _EXFUN(vfiscanf, (FILE *, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__scanf__, 2, 0)))); +int _EXFUN(vfscanf, (FILE *__restrict, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__scanf__, 2, 0)))); +int _EXFUN(viprintf, (const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 1, 0)))); +int _EXFUN(viscanf, (const char *, __VALIST) + _ATTRIBUTE ((__format__ (__scanf__, 1, 0)))); +int _EXFUN(vscanf, (const char *, __VALIST) + _ATTRIBUTE ((__format__ (__scanf__, 1, 0)))); +int _EXFUN(vsiprintf, (char *, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 2, 0)))); +int _EXFUN(vsiscanf, (const char *, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__scanf__, 2, 0)))); +int _EXFUN(vsniprintf, (char *, size_t, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); +int _EXFUN(vsnprintf, (char *__restrict, size_t, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); +int _EXFUN(vsscanf, (const char *__restrict, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__scanf__, 2, 0)))); +#endif /* !_REENT_ONLY */ +#endif /* !__STRICT_ANSI__ */ + +/* + * Routines in POSIX 1003.1:2001. + */ + +#ifndef __STRICT_ANSI__ +#ifndef _REENT_ONLY +FILE * _EXFUN(fdopen, (int, const char *)); +#endif +int _EXFUN(fileno, (FILE *)); +int _EXFUN(getw, (FILE *)); +int _EXFUN(pclose, (FILE *)); +FILE * _EXFUN(popen, (const char *, const char *)); +int _EXFUN(putw, (int, FILE *)); +void _EXFUN(setbuffer, (FILE *, char *, int)); +int _EXFUN(setlinebuf, (FILE *)); +int _EXFUN(getc_unlocked, (FILE *)); +int _EXFUN(getchar_unlocked, (void)); +void _EXFUN(flockfile, (FILE *)); +int _EXFUN(ftrylockfile, (FILE *)); +void _EXFUN(funlockfile, (FILE *)); +int _EXFUN(putc_unlocked, (int, FILE *)); +int _EXFUN(putchar_unlocked, (int)); +#endif /* ! __STRICT_ANSI__ */ + +/* + * Routines in POSIX 1003.1:200x. + */ + +#ifndef __STRICT_ANSI__ +# ifndef _REENT_ONLY +# ifndef dprintf +int _EXFUN(dprintf, (int, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__printf__, 2, 3)))); +# endif +FILE * _EXFUN(fmemopen, (void *__restrict, size_t, const char *__restrict)); +/* getdelim - see __getdelim for now */ +/* getline - see __getline for now */ +FILE * _EXFUN(open_memstream, (char **, size_t *)); +#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809 +int _EXFUN(renameat, (int, const char *, int, const char *)); +#endif +int _EXFUN(vdprintf, (int, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 2, 0)))); +# endif +#endif + +/* + * Recursive versions of the above. + */ + +int _EXFUN(_asiprintf_r, (struct _reent *, char **, const char *, ...) + _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); +char * _EXFUN(_asniprintf_r, (struct _reent *, char *, size_t *, const char *, ...) + _ATTRIBUTE ((__format__ (__printf__, 4, 5)))); +char * _EXFUN(_asnprintf_r, (struct _reent *, char *__restrict, size_t *__restrict, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__printf__, 4, 5)))); +int _EXFUN(_asprintf_r, (struct _reent *, char **__restrict, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); +int _EXFUN(_diprintf_r, (struct _reent *, int, const char *, ...) + _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); +int _EXFUN(_dprintf_r, (struct _reent *, int, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); +int _EXFUN(_fclose_r, (struct _reent *, FILE *)); +int _EXFUN(_fcloseall_r, (struct _reent *)); +FILE * _EXFUN(_fdopen_r, (struct _reent *, int, const char *)); +int _EXFUN(_fflush_r, (struct _reent *, FILE *)); +int _EXFUN(_fgetc_r, (struct _reent *, FILE *)); +int _EXFUN(_fgetc_unlocked_r, (struct _reent *, FILE *)); +char * _EXFUN(_fgets_r, (struct _reent *, char *__restrict, int, FILE *__restrict)); +char * _EXFUN(_fgets_unlocked_r, (struct _reent *, char *__restrict, int, FILE *__restrict)); +#ifdef _COMPILING_NEWLIB +int _EXFUN(_fgetpos_r, (struct _reent *, FILE *__restrict, _fpos_t *__restrict)); +int _EXFUN(_fsetpos_r, (struct _reent *, FILE *, const _fpos_t *)); +#else +int _EXFUN(_fgetpos_r, (struct _reent *, FILE *, fpos_t *)); +int _EXFUN(_fsetpos_r, (struct _reent *, FILE *, const fpos_t *)); +#endif +int _EXFUN(_fiprintf_r, (struct _reent *, FILE *, const char *, ...) + _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); +int _EXFUN(_fiscanf_r, (struct _reent *, FILE *, const char *, ...) + _ATTRIBUTE ((__format__ (__scanf__, 3, 4)))); +FILE * _EXFUN(_fmemopen_r, (struct _reent *, void *__restrict, size_t, const char *__restrict)); +FILE * _EXFUN(_fopen_r, (struct _reent *, const char *__restrict, const char *__restrict)); +FILE * _EXFUN(_freopen_r, (struct _reent *, const char *__restrict, const char *__restrict, FILE *__restrict)); +int _EXFUN(_fprintf_r, (struct _reent *, FILE *__restrict, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); +int _EXFUN(_fpurge_r, (struct _reent *, FILE *)); +int _EXFUN(_fputc_r, (struct _reent *, int, FILE *)); +int _EXFUN(_fputc_unlocked_r, (struct _reent *, int, FILE *)); +int _EXFUN(_fputs_r, (struct _reent *, const char *__restrict, FILE *__restrict)); +int _EXFUN(_fputs_unlocked_r, (struct _reent *, const char *__restrict, FILE *__restrict)); +size_t _EXFUN(_fread_r, (struct _reent *, _PTR __restrict, size_t _size, size_t _n, FILE *__restrict)); +size_t _EXFUN(_fread_unlocked_r, (struct _reent *, _PTR __restrict, size_t _size, size_t _n, FILE *__restrict)); +int _EXFUN(_fscanf_r, (struct _reent *, FILE *__restrict, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__scanf__, 3, 4)))); +int _EXFUN(_fseek_r, (struct _reent *, FILE *, long, int)); +int _EXFUN(_fseeko_r,(struct _reent *, FILE *, _off_t, int)); +long _EXFUN(_ftell_r, (struct _reent *, FILE *)); +_off_t _EXFUN(_ftello_r,(struct _reent *, FILE *)); +void _EXFUN(_rewind_r, (struct _reent *, FILE *)); +size_t _EXFUN(_fwrite_r, (struct _reent *, const _PTR __restrict, size_t _size, size_t _n, FILE *__restrict)); +size_t _EXFUN(_fwrite_unlocked_r, (struct _reent *, const _PTR __restrict, size_t _size, size_t _n, FILE *__restrict)); +int _EXFUN(_getc_r, (struct _reent *, FILE *)); +int _EXFUN(_getc_unlocked_r, (struct _reent *, FILE *)); +int _EXFUN(_getchar_r, (struct _reent *)); +int _EXFUN(_getchar_unlocked_r, (struct _reent *)); +char * _EXFUN(_gets_r, (struct _reent *, char *)); +int _EXFUN(_iprintf_r, (struct _reent *, const char *, ...) + _ATTRIBUTE ((__format__ (__printf__, 2, 3)))); +int _EXFUN(_iscanf_r, (struct _reent *, const char *, ...) + _ATTRIBUTE ((__format__ (__scanf__, 2, 3)))); +FILE * _EXFUN(_open_memstream_r, (struct _reent *, char **, size_t *)); +void _EXFUN(_perror_r, (struct _reent *, const char *)); +int _EXFUN(_printf_r, (struct _reent *, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__printf__, 2, 3)))); +int _EXFUN(_putc_r, (struct _reent *, int, FILE *)); +int _EXFUN(_putc_unlocked_r, (struct _reent *, int, FILE *)); +int _EXFUN(_putchar_unlocked_r, (struct _reent *, int)); +int _EXFUN(_putchar_r, (struct _reent *, int)); +int _EXFUN(_puts_r, (struct _reent *, const char *)); +int _EXFUN(_remove_r, (struct _reent *, const char *)); +int _EXFUN(_rename_r, (struct _reent *, + const char *_old, const char *_new)); +int _EXFUN(_scanf_r, (struct _reent *, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__scanf__, 2, 3)))); +int _EXFUN(_siprintf_r, (struct _reent *, char *, const char *, ...) + _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); +int _EXFUN(_siscanf_r, (struct _reent *, const char *, const char *, ...) + _ATTRIBUTE ((__format__ (__scanf__, 3, 4)))); +int _EXFUN(_sniprintf_r, (struct _reent *, char *, size_t, const char *, ...) + _ATTRIBUTE ((__format__ (__printf__, 4, 5)))); +int _EXFUN(_snprintf_r, (struct _reent *, char *__restrict, size_t, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__printf__, 4, 5)))); +int _EXFUN(_sprintf_r, (struct _reent *, char *__restrict, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); +int _EXFUN(_sscanf_r, (struct _reent *, const char *__restrict, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__scanf__, 3, 4)))); +char * _EXFUN(_tempnam_r, (struct _reent *, const char *, const char *)); +FILE * _EXFUN(_tmpfile_r, (struct _reent *)); +char * _EXFUN(_tmpnam_r, (struct _reent *, char *)); +int _EXFUN(_ungetc_r, (struct _reent *, int, FILE *)); +int _EXFUN(_vasiprintf_r, (struct _reent *, char **, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); +char * _EXFUN(_vasniprintf_r, (struct _reent*, char *, size_t *, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 4, 0)))); +char * _EXFUN(_vasnprintf_r, (struct _reent*, char *, size_t *, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 4, 0)))); +int _EXFUN(_vasprintf_r, (struct _reent *, char **, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); +int _EXFUN(_vdiprintf_r, (struct _reent *, int, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); +int _EXFUN(_vdprintf_r, (struct _reent *, int, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); +int _EXFUN(_vfiprintf_r, (struct _reent *, FILE *, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); +int _EXFUN(_vfiscanf_r, (struct _reent *, FILE *, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__scanf__, 3, 0)))); +int _EXFUN(_vfprintf_r, (struct _reent *, FILE *__restrict, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); +int _EXFUN(_vfscanf_r, (struct _reent *, FILE *__restrict, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__scanf__, 3, 0)))); +int _EXFUN(_viprintf_r, (struct _reent *, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 2, 0)))); +int _EXFUN(_viscanf_r, (struct _reent *, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__scanf__, 2, 0)))); +int _EXFUN(_vprintf_r, (struct _reent *, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 2, 0)))); +int _EXFUN(_vscanf_r, (struct _reent *, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__scanf__, 2, 0)))); +int _EXFUN(_vsiprintf_r, (struct _reent *, char *, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); +int _EXFUN(_vsiscanf_r, (struct _reent *, const char *, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__scanf__, 3, 0)))); +int _EXFUN(_vsniprintf_r, (struct _reent *, char *, size_t, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 4, 0)))); +int _EXFUN(_vsnprintf_r, (struct _reent *, char *__restrict, size_t, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 4, 0)))); +int _EXFUN(_vsprintf_r, (struct _reent *, char *__restrict, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); +int _EXFUN(_vsscanf_r, (struct _reent *, const char *__restrict, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__scanf__, 3, 0)))); + +/* Other extensions. */ + +int _EXFUN(fpurge, (FILE *)); +ssize_t _EXFUN(__getdelim, (char **, size_t *, int, FILE *)); +ssize_t _EXFUN(__getline, (char **, size_t *, FILE *)); + +#if __BSD_VISIBLE +void _EXFUN(clearerr_unlocked, (FILE *)); +int _EXFUN(feof_unlocked, (FILE *)); +int _EXFUN(ferror_unlocked, (FILE *)); +int _EXFUN(fileno_unlocked, (FILE *)); +int _EXFUN(fflush_unlocked, (FILE *)); +int _EXFUN(fgetc_unlocked, (FILE *)); +int _EXFUN(fputc_unlocked, (int, FILE *)); +size_t _EXFUN(fread_unlocked, (_PTR __restrict, size_t _size, size_t _n, FILE *__restrict)); +size_t _EXFUN(fwrite_unlocked, (const _PTR __restrict , size_t _size, size_t _n, FILE *)); +#endif + +#if __GNU_VISIBLE +char * _EXFUN(fgets_unlocked, (char *__restrict, int, FILE *__restrict)); +int _EXFUN(fputs_unlocked, (const char *__restrict, FILE *__restrict)); +#endif + +#ifdef __LARGE64_FILES +#if !defined(__CYGWIN__) || defined(_COMPILING_NEWLIB) +FILE * _EXFUN(fdopen64, (int, const char *)); +FILE * _EXFUN(fopen64, (const char *, const char *)); +FILE * _EXFUN(freopen64, (_CONST char *, _CONST char *, FILE *)); +_off64_t _EXFUN(ftello64, (FILE *)); +_off64_t _EXFUN(fseeko64, (FILE *, _off64_t, int)); +int _EXFUN(fgetpos64, (FILE *, _fpos64_t *)); +int _EXFUN(fsetpos64, (FILE *, const _fpos64_t *)); +FILE * _EXFUN(tmpfile64, (void)); + +FILE * _EXFUN(_fdopen64_r, (struct _reent *, int, const char *)); +FILE * _EXFUN(_fopen64_r, (struct _reent *,const char *, const char *)); +FILE * _EXFUN(_freopen64_r, (struct _reent *, _CONST char *, _CONST char *, FILE *)); +_off64_t _EXFUN(_ftello64_r, (struct _reent *, FILE *)); +_off64_t _EXFUN(_fseeko64_r, (struct _reent *, FILE *, _off64_t, int)); +int _EXFUN(_fgetpos64_r, (struct _reent *, FILE *, _fpos64_t *)); +int _EXFUN(_fsetpos64_r, (struct _reent *, FILE *, const _fpos64_t *)); +FILE * _EXFUN(_tmpfile64_r, (struct _reent *)); +#endif /* !__CYGWIN__ */ +#endif /* __LARGE64_FILES */ + +/* + * Routines internal to the implementation. + */ + +int _EXFUN(__srget_r, (struct _reent *, FILE *)); +int _EXFUN(__swbuf_r, (struct _reent *, int, FILE *)); + +/* + * Stdio function-access interface. + */ + +#ifndef __STRICT_ANSI__ +# ifdef __LARGE64_FILES +FILE *_EXFUN(funopen,(const _PTR __cookie, + int (*__readfn)(_PTR __c, char *__buf, + _READ_WRITE_BUFSIZE_TYPE __n), + int (*__writefn)(_PTR __c, const char *__buf, + _READ_WRITE_BUFSIZE_TYPE __n), + _fpos64_t (*__seekfn)(_PTR __c, _fpos64_t __off, int __whence), + int (*__closefn)(_PTR __c))); +FILE *_EXFUN(_funopen_r,(struct _reent *, const _PTR __cookie, + int (*__readfn)(_PTR __c, char *__buf, + _READ_WRITE_BUFSIZE_TYPE __n), + int (*__writefn)(_PTR __c, const char *__buf, + _READ_WRITE_BUFSIZE_TYPE __n), + _fpos64_t (*__seekfn)(_PTR __c, _fpos64_t __off, int __whence), + int (*__closefn)(_PTR __c))); +# else +FILE *_EXFUN(funopen,(const _PTR __cookie, + int (*__readfn)(_PTR __cookie, char *__buf, + _READ_WRITE_BUFSIZE_TYPE __n), + int (*__writefn)(_PTR __cookie, const char *__buf, + _READ_WRITE_BUFSIZE_TYPE __n), + fpos_t (*__seekfn)(_PTR __cookie, fpos_t __off, int __whence), + int (*__closefn)(_PTR __cookie))); +FILE *_EXFUN(_funopen_r,(struct _reent *, const _PTR __cookie, + int (*__readfn)(_PTR __cookie, char *__buf, + _READ_WRITE_BUFSIZE_TYPE __n), + int (*__writefn)(_PTR __cookie, const char *__buf, + _READ_WRITE_BUFSIZE_TYPE __n), + fpos_t (*__seekfn)(_PTR __cookie, fpos_t __off, int __whence), + int (*__closefn)(_PTR __cookie))); +# endif /* !__LARGE64_FILES */ + +# define fropen(__cookie, __fn) funopen(__cookie, __fn, (int (*)())0, \ + (fpos_t (*)())0, (int (*)())0) +# define fwopen(__cookie, __fn) funopen(__cookie, (int (*)())0, __fn, \ + (fpos_t (*)())0, (int (*)())0) + +typedef ssize_t cookie_read_function_t(void *__cookie, char *__buf, size_t __n); +typedef ssize_t cookie_write_function_t(void *__cookie, const char *__buf, + size_t __n); +# ifdef __LARGE64_FILES +typedef int cookie_seek_function_t(void *__cookie, _off64_t *__off, + int __whence); +# else +typedef int cookie_seek_function_t(void *__cookie, off_t *__off, int __whence); +# endif /* !__LARGE64_FILES */ +typedef int cookie_close_function_t(void *__cookie); +typedef struct +{ + /* These four struct member names are dictated by Linux; hopefully, + they don't conflict with any macros. */ + cookie_read_function_t *read; + cookie_write_function_t *write; + cookie_seek_function_t *seek; + cookie_close_function_t *close; +} cookie_io_functions_t; +FILE *_EXFUN(fopencookie,(void *__cookie, + const char *__mode, cookie_io_functions_t __functions)); +FILE *_EXFUN(_fopencookie_r,(struct _reent *, void *__cookie, + const char *__mode, cookie_io_functions_t __functions)); +#endif /* ! __STRICT_ANSI__ */ + +#ifndef __CUSTOM_FILE_IO__ +/* + * The __sfoo macros are here so that we can + * define function versions in the C library. + */ +#define __sgetc_raw_r(__ptr, __f) (--(__f)->_r < 0 ? __srget_r(__ptr, __f) : (int)(*(__f)->_p++)) + +#ifdef __SCLE +/* For a platform with CR/LF, additional logic is required by + __sgetc_r which would otherwise simply be a macro; therefore we + use an inlined function. The function is only meant to be inlined + in place as used and the function body should never be emitted. + + There are two possible means to this end when compiling with GCC, + one when compiling with a standard C99 compiler, and for other + compilers we're just stuck. At the moment, this issue only + affects the Cygwin target, so we'll most likely be using GCC. */ + +_ELIDABLE_INLINE int __sgetc_r(struct _reent *__ptr, FILE *__p); + +_ELIDABLE_INLINE int __sgetc_r(struct _reent *__ptr, FILE *__p) + { + int __c = __sgetc_raw_r(__ptr, __p); + if ((__p->_flags & __SCLE) && (__c == '\r')) + { + int __c2 = __sgetc_raw_r(__ptr, __p); + if (__c2 == '\n') + __c = __c2; + else + ungetc(__c2, __p); + } + return __c; + } +#else +#define __sgetc_r(__ptr, __p) __sgetc_raw_r(__ptr, __p) +#endif + +#ifdef _never /* __GNUC__ */ +/* If this inline is actually used, then systems using coff debugging + info get hopelessly confused. 21sept93 rich@cygnus.com. */ +_ELIDABLE_INLINE int __sputc_r(struct _reent *_ptr, int _c, FILE *_p) { + if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n')) + return (*_p->_p++ = _c); + else + return (__swbuf_r(_ptr, _c, _p)); +} +#else +/* + * This has been tuned to generate reasonable code on the vax using pcc + */ +#define __sputc_raw_r(__ptr, __c, __p) \ + (--(__p)->_w < 0 ? \ + (__p)->_w >= (__p)->_lbfsize ? \ + (*(__p)->_p = (__c)), *(__p)->_p != '\n' ? \ + (int)*(__p)->_p++ : \ + __swbuf_r(__ptr, '\n', __p) : \ + __swbuf_r(__ptr, (int)(__c), __p) : \ + (*(__p)->_p = (__c), (int)*(__p)->_p++)) +#ifdef __SCLE +#define __sputc_r(__ptr, __c, __p) \ + ((((__p)->_flags & __SCLE) && ((__c) == '\n')) \ + ? __sputc_raw_r(__ptr, '\r', (__p)) : 0 , \ + __sputc_raw_r((__ptr), (__c), (__p))) +#else +#define __sputc_r(__ptr, __c, __p) __sputc_raw_r(__ptr, __c, __p) +#endif +#endif + +#define __sfeof(p) ((int)(((p)->_flags & __SEOF) != 0)) +#define __sferror(p) ((int)(((p)->_flags & __SERR) != 0)) +#define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF))) +#define __sfileno(p) ((p)->_file) + +#ifndef _REENT_SMALL +#define feof(p) __sfeof(p) +#define ferror(p) __sferror(p) +#define clearerr(p) __sclearerr(p) + +#if __BSD_VISIBLE +#define feof_unlocked(p) __sfeof(p) +#define ferror_unlocked(p) __sferror(p) +#define clearerr_unlocked(p) __sclearerr(p) +#endif /* __BSD_VISIBLE */ +#endif /* _REENT_SMALL */ + +#if 0 /*ndef __STRICT_ANSI__ - FIXME: must initialize stdio first, use fn */ +#define fileno(p) __sfileno(p) +#endif + +#ifndef __CYGWIN__ +#ifndef lint +#define getc(fp) __sgetc_r(_REENT, fp) +#define putc(x, fp) __sputc_r(_REENT, x, fp) +#endif /* lint */ +#endif /* __CYGWIN__ */ + +#ifndef __STRICT_ANSI__ +/* fast always-buffered version, true iff error */ +#define fast_putc(x,p) (--(p)->_w < 0 ? \ + __swbuf_r(_REENT, (int)(x), p) == EOF : (*(p)->_p = (x), (p)->_p++, 0)) + +#define L_cuserid 9 /* posix says it goes in stdio.h :( */ +#ifdef __CYGWIN__ +#define L_ctermid 16 +#endif +#endif + +#endif /* !__CUSTOM_FILE_IO__ */ + +#define getchar() getc(stdin) +#define putchar(x) putc(x, stdout) + +#ifndef __STRICT_ANSI__ +#define getchar_unlocked() getc_unlocked(stdin) +#define putchar_unlocked(x) putc_unlocked(x, stdout) +#endif + +_END_STD_C + +#undef putchar +#undef getchar + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* STDIO_H */ diff --git a/cpu/esp8266/include/sys/_intsup.h b/cpu/esp8266/include/sys/_intsup.h deleted file mode 100644 index ac1b174756d9..000000000000 --- a/cpu/esp8266/include/sys/_intsup.h +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) 2004, 2005 by - * Ralf Corsepius, Ulm/Germany. All rights reserved. - * - * Permission to use, copy, modify, and distribute this software - * is freely granted, provided that this notice is preserved. - */ - -/** - * @brief Modified _intsup.h for compilation with RIOT OS - * Source: /path/to/newlib-xtensa/xtensa-lx106-elf/include/sys - * Changes: __INT32 (see below) - */ - -#ifndef SYS__INTSUP_H -#define SYS__INTSUP_H - -#ifndef DOXYGEN - -#ifdef __cplusplus -extern "C" { -#endif - -/* additional header guard to avoid conflicts if original file is included later */ -#ifndef _SYS__INTSUP_H -#define _SYS__INTSUP_H - -#include - -#if __GNUC_PREREQ (3, 2) -/* gcc > 3.2 implicitly defines the values we are interested */ -#define __STDINT_EXP(x) __##x##__ -#else -#define __STDINT_EXP(x) x -#include -#endif - -/* Determine how intptr_t and intN_t fastN_t and leastN_t are defined by gcc - for this target. This is used to determine the correct printf() constant in - inttypes.h and other constants in stdint.h. - So we end up with - ?(signed|unsigned) char == 0 - ?(signed|unsigned) short == 1 - ?(signed|unsigned) int == 2 - ?(signed|unsigned) short int == 3 - ?(signed|unsigned) long == 4 - ?(signed|unsigned) long int == 6 - ?(signed|unsigned) long long == 8 - ?(signed|unsigned) long long int == 10 - */ -#pragma push_macro("signed") -#pragma push_macro("unsigned") -#pragma push_macro("char") -#pragma push_macro("short") -#pragma push_macro("__int20") -#pragma push_macro("int") -#pragma push_macro("long") -#undef signed -#undef unsigned -#undef char -#undef short -#undef int -#undef __int20 -#undef long -#define signed +0 -#define unsigned +0 -#define char +0 -#define short +1 -#define __int20 +2 -#define int +2 -#define long +4 -#if (__INTPTR_TYPE__ == 8 || __INTPTR_TYPE__ == 10) -#define _INTPTR_EQ_LONGLONG -#elif (__INTPTR_TYPE__ == 4 || __INTPTR_TYPE__ == 6) -#define _INTPTR_EQ_LONG -/* Note - the tests for _INTPTR_EQ_INT and _INTPTR_EQ_SHORT are currently - redundant as the values are not used. But one day they may be needed - and so the tests remain. */ -#elif __INTPTR_TYPE__ == 2 -#define _INTPTR_EQ_INT -#elif (__INTPTR_TYPE__ == 1 || __INTPTR_TYPE__ == 3) -#define _INTPTR_EQ_SHORT -#else -#error "Unable to determine type definition of intptr_t" -#endif -#if (__INT32_TYPE__ == 4 || __INT32_TYPE__ == 6) -#define _INT32_EQ_LONG -#elif __INT32_TYPE__ == 2 -/* Nothing to define because int32_t is safe to print as an int. */ -#else -#error "Unable to determine type definition of int32_t" -#endif - -#if (__INT8_TYPE__ == 0) -#define __INT8 /* "hh" */ /* ets_printf doesn't support "h" */ -#elif (__INT8_TYPE__ == 1 || __INT8_TYPE__ == 3) -#define __INT8 /* "h" */ /* ets_printf doesn't support "h" */ -#elif (__INT8_TYPE__ == 2) -#define __INT8 -#elif (__INT8_TYPE__ == 4 || __INT8_TYPE__ == 6) -#define __INT8 "l" -#elif (__INT8_TYPE__ == 8 || __INT8_TYPE__ == 10) -#define __INT8 "ll" -#endif -#if (__INT16_TYPE__ == 1 || __INT16_TYPE__ == 3) -#define __INT16 /* "h" */ /* ets_printf doesn't support "h" */ -#elif (__INT16_TYPE__ == 2) -#define __INT16 -#elif (__INT16_TYPE__ == 4 || __INT16_TYPE__ == 6) -#define __INT16 "l" -#elif (__INT16_TYPE__ == 8 || __INT16_TYPE__ == 10) -#define __INT16 "ll" -#endif -#if (__INT32_TYPE__ == 2) -#define __INT32 -#elif (__INT32_TYPE__ == 4 || __INT32_TYPE__ == 6) -/** - * Definition of __INT32 had to be changed since to avoid format warnings/ - * errors since xtensa-lx106-elf-gcc defines *__INT32_TYPE__* as *long int* - * while newlib defines *int32_t* as *signed int*. PRI*32 there throw format - * warnings/errors. - */ -#if 0 -#define __INT32 "l" -#else -#define __INT32 -#endif -#elif (__INT32_TYPE__ == 8 || __INT32_TYPE__ == 10) -#define __INT32 "ll" -#endif -#if (__INT64_TYPE__ == 2) -#define __INT64 -#elif (__INT64_TYPE__ == 4 || __INT64_TYPE__ == 6) -#define __INT64 "l" -#elif (__INT64_TYPE__ == 8 || __INT64_TYPE__ == 10) -#define __INT64 "ll" -#endif -#if (__INT_FAST8_TYPE__ == 0) -#define __FAST8 /* "hh" */ /* ets_printf doesn't support "h" */ -#elif (__INT_FAST8_TYPE__ == 1 || __INT_FAST8_TYPE__ == 3) -#define __FAST8 /* "h" */ /* ets_printf doesn't support "h" */ -#elif (__INT_FAST8_TYPE__ == 2) -#define __FAST8 -#elif (__INT_FAST8_TYPE__ == 4 || __INT_FAST8_TYPE__ == 6) -#define __FAST8 "l" -#elif (__INT_FAST8_TYPE__ == 8 || __INT_FAST8_TYPE__ == 10) -#define __FAST8 "ll" -#endif -#if (__INT_FAST16_TYPE__ == 1 || __INT_FAST16_TYPE__ == 3) -#define __FAST16 /* "h" */ /* ets_printf doesn't support "h" */ -#elif (__INT_FAST16_TYPE__ == 2) -#define __FAST16 -#elif (__INT_FAST16_TYPE__ == 4 || __INT_FAST16_TYPE__ == 6) -#define __FAST16 "l" -#elif (__INT_FAST16_TYPE__ == 8 || __INT_FAST16_TYPE__ == 10) -#define __FAST16 "ll" -#endif -#if (__INT_FAST32_TYPE__ == 2) -#define __FAST32 -#elif (__INT_FAST32_TYPE__ == 4 || __INT_FAST32_TYPE__ == 6) -#define __FAST32 "l" -#elif (__INT_FAST32_TYPE__ == 8 || __INT_FAST32_TYPE__ == 10) -#define __FAST32 "ll" -#endif -#if (__INT_FAST64_TYPE__ == 2) -#define __FAST64 -#elif (__INT_FAST64_TYPE__ == 4 || __INT_FAST64_TYPE__ == 6) -#define __FAST64 "l" -#elif (__INT_FAST64_TYPE__ == 8 || __INT_FAST64_TYPE__ == 10) -#define __FAST64 "ll" -#endif - -#if (__INT_LEAST8_TYPE__ == 0) -#define __LEAST8 /* "hh" */ /* ets_printf doesn't support "h" */ -#elif (__INT_LEAST8_TYPE__ == 1 || __INT_LEAST8_TYPE__ == 3) -#define __LEAST8 /* "h" */ /* ets_printf doesn't support "h" */ -#elif (__INT_LEAST8_TYPE__ == 2) -#define __LEAST8 -#elif (__INT_LEAST8_TYPE__ == 4 || __INT_LEAST8_TYPE__ == 6) -#define __LEAST8 "l" -#elif (__INT_LEAST8_TYPE__ == 8 || __INT_LEAST8_TYPE__ == 10) -#define __LEAST8 "ll" -#endif -#if (__INT_LEAST16_TYPE__ == 1 || __INT_LEAST16_TYPE__ == 3) -#define __LEAST16 /* "h" */ /* ets_printf doesn't support "h" */ -#elif (__INT_LEAST16_TYPE__ == 2) -#define __LEAST16 -#elif (__INT_LEAST16_TYPE__ == 4 || __INT_LEAST16_TYPE__ == 6) -#define __LEAST16 "l" -#elif (__INT_LEAST16_TYPE__ == 8 || __INT_LEAST16_TYPE__ == 10) -#define __LEAST16 "ll" -#endif -#if (__INT_LEAST32_TYPE__ == 2) -#define __LEAST32 -#elif (__INT_LEAST32_TYPE__ == 4 || __INT_LEAST32_TYPE__ == 6) -#define __LEAST32 "l" -#elif (__INT_LEAST32_TYPE__ == 8 || __INT_LEAST32_TYPE__ == 10) -#define __LEAST32 "ll" -#endif -#if (__INT_LEAST64_TYPE__ == 2) -#define __LEAST64 -#elif (__INT_LEAST64_TYPE__ == 4 || __INT_LEAST64_TYPE__ == 6) -#define __LEAST64 "l" -#elif (__INT_LEAST64_TYPE__ == 8 || __INT_LEAST64_TYPE__ == 10) -#define __LEAST64 "ll" -#endif -#undef signed -#undef unsigned -#undef char -#undef short -#undef int -#undef long -#pragma pop_macro("signed") -#pragma pop_macro("unsigned") -#pragma pop_macro("char") -#pragma pop_macro("short") -#pragma pop_macro("__int20") -#pragma pop_macro("int") -#pragma pop_macro("long") - -#endif /* _SYS__INTSUP_H */ - -#ifdef __cplusplus -} -#endif - -#endif /* DOXYGEN */ -#endif /* SYS__INTSUP_H */ diff --git a/cpu/esp8266/include/sys/types.h b/cpu/esp8266/include/sys/types.h new file mode 100644 index 000000000000..0c24654342e6 --- /dev/null +++ b/cpu/esp8266/include/sys/types.h @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_esp8266 + * @{ + * + * @file + * @brief This file is a modification of original sys/types.h + * + * @author Gunar Schorcht + * + * This file is just a wrapper around sys/types.h to fix missing types + * fsblkcnt_t and fsfilcnt_t needed in statvfs.h and to avoid type conflicts + * with pthread types from pthread module. + */ + + +/* unified sys/types.h: + start with sef's sysvi386 version. + merge go32 version -- a few ifdefs. + h8300hms, h8300xray, and sysvnecv70 disagree on the following types: + + typedef int gid_t; + typedef int uid_t; + typedef int dev_t; + typedef int ino_t; + typedef int mode_t; + typedef int caddr_t; + + however, these aren't "reasonable" values, the sysvi386 ones make far + more sense, and should work sufficiently well (in particular, h8300 + doesn't have a stat, and the necv70 doesn't matter.) -- eichin + */ + +#ifndef SYS_TYPES_H +#define SYS_TYPES_H + +#ifndef DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _FSBLKCNT_T_DECLARED +#include +typedef uint32_t fsblkcnt_t; +typedef uint32_t fsfilcnt_t; +#define _FSBLKCNT_T_DECLARED +#endif + +#ifndef _SYS_TYPES_H + +#include <_ansi.h> + +#ifndef __INTTYPES_DEFINED__ +#define __INTTYPES_DEFINED__ + +#include + +#if defined(__rtems__) || defined(__XMK__) +/* + * The following section is RTEMS specific and is needed to more + * closely match the types defined in the BSD sys/types.h. + * This is needed to let the RTEMS/BSD TCP/IP stack compile. + */ + +/* deprecated */ +#if ___int8_t_defined +typedef __uint8_t u_int8_t; +#endif +#if ___int16_t_defined +typedef __uint16_t u_int16_t; +#endif +#if ___int32_t_defined +typedef __uint32_t u_int32_t; +#endif + +#if ___int64_t_defined +typedef __uint64_t u_int64_t; + +/* deprecated */ +typedef __uint64_t u_quad_t; +typedef __int64_t quad_t; +typedef quad_t * qaddr_t; +#endif + +#endif + +#endif /* ! __INTTYPES_DEFINED */ + +#ifndef __need_inttypes + +#define _SYS_TYPES_H +#include + +#ifdef __i386__ +#if defined (GO32) || defined (__MSDOS__) +#define __MS_types__ +#endif +#endif + +# include +# include + +/* To ensure the stat struct's layout doesn't change when sizeof(int), etc. + changes, we assume sizeof short and long never change and have all types + used to define struct stat use them and not int where possible. + Where not possible, _ST_INTxx are used. It would be preferable to not have + such assumptions, but until the extra fluff is necessary, it's avoided. + No 64 bit targets use stat yet. What to do about them is postponed + until necessary. */ +#ifdef __GNUC__ +#define _ST_INT32 __attribute__ ((__mode__ (__SI__))) +#else +#define _ST_INT32 +#endif + +# ifndef _POSIX_SOURCE + +# define physadr physadr_t +# define quad quad_t + +#ifndef _BSDTYPES_DEFINED +/* also defined in mingw/gmon.h and in w32api/winsock[2].h */ +#ifndef __u_char_defined +typedef unsigned char u_char; +#define __u_char_defined +#endif +#ifndef __u_short_defined +typedef unsigned short u_short; +#define __u_short_defined +#endif +#ifndef __u_int_defined +typedef unsigned int u_int; +#define __u_int_defined +#endif +#ifndef __u_long_defined +typedef unsigned long u_long; +#define __u_long_defined +#endif +#define _BSDTYPES_DEFINED +#endif + +typedef unsigned short ushort; /* System V compatibility */ +typedef unsigned int uint; /* System V compatibility */ +typedef unsigned long ulong; /* System V compatibility */ +# endif /*!_POSIX_SOURCE */ + +#ifndef __clock_t_defined +typedef _CLOCK_T_ clock_t; +#define __clock_t_defined +#endif + +#ifndef __time_t_defined +typedef _TIME_T_ time_t; +#define __time_t_defined +#endif + +#ifndef __timespec_defined +#define __timespec_defined +/* Time Value Specification Structures, P1003.1b-1993, p. 261 */ + +struct timespec { + time_t tv_sec; /* Seconds */ + long tv_nsec; /* Nanoseconds */ +}; +#endif + +struct itimerspec { + struct timespec it_interval; /* Timer period */ + struct timespec it_value; /* Timer expiration */ +}; + +#ifndef __daddr_t_defined +typedef long daddr_t; +#define __daddr_t_defined +#endif +#ifndef __caddr_t_defined +typedef char * caddr_t; +#define __caddr_t_defined +#endif + +#ifndef __CYGWIN__ +#if defined(__MS_types__) || defined(__rtems__) || \ + defined(__sparc__) || defined(__SPU__) +typedef unsigned long ino_t; +#else +typedef unsigned short ino_t; +#endif +#endif /*__CYGWIN__*/ + +#ifdef __MS_types__ +typedef unsigned long vm_offset_t; +typedef unsigned long vm_size_t; + +#define __BIT_TYPES_DEFINED__ + +typedef signed char int8_t; +typedef unsigned char u_int8_t; +typedef short int16_t; +typedef unsigned short u_int16_t; +typedef int int32_t; +typedef unsigned int u_int32_t; +typedef long long int64_t; +typedef unsigned long long u_int64_t; +typedef int32_t register_t; +#endif /* __MS_types__ */ + +/* + * All these should be machine specific - right now they are all broken. + * However, for all of Cygnus' embedded targets, we want them to all be + * the same. Otherwise things like sizeof (struct stat) might depend on + * how the file was compiled (e.g. -mint16 vs -mint32, etc.). + */ + +#ifndef __CYGWIN__ /* which defines these types in it's own types.h. */ +typedef _off_t off_t; +typedef __dev_t dev_t; +typedef __uid_t uid_t; +typedef __gid_t gid_t; +#endif + +#if defined(__XMK__) +typedef signed char pid_t; +#else +typedef int pid_t; +#endif + +#if defined(__rtems__) +typedef _mode_t mode_t; +#endif + +#ifndef __CYGWIN__ +typedef long key_t; +#endif +typedef _ssize_t ssize_t; + +#if !defined(__CYGWIN__) && !defined(__rtems__) +#ifdef __MS_types__ +typedef char * addr_t; +typedef int mode_t; +#else +#if defined (__sparc__) && !defined (__sparc_v9__) +#ifdef __svr4__ +typedef unsigned long mode_t; +#else +typedef unsigned short mode_t; +#endif +#else +typedef unsigned int mode_t _ST_INT32; +#endif +#endif /* ! __MS_types__ */ +#endif /*__CYGWIN__*/ + +typedef unsigned short nlink_t; + +/* We don't define fd_set and friends if we are compiling POSIX + source, or if we have included (or may include as indicated + by __USE_W32_SOCKETS) the W32api winsock[2].h header which + defines Windows versions of them. Note that a program which + includes the W32api winsock[2].h header must know what it is doing; + it must not call the cygwin32 select function. +*/ +# if !(defined (_POSIX_SOURCE) || defined (_WINSOCK_H) || defined (_WINSOCKAPI_) || defined (__USE_W32_SOCKETS)) +# define _SYS_TYPES_FD_SET +# define NBBY 8 /* number of bits in a byte */ +/* + * Select uses bit masks of file descriptors in longs. + * These macros manipulate such bit fields (the filesystem macros use chars). + * FD_SETSIZE may be defined by the user, but the default here + * should be >= NOFILE (param.h). + */ +# ifndef FD_SETSIZE +# define FD_SETSIZE 64 +# endif + +typedef long fd_mask; +# define NFDBITS (sizeof (fd_mask) * NBBY) /* bits per mask */ +# ifndef howmany +# define howmany(x,y) (((x)+((y)-1))/(y)) +# endif + +/* We use a macro for fd_set so that including Sockets.h afterwards + can work. */ +typedef struct _types_fd_set { + fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)]; +} _types_fd_set; + +#define fd_set _types_fd_set + +# define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1L << ((n) % NFDBITS))) +# define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1L << ((n) % NFDBITS))) +# define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1L << ((n) % NFDBITS))) +# define FD_ZERO(p) (__extension__ (void)({ \ + size_t __i; \ + char *__tmp = (char *)p; \ + for (__i = 0; __i < sizeof (*(p)); ++__i) \ + *__tmp++ = 0; \ +})) + +# endif /* !(defined (_POSIX_SOURCE) || defined (_WINSOCK_H) || defined (_WINSOCKAPI_) || defined (__USE_W32_SOCKETS)) */ + +#undef __MS_types__ +#undef _ST_INT32 + + +#ifndef __clockid_t_defined +typedef _CLOCKID_T_ clockid_t; +#define __clockid_t_defined +#endif + +#ifndef __timer_t_defined +typedef _TIMER_T_ timer_t; +#define __timer_t_defined +#endif + +typedef unsigned long useconds_t; +typedef long suseconds_t; + +#endif /* !__need_inttypes */ + +#undef __need_inttypes + +#endif /* _SYS_TYPES_H */ + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* SYS_TYPES_H */ diff --git a/cpu/esp8266/include/syscalls.h b/cpu/esp8266/include/syscalls.h index cf5249f58a77..21185ec36e1b 100644 --- a/cpu/esp8266/include/syscalls.h +++ b/cpu/esp8266/include/syscalls.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -23,6 +23,7 @@ #include #include +#include #include #ifdef __cplusplus @@ -35,12 +36,24 @@ extern void syscalls_init (void); /** System standard printf function */ extern int printf(const char* format, ...); +/** Determine free heap size */ +unsigned int get_free_heap_size (void); + /** System standard puts function */ extern int puts(const char * str); /** Determine free heap size */ extern unsigned int get_free_heap_size (void); +/** Time since boot in us (32bit version) */ +uint32_t system_get_time (void); + +/** Time since boot in ms (32bit version) */ +uint32_t system_get_time_ms (void); + +/** memset version that the compiler should not be allowed to optimize this */ +void *system_secure_memset(void *s, int c, size_t n); + #ifdef __cplusplus } #endif diff --git a/cpu/esp8266/include/thread_arch.h b/cpu/esp8266/include/thread_arch.h index b525a6d94cb6..b4b585c67d2a 100644 --- a/cpu/esp8266/include/thread_arch.h +++ b/cpu/esp8266/include/thread_arch.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level diff --git a/cpu/esp8266/include/tools.h b/cpu/esp8266/include/tools.h index f2de39969aff..f6dc065b0e18 100644 --- a/cpu/esp8266/include/tools.h +++ b/cpu/esp8266/include/tools.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level diff --git a/cpu/esp8266/include/user_config.h b/cpu/esp8266/include/user_config.h deleted file mode 100644 index 94825891a0b0..000000000000 --- a/cpu/esp8266/include/user_config.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2018 Gunar Schorcht - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ -/** - * @ingroup cpu_esp8266 - * @brief Default configurations required by the SDK - * @author Gunar Schorcht - * @file - * @{ - */ - -#ifndef USER_CONFIG_H -#define USER_CONFIG_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Default CPU frequency in MHz. - * Possible values are 80 and 160. - */ -#ifndef ESP8266_CPU_FREQUENCY -#define ESP8266_CPU_FREQUENCY 80 -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* USER_CONFIG_H */ -/** @} */ diff --git a/cpu/esp8266/include/xtensa_conf.h b/cpu/esp8266/include/xtensa_conf.h index f6a9c7a7922a..594d810bf379 100644 --- a/cpu/esp8266/include/xtensa_conf.h +++ b/cpu/esp8266/include/xtensa_conf.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level diff --git a/cpu/esp8266/irq_arch.c b/cpu/esp8266/irq_arch.c index a7563b5d54a9..c5f902cd997d 100644 --- a/cpu/esp8266/irq_arch.c +++ b/cpu/esp8266/irq_arch.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -18,7 +18,7 @@ * @} */ -#define ENABLE_DEBUG 0 +#define ENABLE_DEBUG (0) #include "debug.h" #include @@ -27,10 +27,9 @@ #include "irq.h" #include "cpu.h" -#include "common.h" +#include "esp_common.h" #include "esp/common_macros.h" #include "esp/xtensa_ops.h" -#include "sdk/ets.h" #include "xtensa/xtensa_context.h" /** @@ -46,9 +45,9 @@ unsigned int IRAM irq_disable(void) uint32_t _saved_interrupt_level; /* read and set interrupt level (RSIL) */ - __asm__ volatile ("rsil %0, " XTSTR(XCHAL_NUM_INTLEVELS+1) : "=a" (_saved_interrupt_level)); + __asm__ volatile ("rsil %0, " XTSTR(XCHAL_EXCM_LEVEL) : "=a" (_saved_interrupt_level)); DEBUG ("%s %02x(%02x)\n", __func__, - (_saved_interrupt_level & 0xfffffff0) | (XCHAL_NUM_INTLEVELS+1), + (_saved_interrupt_level & 0xfffffff0) | (XCHAL_EXCM_LEVEL), _saved_interrupt_level); return _saved_interrupt_level; } @@ -62,7 +61,7 @@ unsigned int IRAM irq_enable(void) /* read and set interrupt level (RSIL) */ __asm__ volatile ("rsil %0, 0" : "=a" (_saved_interrupt_level)); - DEBUG ("%s %02x(%02x)\n", __func__, + DEBUG ("%s %02x (%02x)\n", __func__, _saved_interrupt_level & 0xfffffff0, _saved_interrupt_level); return _saved_interrupt_level; } diff --git a/cpu/esp8266/ld/eagle.rom.addr.v6.ld b/cpu/esp8266/ld/eagle.rom.addr.v6.ld deleted file mode 100644 index 282acfe168e2..000000000000 --- a/cpu/esp8266/ld/eagle.rom.addr.v6.ld +++ /dev/null @@ -1,350 +0,0 @@ -PROVIDE ( Cache_Read_Disable = 0x400047f0 ); -PROVIDE ( Cache_Read_Enable = 0x40004678 ); -PROVIDE ( FilePacketSendReqMsgProc = 0x400035a0 ); -PROVIDE ( FlashDwnLdParamCfgMsgProc = 0x4000368c ); -PROVIDE ( FlashDwnLdStartMsgProc = 0x40003538 ); -PROVIDE ( FlashDwnLdStopReqMsgProc = 0x40003658 ); -PROVIDE ( GetUartDevice = 0x40003f4c ); -PROVIDE ( MD5Final = 0x40009900 ); -PROVIDE ( MD5Init = 0x40009818 ); -PROVIDE ( MD5Update = 0x40009834 ); -PROVIDE ( MemDwnLdStartMsgProc = 0x400036c4 ); -PROVIDE ( MemDwnLdStopReqMsgProc = 0x4000377c ); -PROVIDE ( MemPacketSendReqMsgProc = 0x400036f0 ); -PROVIDE ( RcvMsg = 0x40003eac ); -PROVIDE ( SHA1Final = 0x4000b648 ); -PROVIDE ( SHA1Init = 0x4000b584 ); -PROVIDE ( SHA1Transform = 0x4000a364 ); -PROVIDE ( SHA1Update = 0x4000b5a8 ); -PROVIDE ( SPI_read_status = 0x400043c8 ); -PROVIDE ( SPI_write_status = 0x40004400 ); -PROVIDE ( SPI_write_enable = 0x4000443c ); -PROVIDE ( Wait_SPI_Idle = 0x4000448c ); -PROVIDE ( Enable_QMode = 0x400044c0 ); -PROVIDE ( SPIEraseArea = 0x40004b44 ); -PROVIDE ( SPIEraseBlock = 0x400049b4 ); -PROVIDE ( SPIEraseChip = 0x40004984 ); -PROVIDE ( SPIEraseSector = 0x40004a00 ); -PROVIDE ( SPILock = 0x400048a8 ); -PROVIDE ( SPIParamCfg = 0x40004c2c ); -PROVIDE ( SPIRead = 0x40004b1c ); -PROVIDE ( SPIReadModeCnfig = 0x400048ec ); -PROVIDE ( SPIUnlock = 0x40004878 ); -PROVIDE ( SPIWrite = 0x40004a4c ); -PROVIDE ( SelectSpiFunction = 0x40003f58 ); -PROVIDE ( SendMsg = 0x40003cf4 ); -PROVIDE ( UartConnCheck = 0x40003230 ); -PROVIDE ( UartConnectProc = 0x400037a0 ); -PROVIDE ( UartDwnLdProc = 0x40003368 ); -PROVIDE ( UartGetCmdLn = 0x40003ef4 ); -PROVIDE ( UartRegReadProc = 0x4000381c ); -PROVIDE ( UartRegWriteProc = 0x400037ac ); -PROVIDE ( UartRxString = 0x40003c30 ); -PROVIDE ( Uart_Init = 0x40003a14 ); -PROVIDE ( _DebugExceptionVector = 0x40000010 ); -PROVIDE ( _DoubleExceptionVector = 0x40000070 ); -PROVIDE ( _KernelExceptionVector = 0x40000030 ); -PROVIDE ( _NMIExceptionVector = 0x40000020 ); -PROVIDE ( _ResetHandler = 0x400000a4 ); -PROVIDE ( _ResetVector = 0x40000080 ); -PROVIDE ( _UserExceptionVector = 0x40000050 ); -PROVIDE ( __adddf3 = 0x4000c538 ); -PROVIDE ( __addsf3 = 0x4000c180 ); -PROVIDE ( __divdf3 = 0x4000cb94 ); -PROVIDE ( __divdi3 = 0x4000ce60 ); -PROVIDE ( __divsi3 = 0x4000dc88 ); -PROVIDE ( __extendsfdf2 = 0x4000cdfc ); -PROVIDE ( __fixdfsi = 0x4000ccb8 ); -PROVIDE ( __fixunsdfsi = 0x4000cd00 ); -PROVIDE ( __fixunssfsi = 0x4000c4c4 ); -PROVIDE ( __floatsidf = 0x4000e2f0 ); -PROVIDE ( __floatsisf = 0x4000e2ac ); -PROVIDE ( __floatunsidf = 0x4000e2e8 ); -PROVIDE ( __floatunsisf = 0x4000e2a4 ); -PROVIDE ( __muldf3 = 0x4000c8f0 ); -PROVIDE ( __muldi3 = 0x40000650 ); -PROVIDE ( __mulsf3 = 0x4000c3dc ); -PROVIDE ( __subdf3 = 0x4000c688 ); -PROVIDE ( __subsf3 = 0x4000c268 ); -PROVIDE ( __truncdfsf2 = 0x4000cd5c ); -PROVIDE ( __udivdi3 = 0x4000d310 ); -PROVIDE ( __udivsi3 = 0x4000e21c ); -PROVIDE ( __umoddi3 = 0x4000d770 ); -PROVIDE ( __umodsi3 = 0x4000e268 ); -PROVIDE ( __umulsidi3 = 0x4000dcf0 ); -PROVIDE ( _rom_store = 0x4000e388 ); -PROVIDE ( _rom_store_table = 0x4000e328 ); -PROVIDE ( _start = 0x4000042c ); -PROVIDE ( _xtos_alloca_handler = 0x4000dbe0 ); -PROVIDE ( _xtos_c_wrapper_handler = 0x40000598 ); -PROVIDE ( _xtos_cause3_handler = 0x40000590 ); -PROVIDE ( _xtos_ints_off = 0x4000bda4 ); -PROVIDE ( _xtos_ints_on = 0x4000bd84 ); -PROVIDE ( _xtos_l1int_handler = 0x4000048c ); -PROVIDE ( _xtos_p_none = 0x4000dbf8 ); -PROVIDE ( _xtos_restore_intlevel = 0x4000056c ); -PROVIDE ( _xtos_return_from_exc = 0x4000dc54 ); -PROVIDE ( _xtos_set_exception_handler = 0x40000454 ); -PROVIDE ( _xtos_set_interrupt_handler = 0x4000bd70 ); -PROVIDE ( _xtos_set_interrupt_handler_arg = 0x4000bd28 ); -PROVIDE ( _xtos_set_intlevel = 0x4000dbfc ); -PROVIDE ( _xtos_set_min_intlevel = 0x4000dc18 ); -PROVIDE ( _xtos_set_vpri = 0x40000574 ); -PROVIDE ( _xtos_syscall_handler = 0x4000dbe4 ); -PROVIDE ( _xtos_unhandled_exception = 0x4000dc44 ); -PROVIDE ( _xtos_unhandled_interrupt = 0x4000dc3c ); -PROVIDE ( aes_decrypt = 0x400092d4 ); -PROVIDE ( aes_decrypt_deinit = 0x400092e4 ); -PROVIDE ( aes_decrypt_init = 0x40008ea4 ); -PROVIDE ( aes_unwrap = 0x40009410 ); -PROVIDE ( base64_decode = 0x40009648 ); -PROVIDE ( base64_encode = 0x400094fc ); -PROVIDE ( bzero = 0x4000de84 ); -PROVIDE ( cmd_parse = 0x40000814 ); -PROVIDE ( conv_str_decimal = 0x40000b24 ); -PROVIDE ( conv_str_hex = 0x40000cb8 ); -PROVIDE ( convert_para_str = 0x40000a60 ); -PROVIDE ( dtm_get_intr_mask = 0x400026d0 ); -PROVIDE ( dtm_params_init = 0x4000269c ); -PROVIDE ( dtm_set_intr_mask = 0x400026c8 ); -PROVIDE ( dtm_set_params = 0x400026dc ); -PROVIDE ( eprintf = 0x40001d14 ); -PROVIDE ( eprintf_init_buf = 0x40001cb8 ); -PROVIDE ( eprintf_to_host = 0x40001d48 ); -PROVIDE ( est_get_printf_buf_remain_len = 0x40002494 ); -PROVIDE ( est_reset_printf_buf_len = 0x4000249c ); -PROVIDE ( ets_bzero = 0x40002ae8 ); -PROVIDE ( ets_char2xdigit = 0x40002b74 ); -PROVIDE ( ets_delay_us = 0x40002ecc ); -PROVIDE ( ets_enter_sleep = 0x400027b8 ); -PROVIDE ( ets_external_printf = 0x40002578 ); -PROVIDE ( ets_get_cpu_frequency = 0x40002f0c ); -PROVIDE ( ets_getc = 0x40002bcc ); -PROVIDE ( ets_install_external_printf = 0x40002450 ); -PROVIDE ( ets_install_putc1 = 0x4000242c ); -PROVIDE ( ets_install_putc2 = 0x4000248c ); -PROVIDE ( ets_install_uart_printf = 0x40002438 ); -PROVIDE ( ets_intr_lock = 0x40000f74 ); -PROVIDE ( ets_intr_unlock = 0x40000f80 ); -PROVIDE ( ets_isr_attach = 0x40000f88 ); -PROVIDE ( ets_isr_mask = 0x40000f98 ); -PROVIDE ( ets_isr_unmask = 0x40000fa8 ); -PROVIDE ( ets_memcmp = 0x400018d4 ); -PROVIDE ( ets_memcpy = 0x400018b4 ); -PROVIDE ( ets_memmove = 0x400018c4 ); -PROVIDE ( ets_memset = 0x400018a4 ); -PROVIDE ( ets_post = 0x40000e24 ); -PROVIDE ( ets_printf = 0x400024cc ); -PROVIDE ( ets_putc = 0x40002be8 ); -PROVIDE ( ets_rtc_int_register = 0x40002a40 ); -PROVIDE ( ets_run = 0x40000e04 ); -PROVIDE ( ets_set_idle_cb = 0x40000dc0 ); -PROVIDE ( ets_set_user_start = 0x40000fbc ); -PROVIDE ( ets_str2macaddr = 0x40002af8 ); -PROVIDE ( ets_strcmp = 0x40002aa8 ); -PROVIDE ( ets_strcpy = 0x40002a88 ); -PROVIDE ( ets_strlen = 0x40002ac8 ); -PROVIDE ( ets_strncmp = 0x40002ab8 ); -PROVIDE ( ets_strncpy = 0x40002a98 ); -PROVIDE ( ets_strstr = 0x40002ad8 ); -PROVIDE ( ets_task = 0x40000dd0 ); -PROVIDE ( ets_timer_arm = 0x40002cc4 ); -PROVIDE ( ets_timer_disarm = 0x40002d40 ); -PROVIDE ( ets_timer_done = 0x40002d80 ); -PROVIDE ( ets_timer_handler_isr = 0x40002da8 ); -PROVIDE ( ets_timer_init = 0x40002e68 ); -PROVIDE ( ets_timer_setfn = 0x40002c48 ); -PROVIDE ( ets_uart_printf = 0x40002544 ); -PROVIDE ( ets_update_cpu_frequency = 0x40002f04 ); -PROVIDE ( ets_vprintf = 0x40001f00 ); -PROVIDE ( ets_wdt_disable = 0x400030f0 ); -PROVIDE ( ets_wdt_enable = 0x40002fa0 ); -PROVIDE ( ets_wdt_get_mode = 0x40002f34 ); -PROVIDE ( ets_wdt_init = 0x40003170 ); -PROVIDE ( ets_wdt_restore = 0x40003158 ); -PROVIDE ( ets_write_char = 0x40001da0 ); -PROVIDE ( get_first_seg = 0x4000091c ); -PROVIDE ( gpio_init = 0x40004c50 ); -PROVIDE ( gpio_input_get = 0x40004cf0 ); -PROVIDE ( gpio_intr_ack = 0x40004dcc ); -PROVIDE ( gpio_intr_handler_register = 0x40004e28 ); -PROVIDE ( gpio_intr_pending = 0x40004d88 ); -PROVIDE ( gpio_intr_test = 0x40004efc ); -PROVIDE ( gpio_output_set = 0x40004cd0 ); -PROVIDE ( gpio_pin_intr_state_set = 0x40004d90 ); -PROVIDE ( gpio_pin_wakeup_disable = 0x40004ed4 ); -PROVIDE ( gpio_pin_wakeup_enable = 0x40004e90 ); -PROVIDE ( gpio_register_get = 0x40004d5c ); -PROVIDE ( gpio_register_set = 0x40004d04 ); -PROVIDE ( hmac_md5 = 0x4000a2cc ); -PROVIDE ( hmac_md5_vector = 0x4000a160 ); -PROVIDE ( hmac_sha1 = 0x4000ba28 ); -PROVIDE ( hmac_sha1_vector = 0x4000b8b4 ); -PROVIDE ( lldesc_build_chain = 0x40004f40 ); -PROVIDE ( lldesc_num2link = 0x40005050 ); -PROVIDE ( lldesc_set_owner = 0x4000507c ); -PROVIDE ( main = 0x40000fec ); -PROVIDE ( md5_vector = 0x400097ac ); -PROVIDE ( mem_calloc = 0x40001c2c ); -PROVIDE ( mem_free = 0x400019e0 ); -PROVIDE ( mem_init = 0x40001998 ); -PROVIDE ( mem_malloc = 0x40001b40 ); -PROVIDE ( mem_realloc = 0x40001c6c ); -PROVIDE ( mem_trim = 0x40001a14 ); -PROVIDE ( mem_zalloc = 0x40001c58 ); -PROVIDE ( memcmp = 0x4000dea8 ); -PROVIDE ( memcpy = 0x4000df48 ); -PROVIDE ( memmove = 0x4000e04c ); -PROVIDE ( memset = 0x4000e190 ); -PROVIDE ( multofup = 0x400031c0 ); -PROVIDE ( pbkdf2_sha1 = 0x4000b840 ); -PROVIDE ( phy_get_romfuncs = 0x40006b08 ); -PROVIDE ( rand = 0x40000600 ); -PROVIDE ( rc4_skip = 0x4000dd68 ); -PROVIDE ( recv_packet = 0x40003d08 ); -PROVIDE ( remove_head_space = 0x40000a04 ); -PROVIDE ( rijndaelKeySetupDec = 0x40008dd0 ); -PROVIDE ( rijndaelKeySetupEnc = 0x40009300 ); -PROVIDE ( rom_abs_temp = 0x400060c0 ); -PROVIDE ( rom_ana_inf_gating_en = 0x40006b10 ); -PROVIDE ( rom_cal_tos_v50 = 0x40007a28 ); -PROVIDE ( rom_chip_50_set_channel = 0x40006f84 ); -PROVIDE ( rom_chip_v5_disable_cca = 0x400060d0 ); -PROVIDE ( rom_chip_v5_enable_cca = 0x400060ec ); -PROVIDE ( rom_chip_v5_rx_init = 0x4000711c ); -PROVIDE ( rom_chip_v5_sense_backoff = 0x4000610c ); -PROVIDE ( rom_chip_v5_tx_init = 0x4000718c ); -PROVIDE ( rom_dc_iq_est = 0x4000615c ); -PROVIDE ( rom_en_pwdet = 0x400061b8 ); -PROVIDE ( rom_get_bb_atten = 0x40006238 ); -PROVIDE ( rom_get_corr_power = 0x40006260 ); -PROVIDE ( rom_get_fm_sar_dout = 0x400062dc ); -PROVIDE ( rom_get_noisefloor = 0x40006394 ); -PROVIDE ( rom_get_power_db = 0x400063b0 ); -PROVIDE ( rom_i2c_readReg = 0x40007268 ); -PROVIDE ( rom_i2c_readReg_Mask = 0x4000729c ); -PROVIDE ( rom_i2c_writeReg = 0x400072d8 ); -PROVIDE ( rom_i2c_writeReg_Mask = 0x4000730c ); -PROVIDE ( rom_iq_est_disable = 0x40006400 ); -PROVIDE ( rom_iq_est_enable = 0x40006430 ); -PROVIDE ( rom_linear_to_db = 0x40006484 ); -PROVIDE ( rom_mhz2ieee = 0x400065a4 ); -PROVIDE ( rom_pbus_dco___SA2 = 0x40007bf0 ); -PROVIDE ( rom_pbus_debugmode = 0x4000737c ); -PROVIDE ( rom_pbus_enter_debugmode = 0x40007410 ); -PROVIDE ( rom_pbus_exit_debugmode = 0x40007448 ); -PROVIDE ( rom_pbus_force_test = 0x4000747c ); -PROVIDE ( rom_pbus_rd = 0x400074d8 ); -PROVIDE ( rom_pbus_set_rxgain = 0x4000754c ); -PROVIDE ( rom_pbus_set_txgain = 0x40007610 ); -PROVIDE ( rom_pbus_workmode = 0x40007648 ); -PROVIDE ( rom_pbus_xpd_rx_off = 0x40007688 ); -PROVIDE ( rom_pbus_xpd_rx_on = 0x400076cc ); -PROVIDE ( rom_pbus_xpd_tx_off = 0x400076fc ); -PROVIDE ( rom_pbus_xpd_tx_on = 0x40007740 ); -PROVIDE ( rom_pbus_xpd_tx_on__low_gain = 0x400077a0 ); -PROVIDE ( rom_phy_reset_req = 0x40007804 ); -PROVIDE ( rom_restart_cal = 0x4000781c ); -PROVIDE ( rom_rfcal_pwrctrl = 0x40007eb4 ); -PROVIDE ( rom_rfcal_rxiq = 0x4000804c ); -PROVIDE ( rom_rfcal_rxiq_set_reg = 0x40008264 ); -PROVIDE ( rom_rfcal_txcap = 0x40008388 ); -PROVIDE ( rom_rfcal_txiq = 0x40008610 ); -PROVIDE ( rom_rfcal_txiq_cover = 0x400088b8 ); -PROVIDE ( rom_rfcal_txiq_set_reg = 0x40008a70 ); -PROVIDE ( rom_rfpll_reset = 0x40007868 ); -PROVIDE ( rom_rfpll_set_freq = 0x40007968 ); -PROVIDE ( rom_rxiq_cover_mg_mp = 0x40008b6c ); -PROVIDE ( rom_rxiq_get_mis = 0x40006628 ); -PROVIDE ( rom_sar_init = 0x40006738 ); -PROVIDE ( rom_set_ana_inf_tx_scale = 0x4000678c ); -PROVIDE ( rom_set_channel_freq = 0x40006c50 ); -PROVIDE ( rom_set_loopback_gain = 0x400067c8 ); -PROVIDE ( rom_set_noise_floor = 0x40006830 ); -PROVIDE ( rom_set_rxclk_en = 0x40006550 ); -PROVIDE ( rom_set_txbb_atten = 0x40008c6c ); -PROVIDE ( rom_set_txclk_en = 0x4000650c ); -PROVIDE ( rom_set_txiq_cal = 0x40008d34 ); -PROVIDE ( rom_start_noisefloor = 0x40006874 ); -PROVIDE ( rom_start_tx_tone = 0x400068b4 ); -PROVIDE ( rom_stop_tx_tone = 0x4000698c ); -PROVIDE ( rom_tx_mac_disable = 0x40006a98 ); -PROVIDE ( rom_tx_mac_enable = 0x40006ad4 ); -PROVIDE ( rom_txtone_linear_pwr = 0x40006a1c ); -PROVIDE ( rom_write_rfpll_sdm = 0x400078dc ); -PROVIDE ( roundup2 = 0x400031b4 ); -PROVIDE ( rtc_enter_sleep = 0x40002870 ); -PROVIDE ( rtc_get_reset_reason = 0x400025e0 ); -PROVIDE ( rtc_intr_handler = 0x400029ec ); -PROVIDE ( rtc_set_sleep_mode = 0x40002668 ); -PROVIDE ( save_rxbcn_mactime = 0x400027a4 ); -PROVIDE ( save_tsf_us = 0x400027ac ); -PROVIDE ( send_packet = 0x40003c80 ); -PROVIDE ( sha1_prf = 0x4000ba48 ); -PROVIDE ( sha1_vector = 0x4000a2ec ); -PROVIDE ( sip_alloc_to_host_evt = 0x40005180 ); -PROVIDE ( sip_get_ptr = 0x400058a8 ); -PROVIDE ( sip_get_state = 0x40005668 ); -PROVIDE ( sip_init_attach = 0x4000567c ); -PROVIDE ( sip_install_rx_ctrl_cb = 0x4000544c ); -PROVIDE ( sip_install_rx_data_cb = 0x4000545c ); -PROVIDE ( sip_post = 0x400050fc ); -PROVIDE ( sip_post_init = 0x400056c4 ); -PROVIDE ( sip_reclaim_from_host_cmd = 0x4000534c ); -PROVIDE ( sip_reclaim_tx_data_pkt = 0x400052c0 ); -PROVIDE ( sip_send = 0x40005808 ); -PROVIDE ( sip_to_host_chain_append = 0x40005864 ); -PROVIDE ( sip_to_host_evt_send_done = 0x40005234 ); -PROVIDE ( slc_add_credits = 0x400060ac ); -PROVIDE ( slc_enable = 0x40005d90 ); -PROVIDE ( slc_from_host_chain_fetch = 0x40005f24 ); -PROVIDE ( slc_from_host_chain_recycle = 0x40005e94 ); -PROVIDE ( slc_init_attach = 0x40005c50 ); -PROVIDE ( slc_init_credit = 0x4000608c ); -PROVIDE ( slc_pause_from_host = 0x40006014 ); -PROVIDE ( slc_reattach = 0x40005c1c ); -PROVIDE ( slc_resume_from_host = 0x4000603c ); -PROVIDE ( slc_select_tohost_gpio = 0x40005dc0 ); -PROVIDE ( slc_select_tohost_gpio_mode = 0x40005db8 ); -PROVIDE ( slc_send_to_host_chain = 0x40005de4 ); -PROVIDE ( slc_set_host_io_max_window = 0x40006068 ); -PROVIDE ( slc_to_host_chain_recycle = 0x40005f10 ); -PROVIDE ( software_reset = 0x4000264c ); -PROVIDE ( spi_flash_attach = 0x40004644 ); -PROVIDE ( srand = 0x400005f0 ); -PROVIDE ( strcmp = 0x4000bdc8 ); -PROVIDE ( strcpy = 0x4000bec8 ); -PROVIDE ( strlen = 0x4000bf4c ); -PROVIDE ( strncmp = 0x4000bfa8 ); -PROVIDE ( strncpy = 0x4000c0a0 ); -PROVIDE ( strstr = 0x4000e1e0 ); -PROVIDE ( timer_insert = 0x40002c64 ); -PROVIDE ( uartAttach = 0x4000383c ); -PROVIDE ( uart_baudrate_detect = 0x40003924 ); -PROVIDE ( uart_buff_switch = 0x400038a4 ); -PROVIDE ( uart_div_modify = 0x400039d8 ); -PROVIDE ( uart_rx_intr_handler = 0x40003bbc ); -PROVIDE ( uart_rx_one_char = 0x40003b8c ); -PROVIDE ( uart_rx_one_char_block = 0x40003b64 ); -PROVIDE ( uart_rx_readbuff = 0x40003ec8 ); -PROVIDE ( uart_tx_one_char = 0x40003b30 ); -PROVIDE ( wepkey_128 = 0x4000bc40 ); -PROVIDE ( wepkey_64 = 0x4000bb3c ); -PROVIDE ( xthal_bcopy = 0x40000688 ); -PROVIDE ( xthal_copy123 = 0x4000074c ); -PROVIDE ( xthal_get_ccompare = 0x4000dd4c ); -PROVIDE ( xthal_get_ccount = 0x4000dd38 ); -PROVIDE ( xthal_get_interrupt = 0x4000dd58 ); -PROVIDE ( xthal_get_intread = 0x4000dd58 ); -PROVIDE ( xthal_memcpy = 0x400006c4 ); -PROVIDE ( xthal_set_ccompare = 0x4000dd40 ); -PROVIDE ( xthal_set_intclear = 0x4000dd60 ); -PROVIDE ( xthal_spill_registers_into_stack_nw = 0x4000e320 ); -PROVIDE ( xthal_window_spill = 0x4000e324 ); -PROVIDE ( xthal_window_spill_nw = 0x4000e320 ); - -PROVIDE ( Te0 = 0x3fffccf0 ); -PROVIDE ( Td0 = 0x3fffd100 ); -PROVIDE ( Td4s = 0x3fffd500); -PROVIDE ( rcons = 0x3fffd0f0); -PROVIDE ( UartDev = 0x3fffde10 ); diff --git a/cpu/esp8266/ld/esp8266.peripherals.ld b/cpu/esp8266/ld/esp8266.peripherals.ld new file mode 100644 index 000000000000..99d1697a29d9 --- /dev/null +++ b/cpu/esp8266/ld/esp8266.peripherals.ld @@ -0,0 +1,14 @@ +PROVIDE ( GPIO = 0x60000300); + +PROVIDE ( uart0 = 0x60000000 ); +PROVIDE ( uart1 = 0x60000f00 ); + +PROVIDE ( frc1 = 0x60000600 ); + +PROVIDE ( rtc_sys_info = 0x60001100 ); + +PROVIDE ( SLC = 0x60000B00 ); +PROVIDE ( I2S = 0x60000e00 ); + +PROVIDE ( SPI1 = 0x60000100 ); +PROVIDE ( SPI0 = 0x60000200 ); diff --git a/cpu/esp8266/ld/esp8266.riot-os.no_sdk.app.ld b/cpu/esp8266/ld/esp8266.riot-os.ld similarity index 65% rename from cpu/esp8266/ld/esp8266.riot-os.no_sdk.app.ld rename to cpu/esp8266/ld/esp8266.riot-os.ld index fd555cae0172..4f00adcf4cc3 100644 --- a/cpu/esp8266/ld/esp8266.riot-os.no_sdk.app.ld +++ b/cpu/esp8266/ld/esp8266.riot-os.ld @@ -1,17 +1,15 @@ /** - * This linker script is a modified version of eagle.app.v6.ld that - * was generated from xt-genldscripts.tpp for LSP and shipped with - * ESP8266_NONOS_SDK - */ - -/* Linker Script for ld -N */ + * This linker script is a combined and modified version of esp8266.ld and + * esp8266.common.ld from ESP8266-RTOS-SDK. + */ MEMORY { dport0_0_seg : org = 0x3FF00000, len = 0x10 - dram0_0_seg : org = 0x3FFE8000, len = 0x14000 - iram1_0_seg : org = 0x40100000, len = 0x8000 - irom0_0_seg : org = 0x40210000, len = 0x5C000 + dram0_0_seg : org = 0x3FFE8000, len = 0x18000 + iram1_0_seg : org = 0x40100000, len = 0xC000 + irom0_0_seg : org = 0x40200010 + 0x10000, len = 0x80000 - 0x10 - 0x10000 + rtc_seg : org = 0x60001200, len = 0x200 } PHDRS @@ -25,7 +23,7 @@ PHDRS /* Default entry point: */ -ENTRY(_call_user_start) +ENTRY(call_user_start) EXTERN(_DebugExceptionVector) EXTERN(_DoubleExceptionVector) EXTERN(_KernelExceptionVector) @@ -50,17 +48,6 @@ _memmap_cacheattr_wt_allvalid = 0x22222112; _memmap_cacheattr_bp_allvalid = 0x22222222; PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); -/* ROM variables */ -/* source: disassembly of boot rom at https://github.com/trebisky/esp8266 */ -PROVIDE( ets_task_min_prio = 0x3fffc6fc ); -PROVIDE( ets_idle_cb = 0x3fffdab0 ); -PROVIDE( ets_idle_arg = 0x3fffdab4 ); -PROVIDE( ets_task_exec_mask = 0x3fffdab8 ); -PROVIDE( ets_task_tab = 0x3fffdac0 ); -PROVIDE( flashchip = 0x3fffc714 ); -PROVIDE( sdk_flashchip = 0x3fffc718 ); -PROVIDE( ets_phy_mactime = 0x3ff20a00 ); - SECTIONS { @@ -88,6 +75,15 @@ SECTIONS _dport0_data_end = ABSOLUTE(.); } >dport0_0_seg :dport0_0_phdr + /* RTC memory holds user's data/rodata */ + .rtc.data : + { + _rtc_data_start = ABSOLUTE(.); + *(.rtc.data) + *(.rtc.rodata) + _rtc_data_end = ABSOLUTE(.); + } > rtc_seg + .data : ALIGN(4) { _data_start = ABSOLUTE(.); @@ -108,26 +104,30 @@ SECTIONS .rodata : ALIGN(4) { _rodata_start = ABSOLUTE(.); - *(.sdk.version) - /* TODO put only necessary .rodata to dram + /* TODO put only necessary .rodata to dram */ + /* *(.rodata .rodata.*) */ *libc.a:*.o(.rodata.* .rodata) *core.a:*(.rodata.* .rodata) *cpu.a:*(.rodata .rodata.*) - */ - *(.rodata .rodata.*) + *libpp.a:(.rodata.* .rodata) + *liblog.a:(.rodata.* .rodata) + *(.gnu.linkonce.r.*) *(.rodata1) __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); *(.xt_except_table) - *(.gcc_except_table) + *(.gcc_except_table.*) *(.gnu.linkonce.e.*) *(.gnu.version_r) *(.eh_frame) + . = (. + 3) & ~ 3; /* C++ constructor and destructor tables, properly ordered: */ + __init_array_start = ABSOLUTE(.); KEEP (*crtbegin.o(.ctors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) + __init_array_end = ABSOLUTE(.); KEEP (*crtbegin.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) KEEP (*(SORT(.dtors.*))) @@ -140,7 +140,7 @@ SECTIONS *(.xt_except_desc_end) *(.dynamic) *(.gnu.version_d) - . = ALIGN(4); /* this table MUST be 4-byte aligned */ + . = ALIGN(4); /* this table MUST be 4-byte aligned */ _bss_table_start = ABSOLUTE(.); LONG(_bss_start) LONG(_bss_end) @@ -165,7 +165,6 @@ SECTIONS *(.bss.*) *(.gnu.linkonce.b.*) *(COMMON) - . = ALIGN (8); _bss_end = ABSOLUTE(.); _sheap = ABSOLUTE(.); @@ -173,40 +172,39 @@ SECTIONS } >dram0_0_seg :dram0_0_bss_phdr - /* ETS system memory starts at 0x3FFFC000 which is the top of the heap for the app */ - . = 0x3FFFC000; + . = 0x3FFFFFF0; _heap_top = ABSOLUTE(.); _eheap = ABSOLUTE(.); - .text : ALIGN(4) + .text : ALIGN(4) /* IRAM */ { _stext = .; _text_start = ABSOLUTE(.); - *(.UserEnter.text) + LONG(_text_start) . = ALIGN(16); - *(.DebugExceptionVector.text) + *(.DebugExceptionVector.text) /* 0x40100010 */ . = ALIGN(16); - *(.NMIExceptionVector.text) + *(.NMIExceptionVector.text) /* 0x40100020 */ . = ALIGN(16); - *(.KernelExceptionVector.text) + *(.KernelExceptionVector.text) /* 0x40100030 */ LONG(0) LONG(0) LONG(0) LONG(0) . = ALIGN(16); - *(.UserExceptionVector.text) + *(.UserExceptionVector.text) /* 0x40100050 */ LONG(0) LONG(0) LONG(0) LONG(0) . = ALIGN(16); - *(.DoubleExceptionVector.text) + *(.DoubleExceptionVector.text) /* 0x40100070 */ LONG(0) LONG(0) LONG(0) LONG(0) . = ALIGN (16); - *(.UserExceptionTrampoline.text) + *(.UserExceptionTrampoline.text) /* 0x40100090 */ . = ALIGN (16); *(.entry.text) *(.init.literal) @@ -214,30 +212,48 @@ SECTIONS /* normal code should be in irom0 */ /* - *(.literal .text .literal.* .text.* .stub) - *(.gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.literal .text) + *core.a:*(.literal .text .literal.* .text.*) */ - + *gdbstub.a:*(.literal .text .literal.* .text.*) + *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) /* RIOT-OS compiled source files that use the .iram1.* section names for IRAM functions, etc. */ - *(.iram1.*) - - /* SDK libraries expect their .text sections to link to iram, not irom */ - *libcrypto.a:*(.literal .text) - *libmain.a:*(.literal .text .literal.* .text.*) - *libnet80211.a:*(.literal .text) - *libpp.a:*(.literal .text .literal.* .text.*) - *libphy.a:*(.literal .text .literal.* .text.*) - *libwpa.a:*(.literal .text) - *libwpa2.a:*(.literal .text) - *liblwip.a:*(.literal .text) + *(.iram1 .iram1.*) + + /* SDK libraries that expect their .text or .data sections to link to iram */ + /* TODO *libcore.a:(.bss .data .bss.* .data.* COMMON) */ + *esp_idf_spi_flash.a:spi_flash_raw.o(.literal .text .literal.* .text.*) + *esp_idf_esp8266.a:ets_printf.o(.literal .text .literal.* .text.*) + /* + *cpu.a:*.o(.literal .text .literal.* .text.*) + */ + *core.a:sched.o(.literal .text .literal.* .text.*) + *esp_wifi.a:*(.literal .text .literal.* .text.*) + *freertos.a:*(.literal .text .literal.* .text.*) + *periph.a:*(.literal .text .literal.* .text.*) + *xtimer.a:*(.literal .text .literal.* .text.*) + + *libhal.a:clock.o(.literal .text .literal.* .text.*) + *libhal.a:int_asm--set_intclear.o(.literal .text .literal.* .text.*) + *libpp.a:esf_buf.o(.literal .text .literal.* .text.*) + *libpp.a:lmac.o(.literal .text .literal.* .text.*) + *libpp.a:pp.o(.literal .text .literal.* .text.*) + *libpp.a:rate_control.o(.literal .text .literal.* .text.*) + *libpp.a:trc.o(.literal .text .literal.* .text.*) + *libpp.a:wdev.o(.literal .text .literal.* .text.*) + *libphy.a:phy.o(.literal .text .literal.* .text.*) + *libphy.a:phy_chip_v6_cal.o(.literal .text .literal.* .text.*) + *libphy.a:phy_sleep.o(.literal .text .literal.* .text.*) /* Xtensa basic functionality written in assembler should be placed in iram */ *xtensa.a:*(.literal .text .literal.* .text.*) - /* libgcc integer functions also need to be in .text, as some are called before - flash is mapped (also performance) - */ + /* libgcc functions required for debugging have to be in IRAM */ + *libgcc.a:unwind-dw2.o(.literal .text .literal.* .text.*) + + /* libgcc integer functions also need to be in .text */ + /* some are called before flash is mapped and also for performance) */ *libgcc.a:*i3.o(.literal .text .literal.* .text.*) *libgcc.a:*mulsf3.o(.literal .text .literal.* .text.*) @@ -245,6 +261,7 @@ SECTIONS *libgcc.a:*fixsfsi.o(.literal .text .literal.* .text.*) /* libc also in IRAM */ + /* *libc.a:*malloc.o(.literal .text .literal.* .text.*) *libc.a:*mallocr.o(.literal .text .literal.* .text.*) *libc.a:*freer.o(.literal .text .literal.* .text.*) @@ -260,6 +277,7 @@ SECTIONS *libc.a:*printf.o(.literal .text .literal.* .text.*) *libc.a:*findfp.o(.literal .text .literal.* .text.*) *libc.a:*fputwc.o(.literal .text .literal.* .text.*) + */ enc28j60.a:*(.literal .text .literal.* .text.*) @@ -274,15 +292,18 @@ SECTIONS { _irom0_text_start = ABSOLUTE(.); - *libmbedtls.a:(.literal .text .literal.* .text.*) - - /* RIOT-OS compiled code goes into IROM by default - (except for libgcc which is matched above.) */ - *(.literal .text .literal.* .text.* .rodata .rodata.*) + /* RIOT-OS compiled code and RO data go into IROM by default */ + *(.literal .text .literal.* .text.*) + *(.rodata .rodata.*) /* Anything explicitly marked as "irom" or "irom0" should go here */ *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) + . = ALIGN(16); + __start_ksymatabesp_socket = .; + *(ksymatabesp_socket) + __stop_ksymatabesp_socket = .; + _irom0_text_end = ABSOLUTE(.); } >irom0_0_seg :irom0_0_phdr diff --git a/cpu/esp8266/ld/esp8266.riot-os.sdk.app.ld b/cpu/esp8266/ld/esp8266.riot-os.sdk.app.ld deleted file mode 100644 index f9f779cff223..000000000000 --- a/cpu/esp8266/ld/esp8266.riot-os.sdk.app.ld +++ /dev/null @@ -1,322 +0,0 @@ -/** - * This linker script is a modified version of eagle.app.v6.ld that - * was generated from xt-genldscripts.tpp for LSP and shipped with - * ESP8266_NONOS_SDK - */ - -/* Linker Script for ld -N */ - -MEMORY -{ - dport0_0_seg : org = 0x3FF00000, len = 0x10 - dram0_0_seg : org = 0x3FFE8000, len = 0x14000 - iram1_0_seg : org = 0x40100000, len = 0x8000 - irom0_0_seg : org = 0x40210000, len = 0x5C000 -} - -PHDRS -{ - dport0_0_phdr PT_LOAD; - dram0_0_phdr PT_LOAD; - dram0_0_bss_phdr PT_LOAD; - iram1_0_phdr PT_LOAD; - irom0_0_phdr PT_LOAD; -} - - -/* Default entry point: */ -ENTRY(call_user_start) -EXTERN(_DebugExceptionVector) -EXTERN(_DoubleExceptionVector) -EXTERN(_KernelExceptionVector) -EXTERN(_NMIExceptionVector) -EXTERN(_UserExceptionVector) -PROVIDE(_memmap_vecbase_reset = 0x40000000); -/* Various memory-map dependent cache attribute settings: */ -_memmap_cacheattr_wb_base = 0x00000110; -_memmap_cacheattr_wt_base = 0x00000110; -_memmap_cacheattr_bp_base = 0x00000220; -_memmap_cacheattr_unused_mask = 0xFFFFF00F; -_memmap_cacheattr_wb_trapnull = 0x2222211F; -_memmap_cacheattr_wba_trapnull = 0x2222211F; -_memmap_cacheattr_wbna_trapnull = 0x2222211F; -_memmap_cacheattr_wt_trapnull = 0x2222211F; -_memmap_cacheattr_bp_trapnull = 0x2222222F; -_memmap_cacheattr_wb_strict = 0xFFFFF11F; -_memmap_cacheattr_wt_strict = 0xFFFFF11F; -_memmap_cacheattr_bp_strict = 0xFFFFF22F; -_memmap_cacheattr_wb_allvalid = 0x22222112; -_memmap_cacheattr_wt_allvalid = 0x22222112; -_memmap_cacheattr_bp_allvalid = 0x22222222; -PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); - -/* System task handling variables */ -/* source: disassembly of boot rom at https://github.com/trebisky/esp8266 */ -PROVIDE( ets_task_min_prio = 0x3fffc6fc ); -PROVIDE( ets_idle_cb = 0x3fffdab0 ); -PROVIDE( ets_idle_arg = 0x3fffdab4 ); -PROVIDE( ets_task_exec_mask = 0x3fffdab8 ); -PROVIDE( ets_task_tab = 0x3fffdac0 ); -PROVIDE( flashchip = 0x3fffc714 ); -PROVIDE( sdk_flashchip = 0x3fffc718 ); -PROVIDE( _xt_interrupt_table = 0x3fffc200 ); - -SECTIONS -{ - - .dport0.rodata : ALIGN(4) - { - _dport0_rodata_start = ABSOLUTE(.); - *(.dport0.rodata) - *(.dport.rodata) - _dport0_rodata_end = ABSOLUTE(.); - } >dport0_0_seg :dport0_0_phdr - - .dport0.literal : ALIGN(4) - { - _dport0_literal_start = ABSOLUTE(.); - *(.dport0.literal) - *(.dport.literal) - _dport0_literal_end = ABSOLUTE(.); - } >dport0_0_seg :dport0_0_phdr - - .dport0.data : ALIGN(4) - { - _dport0_data_start = ABSOLUTE(.); - *(.dport0.data) - *(.dport.data) - _dport0_data_end = ABSOLUTE(.); - } >dport0_0_seg :dport0_0_phdr - - .data : ALIGN(4) - { - _data_start = ABSOLUTE(.); - *(.data) - *(.data.*) - *(.gnu.linkonce.d.*) - *(.data1) - *(.sdata) - *(.sdata.*) - *(.gnu.linkonce.s.*) - *(.sdata2) - *(.sdata2.*) - *(.gnu.linkonce.s2.*) - *(.jcr) - _data_end = ABSOLUTE(.); - } >dram0_0_seg :dram0_0_phdr - - /* - * .rodata sections that are placed in RAM - * - * Usually, all .rodata sections are placed in RAM by the Espressif SDK - * since IROM (flash) access requires 32-bit word aligned reads. - * - * However, thanks to the LoadStoreError handler from esp-open-rtos which is - * also used in RIOT-OS, it is possible to place .rodata sections in IROM - * (flash) to save RAM resources. - * - * Only .rodata data sections of compilation units that may be executed - * while SPI flash is not mapped have to be stored in RAM. These are IRAM - * functions that are called from interrupt context or SPI flash management - * functions. Such compilation units have to be listed here. - * - * Furthermore, compilation units with constant data that are performance- - * critical should be listed here as well. - */ - - .rodata : ALIGN(4) - { - _rodata_start = ABSOLUTE(.); - *(.sdk.version) - - *core.a:*(.rodata.* .rodata) - *cpu.a:*(.rodata .rodata.*) - *esp.a:*(.rodata .rodata.*) - *esp_now.a:*(.rodata .rodata.*) - *esp_wifi.a:*(.rodata .rodata.*) - *periph.a:*(.rodata.* .rodata) - *sdk.a:*(.rodata .rodata.*) - *xtensa.a:*(.rodata .rodata.*) - - *libc.a:*.o(.rodata.* .rodata) - *libpp.a:wdev.o(.rodata.* .rodata) - *libmain.a:spi_flash.o(.rodata.* .rodata) - - *(.gnu.linkonce.r.*) - *(.rodata1) - __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); - *(.xt_except_table) - *(.gcc_except_table) - *(.gnu.linkonce.e.*) - *(.gnu.version_r) - *(.eh_frame) - /* C++ constructor and destructor tables, properly ordered: */ - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - /* C++ exception handlers table: */ - __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); - *(.xt_except_desc) - *(.gnu.linkonce.h.*) - __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); - *(.xt_except_desc_end) - *(.dynamic) - *(.gnu.version_d) - . = ALIGN(4); /* this table MUST be 4-byte aligned */ - _bss_table_start = ABSOLUTE(.); - LONG(_bss_start) - LONG(_bss_end) - _bss_table_end = ABSOLUTE(.); - _rodata_end = ABSOLUTE(.); - } >dram0_0_seg :dram0_0_phdr - - .bss ALIGN(8) (NOLOAD) : ALIGN(4) - { - . = ALIGN (8); - _bss_start = ABSOLUTE(.); - *(.dynsbss) - *(.sbss) - *(.sbss.*) - *(.gnu.linkonce.sb.*) - *(.scommon) - *(.sbss2) - *(.sbss2.*) - *(.gnu.linkonce.sb2.*) - *(.dynbss) - *(.bss) - *(.bss.*) - *(.gnu.linkonce.b.*) - *(COMMON) - - . = ALIGN (8); - _bss_end = ABSOLUTE(.); - _sheap = ABSOLUTE(.); - _heap_start = ABSOLUTE(.); - - } >dram0_0_seg :dram0_0_bss_phdr - - /* ETS system memory starts at 0x3FFFC000 which is the top of the heap for the app */ - . = 0x3FFFC000; - _heap_top = ABSOLUTE(.); - _eheap = ABSOLUTE(.); - - .text : ALIGN(4) - { - _stext = .; - _text_start = ABSOLUTE(.); - *(.UserEnter.text) - . = ALIGN(16); - *(.DebugExceptionVector.text) - . = ALIGN(16); - *(.NMIExceptionVector.text) - . = ALIGN(16); - *(.KernelExceptionVector.text) - LONG(0) - LONG(0) - LONG(0) - LONG(0) - . = ALIGN(16); - *(.UserExceptionVector.text) - LONG(0) - LONG(0) - LONG(0) - LONG(0) - . = ALIGN(16); - *(.DoubleExceptionVector.text) - LONG(0) - LONG(0) - LONG(0) - LONG(0) - . = ALIGN (16); - *(.UserExceptionTrampoline.text) - . = ALIGN (16); - *(.entry.text) - *(.init.literal) - *(.init) - - /* normal code should be in irom0 */ - /* - *(.literal .text .literal.* .text.* .stub) - *(.gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) - */ - - /* RIOT-OS compiled source files that use the .iram1.* section names for IRAM - functions, etc. */ - *(.iram1.*) - - /* SDK libraries expect their .text sections to link to iram, not irom */ - *libcrypto.a:*(.literal .text) - *libmain.a:*(.literal .text .literal.* .text.*) - *libnet80211.a:*(.literal .text) - *libpp.a:*(.literal .text .literal.* .text.*) - *libphy.a:*(.literal .text .literal.* .text.*) - *libwpa.a:*(.literal .text) - *libwpa2.a:*(.literal .text) - *liblwip.a:*(.literal .text) - - /* Xtensa basic functionality written in assembler should be placed in iram */ - *xtensa.a:*(.literal .text .literal.* .text.*) - - /* libgcc integer functions also need to be in .text, as some are called before - flash is mapped (also performance) */ - *libgcc.a:*i3.o(.literal .text .literal.* .text.*) - - *libgcc.a:*mulsf3.o(.literal .text .literal.* .text.*) - *libgcc.a:*divsf3.o(.literal .text .literal.* .text.*) - *libgcc.a:*fixsfsi.o(.literal .text .literal.* .text.*) - - /* libc also in IRAM */ - *libc.a:*malloc.o(.literal .text .literal.* .text.*) - *libc.a:*mallocr.o(.literal .text .literal.* .text.*) - *libc.a:*freer.o(.literal .text .literal.* .text.*) - *libc.a:*memchr.o(.literal .text .literal.* .text.*) - *libc.a:*memcpy.o(.literal .text .literal.* .text.*) - *libc.a:*memset.o(.literal .text .literal.* .text.*) - *libc.a:*memcmp.o(.literal .text .literal.* .text.*) - *libc.a:*memmove.o(.literal .text .literal.* .text.*) - *libc.a:*rand.o(.literal .text .literal.* .text.*) - *libc.a:*bzero.o(.literal .text .literal.* .text.*) - *libc.a:*lock.o(.literal .text .literal.* .text.*) - - *libc.a:*findfp.o(.literal .text .literal.* .text.*) - *libc.a:*fputwc.o(.literal .text .literal.* .text.*) - - enc28j60.a:*(.literal .text .literal.* .text.*) - - *(.fini.literal) - *(.fini) - *(.gnu.version) - _text_end = ABSOLUTE(.); - _etext = .; - } >iram1_0_seg :iram1_0_phdr - - .irom0.text : ALIGN(4) - { - _irom0_text_start = ABSOLUTE(.); - - *libmbedtls.a:(.literal .text .literal.* .text.*) - - /* RIOT-OS compiled code goes into IROM by default - (except for functions with section names defined in .text above.) */ - *(.literal .text .literal.* .text.* .rodata .rodata.*) - - /* Anything explicitly marked as "irom" or "irom0" should go here */ - *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) - - _irom0_text_end = ABSOLUTE(.); - } >irom0_0_seg :irom0_0_phdr - - .lit4 : ALIGN(4) - { - _lit4_start = ABSOLUTE(.); - *(*.lit4) - *(.lit4.*) - *(.gnu.linkonce.lit4.*) - _lit4_end = ABSOLUTE(.); - } >iram1_0_seg :iram1_0_phdr -} diff --git a/cpu/esp8266/ld/esp8266.rom.ld b/cpu/esp8266/ld/esp8266.rom.ld new file mode 100644 index 000000000000..8a3d29cca725 --- /dev/null +++ b/cpu/esp8266/ld/esp8266.rom.ld @@ -0,0 +1,60 @@ +SPI_sector_erase = 0x400040c0; +SPI_page_program = 0x40004174; +SPI_read_data = 0x400042ac; +SPI_read_status = 0x400043c8; +SPI_write_status = 0x40004400; +SPI_write_enable = 0x4000443c; +Wait_SPI_Idle = 0x4000448c; +Enable_QMode = 0x400044c0; +Disable_QMode = 0x40004508; + +Cache_Read_Enable = 0x40004678; +Cache_Read_Disable = 0x400047f0; + +lldesc_build_chain = 0x40004f40; +lldesc_num2link = 0x40005050; +lldesc_set_owner = 0x4000507c; + +__adddf3 = 0x4000c538; +__addsf3 = 0x4000c180; +__divdf3 = 0x4000cb94; +__divdi3 = 0x4000ce60; +__divsi3 = 0x4000dc88; +__extendsfdf2 = 0x4000cdfc; +__fixdfsi = 0x4000ccb8; +__fixunsdfsi = 0x4000cd00; +__fixunssfsi = 0x4000c4c4; +__floatsidf = 0x4000e2f0; +__floatsisf = 0x4000e2ac; +__floatunsidf = 0x4000e2e8; +__floatunsisf = 0x4000e2a4; +__muldf3 = 0x4000c8f0; +__muldi3 = 0x40000650; +__mulsf3 = 0x4000c3dc; +__subdf3 = 0x4000c688; +__subsf3 = 0x4000c268; +__truncdfsf2 = 0x4000cd5c; +__udivdi3 = 0x4000d310; +__udivsi3 = 0x4000e21c; +__umoddi3 = 0x4000d770; +__umodsi3 = 0x4000e268; +__umulsidi3 = 0x4000dcf0; + +bzero = 0x4000de84; +memcmp = 0x4000dea8; +memcpy = 0x4000df48; +memmove = 0x4000e04c; +memset = 0x4000e190; + +strcmp = 0x4000bdc8; +strcpy = 0x4000bec8; +strlen = 0x4000bf4c; +strncmp = 0x4000bfa8; +strncpy = 0x4000c0a0; +strstr = 0x4000e1e0; + +gpio_input_get = 0x40004cf0; +gpio_pin_wakeup_disable = 0x40004ed4; +gpio_pin_wakeup_enable = 0x40004e90; + +ets_io_vprintf = 0x40001f00; diff --git a/cpu/esp8266/periph/Makefile b/cpu/esp8266/periph/Makefile index 6d1887b64009..d6a5d0455c5d 100644 --- a/cpu/esp8266/periph/Makefile +++ b/cpu/esp8266/periph/Makefile @@ -1,3 +1,3 @@ MODULE = periph -include $(RIOTBASE)/Makefile.base +include $(RIOTMAKE)/periph.mk diff --git a/cpu/esp8266/periph/adc.c b/cpu/esp8266/periph/adc.c index 8e367a005e4e..6615cfed18cd 100644 --- a/cpu/esp8266/periph/adc.c +++ b/cpu/esp8266/periph/adc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser General * Public License v2.1. See the file LICENSE in the top level directory for more @@ -28,10 +28,10 @@ #include "periph_conf.h" #include "board.h" -#include "common.h" +#include "esp_common.h" #include "sdk/sdk.h" -#if defined(ADC_NUMOF) && ADC_NUMOF > 0 +extern uint16_t test_tout(void); int adc_init(adc_t line) { @@ -47,11 +47,10 @@ int adc_sample(adc_t line, adc_res_t res) CHECK_PARAM_RET (line < ADC_NUMOF, -1) CHECK_PARAM_RET (res == ADC_RES_10BIT, -1) - #ifdef MODULE_ESP_SDK - return system_adc_read (); - #else - return test_tout(false); - #endif + return test_tout(); } -#endif +void adc_print_config(void) +{ + printf("\tADC\t\tpins=[ A0 ]\n"); +} diff --git a/cpu/esp8266/periph/flash.c b/cpu/esp8266/periph/flash.c index 912c3ae927e6..8df422ea43b8 100644 --- a/cpu/esp8266/periph/flash.c +++ b/cpu/esp8266/periph/flash.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -18,25 +18,42 @@ * @} */ -#define ENABLE_DEBUG (0) -#include "debug.h" +#if MODULE_MTD #include #include #include #include "board.h" -#include "common.h" +#include "esp_common.h" #include "irq_arch.h" #include "log.h" + #include "mtd.h" -#include "c_types.h" -#include "esp/spiflash.h" +#include "esp_flash_data_types.h" +#include "esp_partition.h" + +#ifdef MCU_ESP32 + +#include "rom/cache.h" +#include "rom/spi_flash.h" +#include "esp_spi_flash.h" + +#else /* MCU_ESP32 */ + +#include "rom_functions.h" #include "spi_flash.h" -#include "sdk/rom.h" -#define SDK_FLASH_FUNCTIONS +#endif /* MCU_ESP32 */ + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define ESP_PART_TABLE_ADDR 0x8000 /* TODO configurable as used in Makefile.include */ +#define ESP_PART_TABLE_SIZE 0xC00 +#define ESP_PART_ENTRY_SIZE 0x20 +#define ESP_PART_ENTRY_MAGIC ESP_PARTITION_MAGIC /* the external pointer to the system MTD device */ mtd_dev_t* mtd0 = 0; @@ -44,6 +61,18 @@ mtd_dev_t* mtd0 = 0; mtd_dev_t _flash_dev; mtd_desc_t _flash_driver; +#ifdef MCU_ESP8266 + +/* for source code compatibility with ESP32 SDK */ +#define esp_rom_spiflash_chip_t esp_spi_flash_chip_t +#define g_rom_flashchip flashchip + +/* defined in vendor/esp-idf/spi_flash.c */ +extern esp_spi_flash_chip_t flashchip; +extern uint32_t spi_flash_get_id(void); + +#endif /* MCU_ESP8266 */ + /* forward declaration of mtd functions */ static int _flash_init (mtd_dev_t *dev); static int _flash_read (mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size); @@ -55,80 +84,147 @@ static uint32_t _flash_beg; /* first byte addr of the flash drive in SPI flash static uint32_t _flash_end; /* first byte addr after the flash drive in SPI flash */ static uint32_t _flash_size; /* resulting size of the flash drive in SPI flash */ -#define SPIFFS_FLASH_BEGIN 0x80000 /* TODO determine real possible value */ +static esp_rom_spiflash_chip_t* _flashchip = NULL; -void flash_drive_init (void) +/* flash_id determines the flash size in kByte */ +static const uint32_t flash_sizes[] = { + 256, /* last byte of id is 0x12 */ + 512, /* last byte of id is 0x13 */ + 1 * 1024, /* last byte of id is 0x14 */ + 2 * 1024, /* last byte of id is 0x15 */ + 4 * 1024, /* last byte of id is 0x16 */ + 8 * 1024, /* last byte of id is 0x17 */ + 16 * 1024 /* last byte of id is 0x18 */ +}; + +void spi_flash_drive_init (void) { DEBUG("%s\n", __func__); + _flashchip = &g_rom_flashchip; + assert(_flashchip); + +#ifdef MCU_ESP8266 + _flashchip->deviceId = spi_flash_get_id(); + uint8_t devid_lb = _flashchip->deviceId >> 16 & 0xff; + if (devid_lb >= 0x12 && devid_lb <= 0x18) { + _flashchip->chip_size = flash_sizes[devid_lb - 0x12] << 10; + } + else { + LOG_TAG_WARNING("spi_flash", "could not determine flash size, " + "4 MBytes are used as default size\n"); + _flashchip->chip_size = 4 << 20; + } +#endif /* MCU_ESP8266 */ + _flash_driver.init = &_flash_init; _flash_driver.read = &_flash_read; _flash_driver.write = &_flash_write; _flash_driver.erase = &_flash_erase; _flash_driver.power = &_flash_power; - _flash_beg = SPIFFS_FLASH_BEGIN; - _flash_end = flashchip->chip_size - 5 * flashchip->sector_size; + /* first, set the beginning of flash to 0x0 to read partition table */ + _flash_beg = 0x0; + _flash_end = _flashchip->chip_size - 5 * _flashchip->sector_size; _flash_size = _flash_end - _flash_beg; + /* read in partition table an determine the top of all partitions */ + uint32_t part_addr = ESP_PART_TABLE_ADDR; + uint8_t part_buf[ESP_PART_ENTRY_SIZE]; + bool part_read = true; + uint32_t part_top = 0; + esp_partition_info_t* part = (esp_partition_info_t*)part_buf; + + while (part_read && part_addr < ESP_PART_TABLE_ADDR + ESP_PART_TABLE_SIZE) { + spi_flash_read (part_addr, (void*)part_buf, ESP_PART_ENTRY_SIZE); + + if (part->magic == ESP_PART_ENTRY_MAGIC) { + DEBUG("%s partition @%08x size=%08x label=%s\n", __func__, + part->pos.offset, part->pos.size, part->label); + if (part->pos.offset + part->pos.size > part_top) { + part_top = part->pos.offset + part->pos.size; + } + part_addr += ESP_PART_ENTRY_SIZE; + } + else { + part_read = false; + } + } + +#ifdef MCU_ESP32 + /* map the partition top address to next higher multiple of 0x100000 (1 MB) */ + part_top = (part_top + 0x100000) & ~0xfffff; +#else /* MCU_ESP32 */ + /* map the partition top address to next higher multiple of 0x80000 (512 kB) */ + part_top = (part_top + 0x80000) & ~0x7ffff; +#endif /* MCU_ESP32 */ + + /* + * if flash drive start address is not configured, use the determined + * one otherwise check the configured one and use it + */ + #if SPI_FLASH_DRIVE_START + if (part_top > SPI_FLASH_DRIVE_START) { + LOG_TAG_ERROR("spi_flash", "configured MTD start address in SPI Flash is to less\n"); + } + else if (SPI_FLASH_DRIVE_START % _flashchip->sector_size) { + LOG_TAG_ERROR("spi_flash", "configured start address has to be a " + "multiple of %d byte\n", _flashchip->sector_size); + part_top = ((SPI_FLASH_DRIVE_START + + _flashchip->sector_size)) & ~(_flashchip->sector_size-1); + } + else { + part_top = SPI_FLASH_DRIVE_START; + } + #endif + + /* second, change flash parameters according to partition table */ + _flash_beg = part_top; + _flash_end = _flashchip->chip_size - 5 * _flashchip->sector_size; + _flash_size = _flash_end - _flash_beg; /* MUST be at least 3 sectors (0x3000) */ + + LOG_TAG_INFO("spi_flash", "MTD in SPI flash starts at address 0x%08x " + "with a size of %d kbytes\n", _flash_beg, _flash_size >> 10); + _flash_dev.driver = &_flash_driver; - _flash_dev.sector_count = _flash_size / flashchip->sector_size; + _flash_dev.sector_count = _flash_size / _flashchip->sector_size; mtd0 = &_flash_dev; - _flash_dev.pages_per_sector = flashchip->sector_size / flashchip->page_size; - _flash_dev.page_size = flashchip->page_size; + _flash_dev.pages_per_sector = _flashchip->sector_size / _flashchip->page_size; + _flash_dev.page_size = _flashchip->page_size; DEBUG("%s flashchip chip_size=%d block_size=%d sector_size=%d page_size=%d\n", __func__, - flashchip->chip_size, flashchip->block_size, - flashchip->sector_size, flashchip->page_size); + _flashchip->chip_size, _flashchip->block_size, + _flashchip->sector_size, _flashchip->page_size); DEBUG("%s flash_dev sector_count=%d pages_per_sector=%d page_size=%d\n", __func__, _flash_dev.sector_count, _flash_dev.pages_per_sector, _flash_dev.page_size); DEBUG("\n"); } -static int _flash_init (mtd_dev_t *dev) -{ - DEBUG("%s dev=%p driver=%p\n", __func__, dev, &_flash_driver); - - CHECK_PARAM_RET (dev == &_flash_dev, -ENODEV); - - #ifdef SPI_FLASH_CHIP_SIZE - if (SPI_FLASH_CHIP_SIZE <= SPIFFS_FLASH_BEGIN) { - #else - if (flashchip->chip_size <= SPIFFS_FLASH_BEGIN) { - #endif - LOG_ERROR("Flash size is equal or less than %d Byte, " - "SPIFFS cannot be used\n", SPIFFS_FLASH_BEGIN); - return -ENODEV; - } +#ifdef MCU_ESP32 - return 0; -} +#define RETURN_WITH_ESP_ERR_CODE(err) do { \ + switch (err) { \ + case ESP_ROM_SPIFLASH_RESULT_OK : return ESP_OK; \ + case ESP_ROM_SPIFLASH_RESULT_ERR : return ESP_ERR_FLASH_OP_FAIL; \ + case ESP_ROM_SPIFLASH_RESULT_TIMEOUT: return ESP_ERR_FLASH_OP_TIMEOUT; \ + } \ + return ESP_FAIL; \ +} while(0) -#define SPI_FLASH_BUF_SIZE 64 -uint8_t _flash_buf[SPI_FLASH_BUF_SIZE]; +uint8_t _flash_buf[ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM]; -static int _flash_read (mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size) +esp_err_t IRAM_ATTR spi_flash_read(size_t addr, void *buff, size_t size) { - DEBUG("%s dev=%p addr=%08x size=%u buf=%p\n", __func__, dev, addr, size, buff); + DEBUG("%s addr=%08x size=%u buf=%p\n", __func__, addr, size, buff); - CHECK_PARAM_RET (dev == &_flash_dev, -ENODEV); CHECK_PARAM_RET (buff != NULL, -ENOTSUP); /* size must be within the flash address space */ - CHECK_PARAM_RET (_flash_beg + addr + size <= _flash_end, -EOVERFLOW); + CHECK_PARAM_RET (addr + size <= _flash_end, -EOVERFLOW); - #ifndef SDK_FLASH_FUNCTIONS - bool result = spiflash_read (_flash_beg + addr, buff, size); - return result ? (int)size : -EIO; - #else - critical_enter(); - - /* it would be great if would work in that way, but would be too easy :-( */ - /* memcpy(buff, (void*)(_flash_beg + addr + 0x40200000), size); */ - - int result = SPI_FLASH_RESULT_OK; + int result = ESP_ROM_SPIFLASH_RESULT_OK; uint32_t len = size; /* if addr is not 4 byte aligned, we need to read the first full word */ @@ -138,89 +234,119 @@ static int _flash_read (mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t siz uint32_t len_in_word = 4 - pos_in_word; len_in_word = (len_in_word < len) ? len_in_word : len; - result = spi_flash_read (_flash_beg + word_addr, (uint32_t*)_flash_buf, 4); + /* disable interrupts and the cache */ + critical_enter(); + Cache_Read_Disable(PRO_CPU_NUM); + + result = esp_rom_spiflash_read (word_addr, (uint32_t*)_flash_buf, 4); memcpy(buff, _flash_buf + pos_in_word, len_in_word); + /* enable interrupts and the cache */ + Cache_Read_Enable(PRO_CPU_NUM); + critical_exit(); + buff = (uint8_t*)buff + len_in_word; addr += len_in_word; len -= len_in_word; } - /* read all full words, maximum SPI_FLASH_BUF_SIZE in one write operation */ - while (result == SPI_FLASH_RESULT_OK && len > 4) { + /* read all full words, maximum ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM + in one read operation */ + while (len > 4 && result == ESP_ROM_SPIFLASH_RESULT_OK) { uint32_t len_full_words = len & ~0x3; - - if (len_full_words > SPI_FLASH_BUF_SIZE) { - len_full_words = SPI_FLASH_BUF_SIZE; + if (len_full_words > ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM) { + len_full_words = ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM; } - result |= spi_flash_read (_flash_beg + addr, (uint32_t*)_flash_buf, len_full_words); + /* disable interrupts and the cache */ + critical_enter(); + Cache_Read_Disable(PRO_CPU_NUM); + + result |= esp_rom_spiflash_read (addr, (uint32_t*)_flash_buf, len_full_words); memcpy(buff, _flash_buf, len_full_words); + /* enable interrupts and the cache */ + Cache_Read_Enable(PRO_CPU_NUM); + critical_exit(); + buff = (uint8_t*)buff + len_full_words; addr += len_full_words; len -= len_full_words; } /* if there is some remaining, we need to prepare last word */ - if (result == SPI_FLASH_RESULT_OK && len) { - result |= spi_flash_read (_flash_beg + addr, (uint32_t*)_flash_buf, 4); + if (len && result == ESP_ROM_SPIFLASH_RESULT_OK) { + /* disable interrupts and the cache */ + critical_enter(); + Cache_Read_Disable(PRO_CPU_NUM); + + result |= esp_rom_spiflash_read (addr, (uint32_t*)_flash_buf, 4); memcpy(buff, _flash_buf, len); + + /* enable interrupts and the cache */ + Cache_Read_Enable(PRO_CPU_NUM); + critical_exit(); } - critical_exit(); - return (result == SPI_FLASH_RESULT_OK) ? (int)size : -EIO; - #endif + /* return with the ESP-IDF error code that is mapped from ROM error code */ + RETURN_WITH_ESP_ERR_CODE(result); } -static int _flash_write (mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size) +esp_err_t IRAM_ATTR spi_flash_write(size_t addr, const void *buff, size_t size) { - DEBUG("%s dev=%p addr=%08x size=%u buf=%p\n", __func__, dev, addr, size, buff); + DEBUG("%s addr=%08x size=%u buf=%p\n", __func__, addr, size, buff); - CHECK_PARAM_RET (dev == &_flash_dev, -ENODEV); CHECK_PARAM_RET (buff != NULL, -ENOTSUP); /* size must be within the flash address space */ - CHECK_PARAM_RET (_flash_beg + addr + size <= _flash_end, -EOVERFLOW); - - #ifndef SDK_FLASH_FUNCTIONS - - bool result = spiflash_write (_flash_beg + addr, (uint8_t*)buff, size); - return result ? (int)size : -EIO; - - #else - - critical_enter(); + CHECK_PARAM_RET (addr + size <= _flash_end, -EOVERFLOW); - int result = SPI_FLASH_RESULT_OK; + /* prepare for write access */ + int result = esp_rom_spiflash_unlock(); uint32_t len = size; /* if addr is not 4 byte aligned, we need to prepare first full word */ - if (addr & 0x3) { + if (addr & 0x3 && result == ESP_ROM_SPIFLASH_RESULT_OK) { uint32_t word_addr = addr & ~0x3; uint32_t pos_in_word = addr & 0x3; uint32_t len_in_word = 4 - pos_in_word; len_in_word = (len_in_word < len) ? len_in_word : len; - result = spi_flash_read (_flash_beg + word_addr, (uint32_t*)_flash_buf, 4); + /* disable interrupts and the cache */ + critical_enter(); + Cache_Read_Disable(PRO_CPU_NUM); + + result |= esp_rom_spiflash_read (word_addr, (uint32_t*)_flash_buf, 4); memcpy(_flash_buf + pos_in_word, buff, len_in_word); - result |= spi_flash_write (_flash_beg + word_addr, (uint32_t*)_flash_buf, 4); + result |= esp_rom_spiflash_write (word_addr, (uint32_t*)_flash_buf, 4); + + /* enable interrupts and the cache */ + Cache_Read_Enable(PRO_CPU_NUM); + critical_exit(); buff = (uint8_t*)buff + len_in_word; addr += len_in_word; len -= len_in_word; } - /* write all full words, maximum SPI_FLASH_BUF_SIZE in one write operation */ - while (result == SPI_FLASH_RESULT_OK && len > 4) { + /* write all full words, maximum ESP_ROM_SPIFLASH_BUFF_BYTE_WRITE_NUM + in one write operation */ + while (len > 4 && result == ESP_ROM_SPIFLASH_RESULT_OK) { uint32_t len_full_words = len & ~0x3; - - if (len_full_words > SPI_FLASH_BUF_SIZE) { - len_full_words = SPI_FLASH_BUF_SIZE; + if (len_full_words > ESP_ROM_SPIFLASH_BUFF_BYTE_WRITE_NUM) { + len_full_words = ESP_ROM_SPIFLASH_BUFF_BYTE_WRITE_NUM; } + /* disable interrupts and the cache */ + critical_enter(); + Cache_Read_Disable(PRO_CPU_NUM); + memcpy(_flash_buf, buff, len_full_words); - result |= spi_flash_write (_flash_beg + addr, (uint32_t*)_flash_buf, len_full_words); + result |= esp_rom_spiflash_write (addr, (uint32_t*)_flash_buf, len_full_words); + + /* enable interrupts and the cache */ + Cache_Read_Enable(PRO_CPU_NUM); + critical_exit(); buff = (uint8_t*)buff + len_full_words; addr += len_full_words; @@ -228,15 +354,178 @@ static int _flash_write (mtd_dev_t *dev, const void *buff, uint32_t addr, uint32 } /* if there is some remaining, we need to prepare last word */ - if (result == SPI_FLASH_RESULT_OK && len) { - result |= spi_flash_read (_flash_beg + addr, (uint32_t*)_flash_buf, 4); + if (len && result == ESP_ROM_SPIFLASH_RESULT_OK) { + /* disable interrupts and the cache */ + critical_enter(); + Cache_Read_Disable(PRO_CPU_NUM); + + result |= esp_rom_spiflash_read (addr, (uint32_t*)_flash_buf, 4); memcpy(_flash_buf, buff, len); - result |= spi_flash_write (_flash_beg + addr, (uint32_t*)_flash_buf, 4); + result |= esp_rom_spiflash_write (addr, (uint32_t*)_flash_buf, 4); + + /* enable interrupts and the cache */ + Cache_Read_Enable(PRO_CPU_NUM); + critical_exit(); } - critical_exit(); - return (result == SPI_FLASH_RESULT_OK) ? (int)size : -EIO; - #endif + /* reset write access */ + esp_rom_spiflash_lock(); + + /* return with the ESP-IDF error code that is mapped from ROM error code */ + RETURN_WITH_ESP_ERR_CODE(result); +} + +esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sector) +{ + return spi_flash_erase_range(sector * _flashchip->sector_size, 1); +} + +esp_err_t IRAM_ATTR spi_flash_erase_range(size_t addr, size_t size) +{ + /* size must be within the flash address space */ + CHECK_PARAM_RET (addr + size <= _flash_end, -EOVERFLOW); + + /* size must be a multiple of sector_size && at least one sector */ + CHECK_PARAM_RET (size >= _flashchip->sector_size, -ENOTSUP); + CHECK_PARAM_RET (size % _flashchip->sector_size == 0, -ENOTSUP) + + /* prepare for write access */ + uint32_t result = esp_rom_spiflash_unlock(); + + /* erase as many sectors as necessary */ + uint32_t sec = addr / _flashchip->sector_size; + uint32_t cnt = size / _flashchip->sector_size; + uint32_t sec_per_block = _flashchip->block_size / _flashchip->sector_size; + + while (cnt && result == ESP_ROM_SPIFLASH_RESULT_OK) { + /* disable interrupts and the cache */ + critical_enter(); + Cache_Read_Disable(PRO_CPU_NUM); + + /* erase block-wise (64 kByte) if cnt is at least sec_per_block */ + if (cnt >= sec_per_block) { + result = esp_rom_spiflash_erase_block (sec / sec_per_block); + sec += sec_per_block; + cnt -= sec_per_block; + } + else { + result = esp_rom_spiflash_erase_sector (sec++); + cnt--; + } + + /* enable interrupts and the cache */ + Cache_Read_Enable(PRO_CPU_NUM); + critical_exit(); + } + + /* reset write access */ + esp_rom_spiflash_lock(); + + /* return with the ESP-IDF error code that is mapped from ROM error code */ + RETURN_WITH_ESP_ERR_CODE(result); +} + +#endif /* MCU_ESP32 */ + +const esp_partition_t* esp_partition_find_first(esp_partition_type_t type, + esp_partition_subtype_t subtype, + const char* label) +{ + uint32_t info_addr = ESP_PART_TABLE_ADDR; + uint8_t info_buf[ESP_PART_ENTRY_SIZE]; + bool info_read = true; + + esp_partition_info_t* info = (esp_partition_info_t*)info_buf; + esp_partition_t* part; + + while (info_read && info_addr < ESP_PART_TABLE_ADDR + ESP_PART_TABLE_SIZE) { + spi_flash_read (info_addr, (void*)info_buf, ESP_PART_ENTRY_SIZE); + + if (info->magic == ESP_PART_ENTRY_MAGIC) { + DEBUG("%s partition @%08x size=%08x label=%s\n", __func__, + info->pos.offset, info->pos.size, info->label); + if ((info->type == type) && + (info->subtype == subtype || subtype == ESP_PARTITION_SUBTYPE_ANY) && + (label == NULL || strcmp((const char*)info->label, label) == 0)) { + part = malloc(sizeof(esp_partition_t)); + part->type = info->type; + part->subtype = info->subtype; + part->address = info->pos.offset; + part->size = info->pos.size; + part->encrypted = info->flags & PART_FLAG_ENCRYPTED; + strncpy(part->label, (const char*)info->label, sizeof(info->label)); + part->label[sizeof(part->label) - 1] = 0x0; + + return part; + } + info_addr += ESP_PART_ENTRY_SIZE; + } + else { + info_read = false; + } + } + return NULL; +} + +esp_err_t esp_partition_erase_range(const esp_partition_t* part, + size_t addr, size_t size) +{ + CHECK_PARAM_RET(part != NULL, ESP_ERR_INVALID_ARG); + + /* start addr and size must be inside the partition */ + CHECK_PARAM_RET(addr <= part->size, ESP_ERR_INVALID_ARG); + CHECK_PARAM_RET(addr + size <= part->size, ESP_ERR_INVALID_SIZE); + /* start addr and size must be a multiple of sector size */ + CHECK_PARAM_RET(addr % SPI_FLASH_SEC_SIZE == 0, ESP_ERR_INVALID_ARG); + CHECK_PARAM_RET(size % SPI_FLASH_SEC_SIZE == 0, ESP_ERR_INVALID_SIZE); + + return spi_flash_erase_range(part->address + addr, size); +} + + +static int _flash_init (mtd_dev_t *dev) +{ + DEBUG("%s dev=%p driver=%p\n", __func__, dev, &_flash_driver); + + CHECK_PARAM_RET (dev == &_flash_dev, -ENODEV); + + if (_flashchip->chip_size <= _flash_beg) { + LOG_ERROR("Flash size is equal or less than %d Byte, " + "SPIFFS cannot be used\n", _flash_beg); + return -ENODEV; + } + + return 0; +} + +static int _flash_read (mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size) +{ + DEBUG("%s dev=%p addr=%08x size=%u buf=%p\n", __func__, dev, addr, size, buff); + + CHECK_PARAM_RET (dev == &_flash_dev, -ENODEV); + CHECK_PARAM_RET (buff != NULL, -ENOTSUP); + + /* size must be within the flash address space */ + CHECK_PARAM_RET (_flash_beg + addr + size <= _flash_end, -EOVERFLOW); + + return (spi_flash_read(_flash_beg + addr, buff, size) == ESP_OK) ? (int)size : -EIO; +} + +static int _flash_write (mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size) +{ + DEBUG("%s dev=%p addr=%08x size=%u buf=%p\n", __func__, dev, addr, size, buff); + + CHECK_PARAM_RET (dev == &_flash_dev, -ENODEV); + CHECK_PARAM_RET (buff != NULL, -ENOTSUP); + + /* size must be within the flash address space */ + CHECK_PARAM_RET (_flash_beg + addr + size <= _flash_end, -EOVERFLOW); + + /* addr + size must be within a page */ + CHECK_PARAM_RET (size <= _flashchip->page_size, -EOVERFLOW); + CHECK_PARAM_RET ((addr % _flashchip->page_size) + size <= _flashchip->page_size, -EOVERFLOW); + + return (spi_flash_write(_flash_beg + addr, buff, size) == ESP_OK) ? (int)size : -EIO; } static int _flash_erase (mtd_dev_t *dev, uint32_t addr, uint32_t size) @@ -249,34 +538,10 @@ static int _flash_erase (mtd_dev_t *dev, uint32_t addr, uint32_t size) CHECK_PARAM_RET (_flash_beg + addr + size <= _flash_end, -EOVERFLOW); /* size must be a multiple of sector_size && at least one sector */ - CHECK_PARAM_RET (size >= flashchip->sector_size, -ENOTSUP); - CHECK_PARAM_RET (size % flashchip->sector_size == 0, -ENOTSUP) - - #ifndef SDK_FLASH_FUNCTIONS - bool result = false; - uint32_t count = size / flashchip->sector_size; - while (count--) { - uint32_t sec = _flash_beg + addr + count * flashchip->sector_size; - if (!(result = spiflash_erase_sector (sec))) { - break; - } - } - return result ? 0 : -EIO; - #else - critical_enter(); - - uint32_t result = SPI_FLASH_RESULT_OK; - uint32_t count = size / flashchip->sector_size; - while (count--) { - uint32_t sec = (_flash_beg + addr) / flashchip->sector_size + count; - if ((result = spi_flash_erase_sector (sec)) != SPI_FLASH_RESULT_OK) { - break; - } - } + CHECK_PARAM_RET (size >= _flashchip->sector_size, -EOVERFLOW); + CHECK_PARAM_RET (size % _flashchip->sector_size == 0, -EOVERFLOW) - critical_exit(); - return result; - #endif + return (spi_flash_erase_range(_flash_beg + addr, size) == ESP_OK) ? 0 : -EIO; } static int _flash_power (mtd_dev_t *dev, enum mtd_power_state power) @@ -285,3 +550,5 @@ static int _flash_power (mtd_dev_t *dev, enum mtd_power_state power) return -ENOTSUP; } + +#endif /* MODULE_MTD */ diff --git a/cpu/esp8266/periph/gpio.c b/cpu/esp8266/periph/gpio.c index 5608fad8840a..4a538436ff72 100644 --- a/cpu/esp8266/periph/gpio.c +++ b/cpu/esp8266/periph/gpio.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -26,17 +26,17 @@ #include "log.h" #include "periph/gpio.h" /* RIOT gpio.h */ -#include "c_types.h" -#include "eagle_soc.h" -#include "ets_sys.h" +#include "esp8266/eagle_soc.h" +#include "esp8266/gpio_register.h" +#include "rom/ets_sys.h" #include "sdk/ets.h" #include "esp/gpio_regs.h" #include "esp/iomux_regs.h" #include "esp/rtc_regs.h" -#include "common.h" -#include "gpio_common.h" +#include "esp_common.h" +#include "gpio_arch.h" #include "irq_arch.h" #include "syscalls.h" @@ -48,7 +48,7 @@ const uint8_t _gpio_to_iomux[] = { 12, 5, 13, 4, 14, 15, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3 }; const uint8_t _iomux_to_gpio[] = { 12, 13, 14, 15, 3, 1, 6, 7, 8, 9, 10, 11, 0, 2, 4, 5 }; -_gpio_pin_usage_t _gpio_pin_usage [GPIO_PIN_NUMOF] = +gpio_pin_usage_t _gpio_pin_usage [GPIO_PIN_NUMOF] = { _GPIO, /* gpio0 */ @@ -75,6 +75,12 @@ _gpio_pin_usage_t _gpio_pin_usage [GPIO_PIN_NUMOF] = _GPIO /* gpio16 */ }; +/* String representation of usage types */ +const char* _gpio_pin_usage_str[] = +{ + "GPIO", "I2C", "PWM", "SPI", "SPI Flash", "UART", "N/A" +}; + int gpio_init(gpio_t pin, gpio_mode_t mode) { DEBUG("%s: %d %d\n", __func__, pin, mode); @@ -285,3 +291,20 @@ void gpio_toggle (gpio_t pin) GPIO.OUT ^= BIT(pin); } + +int gpio_set_pin_usage(gpio_t pin, gpio_pin_usage_t usage) +{ + CHECK_PARAM_RET(pin < GPIO_PIN_NUMOF, -1); + _gpio_pin_usage [pin] = usage; + return 0; +} + +gpio_pin_usage_t gpio_get_pin_usage (gpio_t pin) +{ + return (pin < GPIO_PIN_NUMOF) ? _gpio_pin_usage[pin] : _NOT_EXIST; +} + +const char* gpio_get_pin_usage_str(gpio_t pin) +{ + return _gpio_pin_usage_str[_gpio_pin_usage[((pin < GPIO_PIN_NUMOF) ? pin : _NOT_EXIST)]]; +} diff --git a/cpu/esp8266/periph/hwrng.c b/cpu/esp8266/periph/hwrng.c index 4696810e63a3..3984e309de87 100644 --- a/cpu/esp8266/periph/hwrng.c +++ b/cpu/esp8266/periph/hwrng.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -22,8 +22,13 @@ #include "cpu.h" #include "periph_conf.h" #include "periph/hwrng.h" +#include "rom/ets_sys.h" -#include "esp/wdev_regs.h" +#ifdef MCU_ESP32 +static const uint32_t* RNG_DATA_REG = (uint32_t*)0x3ff75144; +#else +static const uint32_t* RNG_DATA_REG = (uint32_t*)0x3ff20e44; +#endif void hwrng_init(void) { @@ -37,7 +42,7 @@ void hwrng_read(void *buf, unsigned int num) while (count < num) { /* read next 4 bytes of random data */ - uint32_t tmp = WDEV.HWRNG; + uint32_t tmp = *RNG_DATA_REG; /* copy data into result vector */ for (int i = 0; i < 4 && count < num; i++) { diff --git a/cpu/esp8266/periph/i2c.c b/cpu/esp8266/periph/i2c.c index 5a21624b761a..d7608fc51d09 100644 --- a/cpu/esp8266/periph/i2c.c +++ b/cpu/esp8266/periph/i2c.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -7,8 +7,8 @@ */ /** - * @ingroup cpu_esp8266 - * @ingroup drivers_periph_i2c + * @ingroup cpu_esp8266 + * @ingroup drivers_periph_i2c * @{ * * @file @@ -22,18 +22,16 @@ /* PLEASE NOTE: - Some parts of the implementation bases on the bit-banging implementation as - described in [wikipedia](https://en.wikipedia.org/wiki/I%C2%B2C) as well as - its implementation in [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos.git). - These parts are under the copyright of their respective owners. + The implementation bases on the bit-banging I2C master implementation as + described in [wikipedia](https://en.wikipedia.org/wiki/I%C2%B2C#Example_of_bit-banging_the_I%C2%B2C_master_protocol). */ #define ENABLE_DEBUG (0) #include "debug.h" #include -#include #include +#include #include "cpu.h" #include "log.h" @@ -42,20 +40,36 @@ #include "periph/gpio.h" #include "periph/i2c.h" -#include "common.h" +#include "esp_common.h" +#include "gpio_arch.h" +#include "rom/ets_sys.h" + +#ifdef MCU_ESP32 + +#include "soc/gpio_reg.h" +#include "soc/gpio_struct.h" + +/* max clock stretching counter */ +#define I2C_CLOCK_STRETCH 200 + +/* gpio access macros */ +#define GPIO_SET(l,h,b) if (b < 32) GPIO.l = BIT(b); else GPIO.h.val = BIT(32-b) +#define GPIO_GET(l,h,b) ((b < 32) ? GPIO.l & BIT(b) : GPIO.h.val & BIT(32-b)) + +#else /* MCU_ESP32 */ #include "esp/gpio_regs.h" #include "sdk/ets.h" -#if defined(I2C_NUMOF) && I2C_NUMOF > 0 +/* max clock stretching counter (ca. 10 ms) */ +#define I2C_CLOCK_STRETCH 40000 -/* has to be declared as extern since it is not possible to include */ -/* user_interface.h due to conflicts with gpio_init */ +/* following functions have to be declared as extern since it is not possible */ +/* to include user_interface.h due to conflicts with gpio_init */ extern uint8_t system_get_cpu_freq(void); extern bool system_update_cpu_freq(uint8_t freq); -/* max clock stretching counter (ca. 10 ms) */ -#define I2C_CLOCK_STRETCH 40000 +#endif /* MCU_ESP32 */ typedef struct { @@ -71,50 +85,42 @@ typedef struct uint32_t sda_bit; /* gpio bit mask for faster access */ uint32_t delay; + mutex_t lock; } _i2c_bus_t; -static _i2c_bus_t _i2c_bus[] = -{ - #if defined(I2C0_SDA) && defined(I2C0_SCL) - { - .speed = I2C0_SPEED, - .sda = I2C0_SDA, - .scl = I2C0_SCL - }, - #endif - #if defined(I2C1_SDA) && defined(I2C1_SCL) - { - .speed = I2C1_SPEED, - .sda = I2C1_SDA, - .scl = I2C1_SCL - }, - #endif - #if defined(I2C2_SDA) && defined(I2C2_SCL) - { - .speed = I2C2_SPEED, - .sda = I2C2_SDA, - .scl = I2C2_SCL - }, - #endif -}; +static _i2c_bus_t _i2c_bus[I2C_NUMOF] = {}; /* to ensure that I2C is always optimized with -O2 to use the defined delays */ #pragma GCC optimize ("O2") +#ifdef MCU_ESP32 +static const uint32_t _i2c_delays[][3] = +{ + /* values specify one half-period and are only valid for -O2 option */ + /* value = [period - 0.25 us (240 MHz) / 0.5us(160MHz) / 1.0us(80MHz)] */ + /* * cycles per second / 2 */ + /* 1 us = 16 cycles (80 MHz) / 32 cycles (160 MHz) / 48 cycles (240) */ + /* values for 80, 160, 240 MHz */ + [I2C_SPEED_LOW] = {790, 1590, 2390}, /* 10 kbps (period 100 us) */ + [I2C_SPEED_NORMAL] = { 70, 150, 230}, /* 100 kbps (period 10 us) */ + [I2C_SPEED_FAST] = { 11, 31, 51}, /* 400 kbps (period 2.5 us) */ + [I2C_SPEED_FAST_PLUS] = { 0, 7, 15}, /* 1 Mbps (period 1 us) */ + [I2C_SPEED_HIGH] = { 0, 0, 0} /* 3.4 Mbps (period 0.3 us) not working */ +}; +#else /* MCU_ESP32 */ static const uint32_t _i2c_delays[][2] = { - /* values specify one half-period and are only valid for -O2 option */ + /* values specify one half-period and are only valid for -O2 option */ /* value = [period - 0.5us(160MHz) or 1.0us(80MHz)] * cycles per second / 2 */ - /* cycles per us = ca. 20 (80 MHz) / ca. 40 (160 MHz) */ - [I2C_SPEED_LOW] = {1990, 989}, /* 10 kbps (period 100 us) */ - [I2C_SPEED_NORMAL] = { 190, 89}, /* 100 kbps (period 10 us) */ - [I2C_SPEED_FAST] = { 40, 16}, /* 400 kbps (period 2.5 us) */ - [I2C_SPEED_FAST_PLUS] = { 13, 0}, /* 1 Mbps (period 1 us) */ + /* 1 us = 20 cycles (80 MHz) / 40 cycles (160 MHz) */ + [I2C_SPEED_LOW] = {989, 1990}, /* 10 kbps (period 100 us) */ + [I2C_SPEED_NORMAL] = { 89, 190}, /* 100 kbps (period 10 us) */ + [I2C_SPEED_FAST] = { 16, 40}, /* 400 kbps (period 2.5 us) */ + [I2C_SPEED_FAST_PLUS] = { 0, 13}, /* 1 Mbps (period 1 us) */ [I2C_SPEED_HIGH] = { 0, 0} /* 3.4 Mbps (period 0.3 us) is not working */ }; - -static mutex_t i2c_bus_lock[I2C_NUMOF] = { MUTEX_INIT }; +#endif /* MCU_ESP32 */ /* forward declaration of internal functions */ @@ -136,51 +142,86 @@ static void _i2c_abort (_i2c_bus_t* bus, const char* func); static void _i2c_clear (_i2c_bus_t* bus); /* implementation of i2c interface */ + void i2c_init(i2c_t dev) { - if (I2C_NUMOF != ARRAY_SIZE(_i2c_bus)) { - LOG_INFO("I2C_NUMOF does not match number of I2C_SDA_x/I2C_SCL_x definitions\n"); - LOG_INFO("Please check your board configuration in 'board.h'\n"); - assert(I2C_NUMOF < ARRAY_SIZE(_i2c_bus)); + assert(dev < I2C_NUMOF_MAX); + assert(dev < I2C_NUMOF); + if (i2c_config[dev].speed == I2C_SPEED_HIGH) { + LOG_TAG_INFO("i2c", "I2C_SPEED_HIGH is not supported\n"); return; } - CHECK_PARAM (dev < I2C_NUMOF) + mutex_init(&_i2c_bus[dev].lock); - if (_i2c_bus[dev].speed == I2C_SPEED_HIGH) { - LOG_INFO("I2C_SPEED_HIGH is not supported\n"); - return; - } - - i2c_acquire (dev); + _i2c_bus[dev].scl = i2c_config[dev].scl; + _i2c_bus[dev].sda = i2c_config[dev].sda; + _i2c_bus[dev].speed = i2c_config[dev].speed; _i2c_bus[dev].dev = dev; - _i2c_bus[dev].delay =_i2c_delays[_i2c_bus[dev].speed][ets_get_cpu_frequency() == 80 ? 1 : 0]; _i2c_bus[dev].scl_bit = BIT(_i2c_bus[dev].scl); /* store bit mask for faster access */ _i2c_bus[dev].sda_bit = BIT(_i2c_bus[dev].sda); /* store bit mask for faster access */ _i2c_bus[dev].started = false; /* for handling of repeated start condition */ - DEBUG ("%s: scl=%d sda=%d speed=%d\n", __func__, - _i2c_bus[dev].scl, _i2c_bus[dev].sda, _i2c_bus[dev].speed); + switch (ets_get_cpu_frequency()) { + case 80: _i2c_bus[dev].delay = _i2c_delays[_i2c_bus[dev].speed][0]; break; + case 160: _i2c_bus[dev].delay = _i2c_delays[_i2c_bus[dev].speed][1]; break; +#ifdef MCU_ESP32 + case 240: _i2c_bus[dev].delay = _i2c_delays[_i2c_bus[dev].speed][2]; break; +#endif + default : LOG_TAG_INFO("i2c", "I2C software implementation is not " + "supported for this CPU frequency: %d MHz\n", + ets_get_cpu_frequency()); + return; + } + + DEBUG("%s: scl=%d sda=%d speed=%d\n", __func__, + _i2c_bus[dev].scl, _i2c_bus[dev].sda, _i2c_bus[dev].speed); + /* reset the GPIO usage if the pins were used for I2C before */ + if (gpio_get_pin_usage(_i2c_bus[dev].scl) == _I2C) { + gpio_set_pin_usage(_i2c_bus[dev].scl, _GPIO); + } + if (gpio_get_pin_usage(_i2c_bus[dev].sda) == _I2C) { + gpio_set_pin_usage(_i2c_bus[dev].sda, _GPIO); + } + + /* Configure and initialize SDA and SCL pin. */ +#ifdef MCU_ESP32 + /* + * ESP32 pins are used in input/output mode with open-drain output driver. + * Signal levels are then realized as following: + * + * - HIGH: Output value 1 lets the pin floating and is pulled-up to high. + * - LOW : Output value 0 actively drives the pin to low. + */ + if (gpio_init(_i2c_bus[dev].scl, GPIO_IN_OD_PU) || + gpio_init(_i2c_bus[dev].sda, GPIO_IN_OD_PU)) { + return; + } +#else /* MCU_ESP32 */ /* - * Configure and initialize SDA and SCL pin. - * Note: Due to critical timing required by the I2C software - * implementation, the ESP8266 GPIOs can not be used directly in GPIO_OD_PU - * mode. Instead, the GPIOs are configured in GPIO_IN_PU mode with - * open-drain output driver. Signal levels are then realized as following: + * Due to critical timing required by the I2C software implementation, + * the ESP8266 GPIOs can not be used directly in GPIO_OD_PU mode. + * Instead, the GPIOs are configured in GPIO_IN_PU mode with open-drain + * output driver. Signal levels are then realized as following: * * - HIGH: The GPIO is used in the configured GPIO_IN_PU mode. In this * mode, the output driver is in open-drain mode and pulled-up. * - LOW : The GPIO is temporarily switched to GPIO_OD_PU mode. In this * mode, the output value 0, which is written during - * initialization, actively drives the output to low. + * initialization, actively drives the pin to low. */ - gpio_init (_i2c_bus[dev].scl, GPIO_IN_PU); - gpio_init (_i2c_bus[dev].sda, GPIO_IN_PU); - gpio_clear (_i2c_bus[dev].scl); - gpio_clear (_i2c_bus[dev].sda); + if (gpio_init(_i2c_bus[dev].scl, GPIO_IN_PU) || + gpio_init(_i2c_bus[dev].sda, GPIO_IN_PU)) { + return; + } +#endif /* MCU_ESP32 */ + + /* store the usage type in GPIO table */ + gpio_set_pin_usage(_i2c_bus[dev].scl, _I2C); + gpio_set_pin_usage(_i2c_bus[dev].sda, _I2C); /* set SDA and SCL to be floating and pulled-up to high */ _i2c_sda_high (&_i2c_bus[dev]); @@ -189,16 +230,14 @@ void i2c_init(i2c_t dev) /* clear the bus if necessary (SDA is driven permanently low) */ _i2c_clear (&_i2c_bus[dev]); - i2c_release (dev); - return; } int i2c_acquire(i2c_t dev) { - CHECK_PARAM_RET (dev < I2C_NUMOF, -1) + assert(dev < I2C_NUMOF); - mutex_lock(&i2c_bus_lock[dev]); + mutex_lock(&_i2c_bus[dev].lock); return 0; } @@ -206,7 +245,7 @@ void i2c_release(i2c_t dev) { assert(dev < I2C_NUMOF); - mutex_unlock(&i2c_bus_lock[dev]); + mutex_unlock(&_i2c_bus[dev].lock); } int /* IRAM */ i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len, uint8_t flags) @@ -214,7 +253,8 @@ int /* IRAM */ i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len, DEBUG ("%s: dev=%u addr=%02x data=%p len=%d flags=%01x\n", __func__, dev, addr, data, len, flags); - CHECK_PARAM_RET (dev < I2C_NUMOF, -EINVAL); + assert(dev < I2C_NUMOF); + CHECK_PARAM_RET (len > 0, -EINVAL); CHECK_PARAM_RET (data != NULL, -EINVAL); @@ -235,7 +275,7 @@ int /* IRAM */ i2c_read_bytes(i2c_t dev, uint16_t addr, void *data, size_t len, /* prepare 10 bit address bytes */ uint8_t addr1 = 0xf0 | (addr & 0x0300) >> 7 | I2C_READ; uint8_t addr2 = addr & 0xff; - /* send address bytes wit read flag */ + /* send address bytes with read flag */ if ((res = _i2c_write_byte (bus, addr1)) != 0 || (res = _i2c_write_byte (bus, addr2)) != 0) { /* abort transfer */ @@ -275,7 +315,8 @@ int /* IRAM */ i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_ DEBUG ("%s: dev=%u addr=%02x data=%p len=%d flags=%01x\n", __func__, dev, addr, data, len, flags); - CHECK_PARAM_RET (dev < I2C_NUMOF, -EINVAL); + assert(dev < I2C_NUMOF); + CHECK_PARAM_RET (len > 0, -EINVAL); CHECK_PARAM_RET (data != NULL, -EINVAL); @@ -348,74 +389,99 @@ void i2c_poweroff(i2c_t dev) static inline void _i2c_delay (_i2c_bus_t* bus) { /* produces a delay */ - /* ca. 20 cycles = 1 us (80 MHz) or ca. 40 cycles = 1 us (160 MHz) */ - uint32_t cycles = bus->delay; if (cycles) { - __asm__ volatile ("1: _addi.n %0, %0, -1 \n" - " bnez %0, 1b \n" : "=r" (cycles) : "0" (cycles)); + __asm__ volatile ("1: _addi.n %0, %0, -1 \n" + " bnez %0, 1b \n" : "=r" (cycles) : "0" (cycles)); } } /* - * Note: Due to critical timing required by the I2C software implementation, - * the ESP8266 GPIOs can not be used directly in GPIO_OD_PU mode. Instead, - * the GPIOs are configured in GPIO_IN_PU mode with open-drain output driver. - * Signal levels are then realized as following: + * Please note: SDA and SDL pins are used in GPIO_OD_PU mode + * (open-drain with pull-ups). * - * - HIGH: The GPIO is used in the configured GPIO_IN_PU mode. In this mode, - * the output driver is in open-drain mode and pulled-up. - * - LOW : The GPIO is temporarily switched to GPIO_OD_PU mode. In this mode, - * the output value 0, which is written during initialization, - * actively drives the output to low. + * Setting a pin which is in open-drain mode leaves the pin floating and + * the signal is pulled up to high. The signal can then be actively driven + * to low by a slave. A read operation returns the current signal at the pin. + * + * Clearing a pin which is in open-drain mode actively drives the signal to + * low. */ static inline bool _i2c_scl_read(_i2c_bus_t* bus) { - /* read SCL status */ + /* read SCL status (pin is in open-drain mode and set) */ +#ifdef MCU_ESP32 + return GPIO_GET(in, in1, bus->scl); +#else /* MCU_ESP32 */ return GPIO.IN & bus->scl_bit; +#endif /* MCU_ESP32 */ } static inline bool _i2c_sda_read(_i2c_bus_t* bus) { - /* read SDA status */ + /* read SDA status (pin is in open-drain mode and set) */ +#ifdef MCU_ESP32 + return GPIO_GET(in, in1, bus->sda); +#else /* MCU_ESP32 */ return GPIO.IN & bus->sda_bit; -} - -static inline void _i2c_scl_low(_i2c_bus_t* bus) -{ - /* - * set SCL signal low (switch temporarily to GPIO_OD_PU where the - * written output value 0 drives the pin actively to low) - */ - GPIO.ENABLE_OUT_SET = bus->scl_bit; +#endif /* MCU_ESP32 */ } static inline void _i2c_scl_high(_i2c_bus_t* bus) { +#ifdef MCU_ESP32 + /* set SCL signal high (pin is in open-drain mode and pulled-up) */ + GPIO_SET(out_w1ts, out1_w1ts, bus->scl); +#else /* MCU_ESP32 */ /* * set SCL signal high (switch back to GPIO_IN_PU mode, that is the pin is * in open-drain mode and pulled-up to high) */ GPIO.ENABLE_OUT_CLEAR = bus->scl_bit; +#endif /* MCU_ESP32 */ } -static inline void _i2c_sda_low(_i2c_bus_t* bus) +static inline void _i2c_scl_low(_i2c_bus_t* bus) { +#ifdef MCU_ESP32 + /* set SCL signal low (actively driven to low) */ + GPIO_SET(out_w1tc, out1_w1tc, bus->scl); +#else /* MCU_ESP32 */ /* - * set SDA signal low (switch temporarily to GPIO_OD_PU where the + * set SCL signal low (switch temporarily to GPIO_OD_PU where the * written output value 0 drives the pin actively to low) */ - GPIO.ENABLE_OUT_SET = bus->sda_bit; + GPIO.ENABLE_OUT_SET = bus->scl_bit; +#endif /* MCU_ESP32 */ } static inline void _i2c_sda_high(_i2c_bus_t* bus) { +#ifdef MCU_ESP32 + /* set SDA signal high (pin is in open-drain mode and pulled-up) */ + GPIO_SET(out_w1ts, out1_w1ts, bus->sda); +#else /* MCU_ESP32 */ /* * set SDA signal high (switch back to GPIO_IN_PU mode, that is the pin is * in open-drain mode and pulled-up to high) */ GPIO.ENABLE_OUT_CLEAR = bus->sda_bit; +#endif /* MCU_ESP32 */ +} + +static inline void _i2c_sda_low(_i2c_bus_t* bus) +{ +#ifdef MCU_ESP32 + /* set SDA signal low (actively driven to low) */ + GPIO_SET(out_w1tc, out1_w1tc, bus->sda); +#else /* MCU_ESP32 */ + /* + * set SDA signal low (switch temporarily to GPIO_OD_PU where the + * written output value 0 drives the pin actively to low) + */ + GPIO.ENABLE_OUT_SET = bus->sda_bit; +#endif /* MCU_ESP32 */ } static void _i2c_clear(_i2c_bus_t* bus) @@ -500,7 +566,7 @@ static /* IRAM */ int _i2c_start_cond(_i2c_bus_t* bus) /* SDA = passive HIGH (floating and pulled-up) */ _i2c_sda_high (bus); - /* t_VD;DAT not neccessary */ + /* t_VD;DAT not necessary */ /* _i2c_delay (bus); */ /* SCL = passive HIGH (floating and pulled-up) */ @@ -724,7 +790,7 @@ static /* IRAM */ int _i2c_read_byte(_i2c_bus_t* bus, uint8_t *byte, bool ack) if (res != 0) { return res; } - *byte = (*byte << 1) | bit; + *byte = (*byte << 1) | (bit ? 1 : 0); } /* write acknowledgement flag */ @@ -735,17 +801,8 @@ static /* IRAM */ int _i2c_read_byte(_i2c_bus_t* bus, uint8_t *byte, bool ack) void i2c_print_config(void) { - for (unsigned bus = 0; bus < I2C_NUMOF; bus++) { - LOG_INFO("\tI2C_DEV(%d): scl=%d sda=%d\n", - bus, _i2c_bus[bus].scl, _i2c_bus[bus].sda); + for (unsigned dev = 0; dev < I2C_NUMOF; dev++) { + printf("\tI2C_DEV(%u)\tscl=%d sda=%d\n", + dev, i2c_config[dev].scl, i2c_config[dev].sda); } } - -#else /* if defined(I2C_NUMOF) && I2C_NUMOF */ - -void i2c_print_config(void) -{ - LOG_INFO("\tI2C: no devices\n"); -} - -#endif /* if defined(I2C_NUMOF) && I2C_NUMOF */ diff --git a/cpu/esp8266/periph/pm.c b/cpu/esp8266/periph/pm.c index 8b07a4eb73a8..94c71457e42a 100644 --- a/cpu/esp8266/periph/pm.c +++ b/cpu/esp8266/periph/pm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -18,31 +18,28 @@ * @} */ -#define ENABLE_DEBUG 0 +#define ENABLE_DEBUG (0) #include "debug.h" -#include - -#include "irq.h" - -#include "esp/xtensa_ops.h" -#include "sdk/ets_task.h" #include "sdk/sdk.h" - #include "syscalls.h" void pm_set_lowest(void) { - DEBUG ("%s\n", __func__); + DEBUG ("%s enter to sleep @%u\n", __func__, system_get_time()); - #if !defined(QEMU) - DEBUG ("%s enter to sleep @%u\n", __func__, phy_get_mactime()); + /* reset system watchdog timer */ + system_wdt_feed(); + #ifndef MODULE_ESP_QEMU /* passive wait for interrupt to leave lowest power mode */ __asm__ volatile ("waiti 0"); - - DEBUG ("%s exit from sleep @%u\n", __func__, phy_get_mactime()); #endif + + DEBUG ("%s exit from sleep @%u\n", __func__, system_get_time()); + + /* reset system watchdog timer */ + system_wdt_feed(); } void pm_off(void) diff --git a/cpu/esp8266/periph/pwm.c b/cpu/esp8266/periph/pwm.c index 58f7437ab928..c8ff89b6b6c7 100644 --- a/cpu/esp8266/periph/pwm.c +++ b/cpu/esp8266/periph/pwm.c @@ -18,7 +18,7 @@ * @} */ -#define ENABLE_DEBUG 0 +#define ENABLE_DEBUG (0) #include "debug.h" #include "cpu.h" @@ -27,21 +27,19 @@ #include "periph/pwm.h" #include "periph/gpio.h" -#include "common.h" +#include "esp_common.h" #include "esp/iomux_regs.h" #include "esp/timer_regs.h" -#include "gpio_common.h" -#include "sdk/ets.h" - -#if defined(PWM_NUMOF) && PWM_NUMOF > 0 +#include "gpio_arch.h" +#include "sdk/sdk.h" +#include "xtensa/xtensa_api.h" #define TIMER_FRC1_CLKDIV_16 BIT(2) #define TIMER_FRC1_CLKDIV_256 BIT(3) -#define ETS_FRC1_INT_ENABLE ETS_FRC1_INTR_ENABLE -#define ETS_FRC1_INT_DISABLE ETS_FRC1_INTR_DISABLE -#define ETS_FRC1_INT_ATTACH ETS_FRC_TIMER1_INTR_ATTACH -#define ETS_FRC1_NMI_ATTACH ETS_FRC_TIMER1_NMI_INTR_ATTACH +#define ETS_FRC1_INT_ENABLE() xt_ints_on(BIT(ETS_FRC_TIMER1_INUM)) +#define ETS_FRC1_INT_DISABLE() xt_ints_off(BIT(ETS_FRC_TIMER1_INUM)) +#define ETS_FRC1_INT_ATTACH(f, a) xt_set_interrupt_handler(ETS_FRC_TIMER1_INUM, f, a) typedef struct { @@ -65,8 +63,6 @@ typedef struct static _pwm_dev_t _pwm_dev; -static const uint32_t _pwm_channel_gpios[] = PWM0_CHANNEL_GPIOS; - static void _pwm_timer_handler (void* arg) { irq_isr_enter (); @@ -119,14 +115,15 @@ uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res) { DEBUG ("%s pwm=%u mode=%u freq=%u, res=%u\n", __func__, pwm, mode, freq, res); - uint8_t _pwm_channel_gpio_num = sizeof(_pwm_channel_gpios) >> 2; + uint8_t _pwm_channel_gpio_num = sizeof(pwm0_channels) >> 2; - CHECK_PARAM_RET (pwm < PWM_NUMOF, 0); - CHECK_PARAM_RET (freq > 0, 0); - CHECK_PARAM_RET (_pwm_channel_gpio_num <= PWM_CHANNEL_NUM_MAX, 0); + assert(pwm < PWM_NUMOF_MAX); + assert(pwm < PWM_NUMOF); + assert(freq > 0); + assert(_pwm_channel_gpio_num <= PWM_CHANNEL_NUM_MAX); /* maximum number of cycles per second (freq*res) should not be greater than */ - /* 100.000 (period of 10 us), reduce freq if neccessary and keep resolution */ + /* 100.000 (period of 10 us), reduce freq if necessary and keep resolution */ if (res * freq > PWM_MAX_CPS) { freq = PWM_MAX_CPS / res; } @@ -138,21 +135,21 @@ uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res) _pwm_dev.mode = mode; for (int i = 0; i < _pwm_channel_gpio_num; i++) { - if (_gpio_pin_usage[_pwm_channel_gpios[i]] != _GPIO) { + if (gpio_get_pin_usage(pwm0_channels[i]) != _GPIO) { LOG_ERROR("GPIO%d is used for something else and cannot be used as PWM output\n", i); return 0; } - if (gpio_init(_pwm_channel_gpios[i], GPIO_OUT) < 0) { + if (gpio_init(pwm0_channels[i], GPIO_OUT) < 0) { return 0; } - gpio_clear (_pwm_channel_gpios[i]); + gpio_clear (pwm0_channels[i]); _pwm_dev.chn[_pwm_dev.chn_num].duty = 0; _pwm_dev.chn[_pwm_dev.chn_num].next_on = 0; _pwm_dev.chn[_pwm_dev.chn_num].next_off = 0; - _pwm_dev.chn[_pwm_dev.chn_num].gpio = _pwm_channel_gpios[i]; + _pwm_dev.chn[_pwm_dev.chn_num].gpio = pwm0_channels[i]; _pwm_dev.chn_num++; } @@ -169,7 +166,7 @@ uint32_t pwm_init(pwm_t pwm, pwm_mode_t mode, uint32_t freq, uint16_t res) uint8_t pwm_channels(pwm_t pwm) { - CHECK_PARAM_RET (pwm < PWM_NUMOF, 0); + assert(pwm < PWM_NUMOF); return _pwm_dev.chn_num; } @@ -178,9 +175,9 @@ void pwm_set(pwm_t pwm, uint8_t channel, uint16_t value) { DEBUG("%s pwm=%u channel=%u value=%u\n", __func__, pwm, channel, value); - CHECK_PARAM (pwm < PWM_NUMOF); - CHECK_PARAM (channel < _pwm_dev.chn_num); - CHECK_PARAM (value <= _pwm_dev.res); + assert(pwm < PWM_NUMOF); + assert(channel < _pwm_dev.chn_num); + assert(value <= _pwm_dev.res); uint32_t state = irq_disable(); uint32_t phase = _pwm_dev.cycles - _pwm_dev.cycles % _pwm_dev.res; @@ -226,25 +223,16 @@ void pwm_poweron(pwm_t pwm) void pwm_poweroff(pwm_t pwm) { - CHECK_PARAM (pwm < PWM_NUMOF); + assert(pwm < PWM_NUMOF); _pwm_stop (); } void pwm_print_config(void) { - LOG_INFO("\tPWM_DEV(0): channels=[ "); - for (unsigned i = 0; i < sizeof(_pwm_channel_gpios) >> 2; i++) { - LOG_INFO("%d ", _pwm_channel_gpios[i]); + printf("\tPWM_DEV(0)\tchannels=[ "); + for (unsigned i = 0; i < sizeof(pwm0_channels) >> 2; i++) { + printf("%d ", pwm0_channels[i]); } - LOG_INFO("]\n"); -} - -#else /* defined(PWM_NUMOF) && PWM_NUMOF > 0 */ - -void pwm_print_config(void) -{ - LOG_INFO("\tPWM: no devices\n"); + printf("]\n"); } - -#endif /* defined(PWM_NUMOF) && PWM_NUMOF > 0 */ diff --git a/cpu/esp8266/periph/rtc.c b/cpu/esp8266/periph/rtc.c index cfdabca47a7a..5a306d2fde50 100644 --- a/cpu/esp8266/periph/rtc.c +++ b/cpu/esp8266/periph/rtc.c @@ -26,9 +26,9 @@ #include "log.h" #include "periph/rtc.h" -#include "common.h" +#include "esp_common.h" -#include "sdk/ets.h" +#include "sdk/sdk.h" void rtc_init(void) { diff --git a/cpu/esp8266/periph/spi.c b/cpu/esp8266/periph/spi.c index 7d0440f7c1d5..59d31a9f3637 100644 --- a/cpu/esp8266/periph/spi.c +++ b/cpu/esp8266/periph/spi.c @@ -21,32 +21,77 @@ #define ENABLE_DEBUG (0) #include "debug.h" -#include "common.h" +#include "esp_common.h" #include "log.h" -#if defined(MODULE_PERIPH_SPI) - #include #include "cpu.h" #include "mutex.h" #include "periph/spi.h" -#include "esp/iomux_regs.h" -#include "esp/spi_regs.h" - -#include "gpio_common.h" +#include "esp_attr.h" +#include "gpio_arch.h" -#define SPI_BUS_NUM 2 -#define SPI_BLOCK_SIZE 64 /* number of bytes per SPI transfer */ +#ifdef MCU_ESP32 -static mutex_t _spi_lock[SPI_BUS_NUM] = { MUTEX_INIT }; +#include "driver/periph_ctrl.h" +#include "rom/ets_sys.h" +#include "soc/gpio_reg.h" +#include "soc/gpio_sig_map.h" +#include "soc/gpio_struct.h" +#include "soc/io_mux_reg.h" +#include "soc/spi_reg.h" +#include "soc/spi_struct.h" -/* indicate whether SPI interface were already initilized */ -static bool _spi_initialized[SPI_BUS_NUM] = { false }; +#else /* MCU_ESP32 */ -/* indicate whether pins of the SPI interface were already initilized */ -static bool _spi_pins_initialized[SPI_BUS_NUM] = { false }; +#include "esp/iomux_regs.h" +#include "esp8266/spi_register.h" +#include "esp8266/spi_struct.h" + +#define SPI_DOUTDIN (BIT(0)) + +#endif /* MCU_ESP32 */ + +#define SPI_BLOCK_SIZE 64 /* number of bytes per SPI transfer */ + +/* pins of FSI are fixed */ +#define FSPI_SCK GPIO6 +#define FSPI_MISO GPIO7 +#define FSPI_MOSI GPIO8 + +/** structure which describes all properties of one SPI bus */ +struct _spi_bus_t { + spi_dev_t* regs; /* pointer to register data struct of the SPI device */ + mutex_t lock; /* mutex for each possible SPI interface */ + bool initialized; /* interface already initialized */ + bool pins_initialized; /* pins interface initialized */ +#ifdef MCU_ESP32 + uint8_t mod; /* peripheral hardware module of the SPI interface */ + uint8_t int_src; /* peripheral interrupt source used by the SPI device */ + uint8_t signal_sck; /* SCK signal from the controller */ + uint8_t signal_mosi; /* MOSI signal from the controller */ + uint8_t signal_miso; /* MISO signal to the controller */ +#endif /* MCU_ESP32 */ +}; + +static struct _spi_bus_t _spi[] = { + #ifdef SPI0_CTRL + { + .initialized = false, + .pins_initialized = false, + .lock = MUTEX_INIT + }, + #endif + #ifdef SPI1_CTRL + { + .initialized = false, + .pins_initialized = false, + .lock = MUTEX_INIT + }, + #endif +}; /* * GPIOs that were once initialized as SPI interface pins can not be used @@ -57,23 +102,48 @@ static bool _spi_pins_initialized[SPI_BUS_NUM] = { false }; * the *spi_init_cs* function or the *spi_acquire* function when the interface * is used for the first time. */ -void IRAM spi_init (spi_t bus) +void IRAM_ATTR spi_init (spi_t bus) { + assert(bus < SPI_NUMOF_MAX); + assert(bus < SPI_NUMOF); + + switch (spi_config[bus].ctrl) { +#ifdef MCU_ESP32 + case HSPI: _spi[bus].regs = &SPI2; + _spi[bus].mod = PERIPH_HSPI_MODULE; + _spi[bus].int_src = ETS_SPI2_INTR_SOURCE; + _spi[bus].signal_sck = HSPICLK_OUT_IDX; + _spi[bus].signal_mosi = HSPID_OUT_IDX; + _spi[bus].signal_miso = HSPIQ_IN_IDX; + break; + case VSPI: _spi[bus].regs = &SPI3; + _spi[bus].mod = PERIPH_VSPI_MODULE; + _spi[bus].int_src = ETS_SPI3_INTR_SOURCE; + _spi[bus].signal_sck = VSPICLK_OUT_IDX; + _spi[bus].signal_mosi = VSPID_OUT_IDX; + _spi[bus].signal_miso = VSPIQ_IN_IDX; + break; +#else /* MCU_ESP32 */ + case HSPI: _spi[bus].regs = &SPI1; + break; +#endif /* MCU_ESP32 */ + default: LOG_TAG_ERROR("spi", "invalid SPI interface controller " + "used for SPI_DEV(%d)\n", bus); + break; + } return; } -void _spi_init_internal(spi_t bus) +/* Internal initialization function when the interface is used the first time */ +static void IRAM_ATTR _spi_init_internal(spi_t bus) { - /* only one physical SPI(1) bus (HSPI) can be used for peripherals */ - /* RIOT's SPI_DEV(0) is mapped to SPI(1) bus (HSPI) */ - /* TODO SPI overlap mode SPI and HSPI */ - CHECK_PARAM (bus == SPI_DEV(0)); + assert(bus < SPI_NUMOF); /* avoid multiple initializations */ - if (_spi_initialized[bus]) { + if (_spi[bus].initialized) { return; } - _spi_initialized[bus] = true; + _spi[bus].initialized = true; DEBUG("%s bus=%u\n", __func__, bus); @@ -82,139 +152,176 @@ void _spi_init_internal(spi_t bus) /* check whether pins could be initialized, otherwise return, CS is not initialized in spi_init_pins */ - if (_gpio_pin_usage[SPI0_SCK_GPIO] != _SPI && - _gpio_pin_usage[SPI0_MOSI_GPIO] != _SPI && - _gpio_pin_usage[SPI0_MISO_GPIO] != _SPI) { + if (gpio_get_pin_usage(spi_config[bus].sck) != _SPI && + gpio_get_pin_usage(spi_config[bus].miso) != _SPI && + gpio_get_pin_usage(spi_config[bus].mosi) != _SPI && + gpio_get_pin_usage(spi_config[bus].cs) != _SPI) { return; } - /* set bus into a defined state */ - SPI(bus).USER0 = SPI_USER0_MOSI | SPI_USER0_CLOCK_IN_EDGE | SPI_USER0_DUPLEX; - SPI(bus).USER0 |= SPI_USER0_CS_SETUP | SPI_USER0_CS_HOLD; +#ifdef MCU_ESP32 + /* enable (power on) the according SPI module */ + periph_module_enable(_spi[bus].mod); +#endif /* MCU_ESP32 */ + + /* bring the bus into a defined state */ + _spi[bus].regs->user.val = SPI_USR_MOSI | SPI_CK_I_EDGE | SPI_DOUTDIN | + SPI_CS_SETUP | SPI_CS_HOLD; /* set byte order to little endian for read and write operations */ - SPI(bus).USER0 &= ~(SPI_USER0_WR_BYTE_ORDER | SPI_USER0_RD_BYTE_ORDER); + _spi[bus].regs->user.wr_byte_order = 0; + _spi[bus].regs->user.rd_byte_order = 0; /* set bit order to most significant first for read and write operations */ - SPI(bus).CTRL0 = 0; /* ~(SPI_CTRL0_WR_BIT_ORDER | SPI_CTRL0_RD_BIT_ORDER); */ - - DEBUG("%s SPI(bus).USER0=%08x SPI(bus).CTRL0=%08x\n", - __func__, SPI(bus).USER0, SPI(bus).CTRL0); + _spi[bus].regs->ctrl.wr_bit_order = 0; + _spi[bus].regs->ctrl.rd_bit_order = 0; + + /* reset all DIO or QIO flags */ + _spi[bus].regs->ctrl.fread_qio = 0; + _spi[bus].regs->ctrl.fread_dio = 0; + _spi[bus].regs->ctrl.fread_quad = 0; + _spi[bus].regs->ctrl.fread_dual = 0; + + /* disable fast read mode and write protection */ + _spi[bus].regs->ctrl.fastrd_mode = 0; +#ifdef MCU_ESP32 + _spi[bus].regs->ctrl.wp = 0; +#endif /* MCU_ESP32 */ + + /* acquire and release to set default parameters */ + spi_acquire(bus, GPIO_UNDEF, SPI_MODE_0, SPI_CLK_1MHZ); + spi_release(bus); } void spi_init_pins(spi_t bus) { - /* see spi_init */ - CHECK_PARAM (bus == SPI_DEV(0)); + assert(bus < SPI_NUMOF); /* call initialization of the SPI interface if it is not initialized yet */ - if (!_spi_initialized[bus]) { + if (!_spi[bus].initialized) { _spi_init_internal(bus); } /* avoid multiple pin initializations */ - if (_spi_pins_initialized[bus]) { + if (_spi[bus].pins_initialized) { return; } - _spi_pins_initialized[bus] = true; + _spi[bus].pins_initialized = true; DEBUG("%s bus=%u\n", __func__, bus); - uint32_t iomux_func = (bus == 0) ? IOMUX_FUNC(1) : IOMUX_FUNC(2); + if (gpio_init (spi_config[bus].sck, GPIO_OUT) || + gpio_init (spi_config[bus].mosi, GPIO_OUT) || + gpio_init (spi_config[bus].miso, GPIO_IN)) { + LOG_TAG_ERROR("spi", + "SPI_DEV(%d) pins could not be initialized\n", bus); + return; + } + if (spi_init_cs(bus, spi_config[bus].cs) != SPI_OK) { + LOG_TAG_ERROR("spi", + "SPI_DEV(%d) CS signal could not be initialized\n", + bus); + return; + } + /* store the usage type in GPIO table */ + gpio_set_pin_usage(spi_config[bus].sck, _SPI); + gpio_set_pin_usage(spi_config[bus].mosi, _SPI); + gpio_set_pin_usage(spi_config[bus].miso, _SPI); + +#ifdef MCU_ESP32 + /* connect SCK and MOSI pins to the output signal through the GPIO matrix */ + GPIO.func_out_sel_cfg[spi_config[bus].sck].func_sel = _spi[bus].signal_sck; + GPIO.func_out_sel_cfg[spi_config[bus].mosi].func_sel = _spi[bus].signal_mosi; + /* connect MISO input signal to the MISO pin through the GPIO matrix */ + GPIO.func_in_sel_cfg[_spi[bus].signal_miso].sig_in_sel = 1; + GPIO.func_in_sel_cfg[_spi[bus].signal_miso].sig_in_inv = 0; + GPIO.func_in_sel_cfg[_spi[bus].signal_miso].func_sel = spi_config[bus].miso; +#else /* MCU_ESP32 */ /* - * CS is handled as normal GPIO ouptut. Due to the small number of GPIOs + * CS is handled as normal GPIO output. Due to the small number of GPIOs * we have, we do not initialize the default CS pin here. Either the app * uses spi_init_cs to initialize the CS pin explicitly, or we initialize * the default CS when spi_aquire is used first time. */ - IOMUX.PIN[_gpio_to_iomux[SPI0_MISO_GPIO]] &= ~IOMUX_PIN_FUNC_MASK; - IOMUX.PIN[_gpio_to_iomux[SPI0_MOSI_GPIO]] &= ~IOMUX_PIN_FUNC_MASK; - IOMUX.PIN[_gpio_to_iomux[SPI0_SCK_GPIO]] &= ~IOMUX_PIN_FUNC_MASK; + uint32_t iomux_func = IOMUX_FUNC(2); - IOMUX.PIN[_gpio_to_iomux[SPI0_MISO_GPIO]] |= iomux_func; - IOMUX.PIN[_gpio_to_iomux[SPI0_MOSI_GPIO]] |= iomux_func; - IOMUX.PIN[_gpio_to_iomux[SPI0_SCK_GPIO]] |= iomux_func; + IOMUX.PIN[_gpio_to_iomux[spi_config[bus].miso]] &= ~IOMUX_PIN_FUNC_MASK; + IOMUX.PIN[_gpio_to_iomux[spi_config[bus].mosi]] &= ~IOMUX_PIN_FUNC_MASK; + IOMUX.PIN[_gpio_to_iomux[spi_config[bus].sck]] &= ~IOMUX_PIN_FUNC_MASK; - _gpio_pin_usage [SPI0_MISO_GPIO] = _SPI; /* pin cannot be used for anything else */ - _gpio_pin_usage [SPI0_MOSI_GPIO] = _SPI; /* pin cannot be used for anything else */ - _gpio_pin_usage [SPI0_SCK_GPIO] = _SPI; /* pin cannot be used for anything else */ + IOMUX.PIN[_gpio_to_iomux[spi_config[bus].miso]] |= iomux_func; + IOMUX.PIN[_gpio_to_iomux[spi_config[bus].mosi]] |= iomux_func; + IOMUX.PIN[_gpio_to_iomux[spi_config[bus].sck]] |= iomux_func; +#endif /* MCU_ESP32 */ } int spi_init_cs(spi_t bus, spi_cs_t cs) { DEBUG("%s bus=%u cs=%u\n", __func__, bus, cs); - /* see spi_init */ - CHECK_PARAM_RET (bus == SPI_DEV(0), SPI_NODEV); + assert(bus < SPI_NUMOF); /* call initialization of the SPI interface if it is not initialized yet */ - if (!_spi_initialized[bus]) { + if (!_spi[bus].initialized) { _spi_init_internal(bus); } /* return if pin is already initialized as SPI CS signal */ - if (_gpio_pin_usage [cs] == _SPI) { + if (gpio_get_pin_usage(cs) == _SPI) { return SPI_OK; } - if (_gpio_pin_usage [cs] != _GPIO) { + /* check whether CS pin is used otherwise */ + if (gpio_get_pin_usage(cs) != _GPIO) { return SPI_NOCS; } + /* initialize the pin */ gpio_init(cs, GPIO_OUT); - gpio_set (cs); + gpio_set(cs); - _gpio_pin_usage [cs] = _SPI; /* pin cannot be used for anything else */ + /* pin cannot be used for anything else */ + gpio_set_pin_usage(cs, _SPI); return SPI_OK; } -int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) +int IRAM_ATTR spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) { DEBUG("%s bus=%u cs=%u mode=%u clk=%u\n", __func__, bus, cs, mode, clk); - /* see spi_init */ - CHECK_PARAM_RET (bus == SPI_DEV(0), SPI_NODEV); + assert(bus < SPI_NUMOF); /* call initialization of the SPI interface if it is not initialized yet */ - if (!_spi_initialized[bus]) { + if (!_spi[bus].initialized) { _spi_init_internal(bus); } /* if parameter cs is GPIO_UNDEF, the default CS pin is used */ - cs = (cs == GPIO_UNDEF) ? SPI0_CS0_GPIO : cs; + cs = (cs == GPIO_UNDEF) ? spi_config[bus].cs : cs; /* if the CS pin used is not yet initialized, we do it now */ - if (_gpio_pin_usage[cs] != _SPI && spi_init_cs(bus, cs) != SPI_OK) { - LOG_ERROR("SPI_DEV(%d) CS signal could not be initialized\n", bus); + if (gpio_get_pin_usage(cs) != _SPI && spi_init_cs(bus, cs) != SPI_OK) { + LOG_TAG_ERROR("spi", + "SPI_DEV(%d) CS signal could not be initialized\n", + bus); return SPI_NOCS; } /* lock the bus */ - mutex_lock(&_spi_lock[bus]); - - /* set SPI mode */ - bool cpha = (mode == SPI_MODE_1 || mode == SPI_MODE_3); - bool cpol = (mode == SPI_MODE_2 || mode == SPI_MODE_3); + mutex_lock(&_spi[bus].lock); - if (cpol) { - cpha = !cpha; /* CPHA must be inverted when CPOL = 1 */ - } - - if (cpha) { - SPI(bus).USER0 |= SPI_USER0_CLOCK_OUT_EDGE; - } - else { - SPI(bus).USER0 &= ~SPI_USER0_CLOCK_OUT_EDGE; - } - - if (cpol) { - SPI(bus).PIN |= SPI_PIN_IDLE_EDGE; - } - else { - SPI(bus).PIN &= ~SPI_PIN_IDLE_EDGE; - } + /* + * set SPI mode + * see ESP32 Technical Reference, Table 25 and Section 7.4.2 + */ + _spi[bus].regs->pin.ck_idle_edge = (mode == SPI_MODE_2 || mode == SPI_MODE_3); + _spi[bus].regs->user.ck_out_edge = (mode == SPI_MODE_1 || mode == SPI_MODE_2); + _spi[bus].regs->ctrl2.miso_delay_mode = (mode == SPI_MODE_0 || mode == SPI_MODE_3) ? 2 : 1; + _spi[bus].regs->ctrl2.miso_delay_num = 0; + _spi[bus].regs->ctrl2.mosi_delay_mode = 0; + _spi[bus].regs->ctrl2.mosi_delay_num = 0; /* set SPI clock * see ESP8266 Technical Reference Appendix 2 - SPI registers @@ -248,31 +355,53 @@ int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) spi_clkdiv_pre--; spi_clkcnt_N--; - DEBUG("%s spi_clkdiv_prev=%u spi_clkcnt_N=%u\n", __func__, spi_clkdiv_pre, spi_clkcnt_N); + DEBUG("%s spi_clkdiv_prev=%u spi_clkcnt_N=%u\n", + __func__, spi_clkdiv_pre, spi_clkcnt_N); + +#ifdef MCU_ESP8266 + IOMUX.CONF &= ~IOMUX_CONF_SPI1_CLOCK_EQU_SYS_CLOCK; +#endif - /* SPI clock is derived from system bus frequency and should not be affected by */ - /* CPU clock */ + /* SPI clock is derived from APB clock by dividers */ + _spi[bus].regs->clock.clk_equ_sysclk = 0; - IOMUX.CONF &= ~(bus == 0 ? IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK - : IOMUX_CONF_SPI1_CLOCK_EQU_SYS_CLOCK); - SPI(bus).CLOCK = VAL2FIELD_M (SPI_CLOCK_DIV_PRE, spi_clkdiv_pre) | - VAL2FIELD_M (SPI_CLOCK_COUNT_NUM, spi_clkcnt_N) | - VAL2FIELD_M (SPI_CLOCK_COUNT_HIGH, (spi_clkcnt_N+1)/2-1) | - VAL2FIELD_M (SPI_CLOCK_COUNT_LOW, spi_clkcnt_N); + /* set SPI clock dividers */ + _spi[bus].regs->clock.clkdiv_pre = spi_clkdiv_pre; + _spi[bus].regs->clock.clkcnt_n = spi_clkcnt_N; + _spi[bus].regs->clock.clkcnt_h = (spi_clkcnt_N+1)/2-1; + _spi[bus].regs->clock.clkcnt_l = spi_clkcnt_N; - DEBUG("%s IOMUX.CONF=%08x SPI(bus).CLOCK=%08x\n", - __func__, IOMUX.CONF, SPI(bus).CLOCK); + DEBUG("%s bus %d: SPI_CLOCK_REG=%08x\n", + __func__, bus, _spi[bus].regs->clock.val); return SPI_OK; } -void spi_release(spi_t bus) +void IRAM_ATTR spi_release(spi_t bus) { - /* see spi_init */ - CHECK_PARAM (bus == SPI_DEV(0)); + DEBUG("%s bus=%u\n", __func__, bus); + + assert(bus < SPI_NUMOF); /* release the bus */ - mutex_unlock(&_spi_lock[bus]); + mutex_unlock(&_spi[bus].lock); +} + +#ifdef MCU_ESP32 +static const char* _spi_names[] = { "CSPI", "FSPI", "HSPI", "VSPI" }; +#else /* MCU_ESP32 */ +static const char* _spi_names[] = { "FSPI", "HSPI" }; +#endif /* MCU_ESP32 */ + +void spi_print_config(void) +{ + for (unsigned bus = 0; bus < SPI_NUMOF; bus++) { + printf("\tSPI_DEV(%u)\t%s ", bus, _spi_names[spi_config[bus].ctrl]); + printf("sck=%d " , spi_config[bus].sck); + printf("miso=%d ", spi_config[bus].miso); + printf("mosi=%d ", spi_config[bus].mosi); + printf("cs=%d\n" , spi_config[bus].cs); + } } /* @@ -284,29 +413,37 @@ void spi_release(spi_t bus) * https://github.com/SuperHouse/esp-open-rtos/blob/master/LICENSE */ -inline static void _set_size(uint8_t bus, uint8_t bytes) +inline static void IRAM_ATTR _set_size(uint8_t bus, uint8_t bytes) { uint32_t bits = ((uint32_t)bytes << 3) - 1; - SPI(bus).USER1 = SET_FIELD(SPI(bus).USER1, SPI_USER1_MISO_BITLEN, bits); - SPI(bus).USER1 = SET_FIELD(SPI(bus).USER1, SPI_USER1_MOSI_BITLEN, bits); + +#ifdef MCU_ESP32 + _spi[bus].regs->mosi_dlen.val = bits; + _spi[bus].regs->miso_dlen.val = bits; +#else /* MCU_ESP32 */ + _spi[bus].regs->user1.usr_mosi_bitlen = bits; + _spi[bus].regs->user1.usr_miso_bitlen = bits; +#endif /* MCU_ESP32 */ } -inline static void _wait(uint8_t bus) +inline static void IRAM_ATTR _wait(uint8_t bus) { - while (SPI(bus).CMD & SPI_CMD_USR) {} + /* SPI_CMD_REG.SPI_USR is cleared when operation has been finished */ + while (_spi[bus].regs->cmd.usr) {} } -inline static void _start(uint8_t bus) +inline static void IRAM_ATTR _start(uint8_t bus) { - SPI(bus).CMD |= SPI_CMD_USR; + /* set SPI_CMD_REG.SPI_USR to start an operation */ + _spi[bus].regs->cmd.usr = 1; } -inline static void _store_data(uint8_t bus, const void *data, size_t len) +inline static void IRAM_ATTR _store_data(uint8_t bus, const void *data, size_t len) { uint8_t words = len / 4; uint8_t tail = len % 4; - memcpy((void *)SPI(bus).W, data, len - tail); + memcpy((void *)_spi[bus].regs->data_buf, data, len - tail); if (!tail) { return; @@ -317,12 +454,12 @@ inline static void _store_data(uint8_t bus, const void *data, size_t len) for (uint8_t i = 0; i < tail; i++) { last = last | (offs[i] << (i * 8)); } - SPI(bus).W[words] = last; + _spi[bus].regs->data_buf[words] = last; } static const uint8_t spi_empty_out[SPI_BLOCK_SIZE] = { 0 }; -static void _spi_buf_transfer(uint8_t bus, const void *out, void *in, size_t len) +static void IRAM_ATTR _spi_buf_transfer(uint8_t bus, const void *out, void *in, size_t len) { DEBUG("%s bus=%u out=%p in=%p len=%u\n", __func__, bus, out, in, len); @@ -333,15 +470,14 @@ static void _spi_buf_transfer(uint8_t bus, const void *out, void *in, size_t len _start(bus); _wait(bus); if (in) { - memcpy(in, (void *)SPI(bus).W, len); + memcpy(in, (void *)_spi[bus].regs->data_buf, len); } } -void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, - const void *out, void *in, size_t len) +void IRAM_ATTR spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) { - /* see spi_init */ - CHECK_PARAM (bus == SPI_DEV(0)); + assert(bus < SPI_NUMOF); DEBUG("%s bus=%u cs=%u cont=%d out=%p in=%p len=%u\n", __func__, bus, cs, cont, out, in, len); @@ -360,9 +496,7 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, } #endif - if (cs != SPI_CS_UNDEF) { - gpio_clear (cs); - } + gpio_clear(cs != SPI_CS_UNDEF ? cs : spi_config[bus].cs); size_t blocks = len / SPI_BLOCK_SIZE; uint8_t tail = len % SPI_BLOCK_SIZE; @@ -382,8 +516,8 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, in ? (uint8_t *)in + blocks * SPI_BLOCK_SIZE : NULL, tail); } - if (!cont && (cs != SPI_CS_UNDEF)) { - gpio_set (cs); + if (!cont) { + gpio_set(cs != SPI_CS_UNDEF ? cs : spi_config[bus].cs); } #if ENABLE_DEBUG @@ -396,21 +530,3 @@ void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, } #endif } - -void spi_print_config(void) -{ - LOG_INFO("\tSPI_DEV(0): "); - LOG_INFO("sck=%d " , SPI0_SCK_GPIO); - LOG_INFO("miso=%d ", SPI0_MISO_GPIO); - LOG_INFO("mosi=%d ", SPI0_MOSI_GPIO); - LOG_INFO("cs=%d\n" , SPI0_CS0_GPIO); -} - -#else /* MODULE_PERIPH_SPI */ - -void spi_print_config(void) -{ - LOG_INFO("\tSPI: no devices\n"); -} - -#endif /* MODULE_PERIPH_SPI */ diff --git a/cpu/esp8266/periph/timer.c b/cpu/esp8266/periph/timer.c index 967787b0815c..06231a5376e5 100644 --- a/cpu/esp8266/periph/timer.c +++ b/cpu/esp8266/periph/timer.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -27,9 +27,10 @@ #include "xtimer.h" #include "periph/timer.h" -#include "common.h" -#include "irq_arch.h" #include "esp/common_macros.h" +#include "esp_common.h" +#include "irq_arch.h" +#include "rom/ets_sys.h" #include "sdk/sdk.h" #include "xtensa/hal.h" @@ -295,18 +296,14 @@ static void IRAM __timer_channel_stop (struct hw_timer_t* timer, struct hw_chann void timer_print_config(void) { - for (int i = 0; i < HW_TIMER_NUMOF; i++) { - LOG_INFO("\tTIMER_DEV(%d): %d channel(s)\n", i, - ARRAY_SIZE(timers[i].channels)); + for (unsigned i = 0; i < HW_TIMER_NUMOF; i++) { + printf("\tTIMER_DEV(%u)\t%d channel(s)\n", i, + ARRAY_SIZE(timers[i].channels)); } } #else /* MODULE_ESP_SW_TIMER */ -#ifndef MODULE_ESP_SDK -#error Software timers are not available in Non-SDK version, use USE_SDK=1 to enable SDK-version. -#else - /* software timer based on os_timer_arm functions */ #define OS_TIMER_NUMOF 1 @@ -319,6 +316,8 @@ void timer_print_config(void) #define OS_TIMER_DELTA_RSHIFT 16 #define OS_TIMER_CORRECTION 4 +extern void os_timer_arm_us(os_timer_t *ptimer, uint32_t time, bool repeat_flag); + /* Since hardware timer FRC1 is needed to implement PWM, we have to map our */ /* timer using the exsting ETS timer with 1 us clock rate */ @@ -560,12 +559,10 @@ static void IRAM __timer_channel_stop (struct phy_timer_t* timer, struct phy_cha void timer_print_config(void) { - for (int i = 0; i < OS_TIMER_NUMOF; i++) { - LOG_INFO("\tTIMER_DEV(%d): %d channel(s)\n", i, - ARRAY_SIZE(timers[i].channels)); + for (unsigned i = 0; i < OS_TIMER_NUMOF; i++) { + printf("\tTIMER_DEV(%u)\t%d channel(s)\n", i, + ARRAY_SIZE(timers[i].channels)); } } -#endif /* NON_SDK */ - #endif /* MODULE_ESP_SW_TIMER */ diff --git a/cpu/esp8266/periph/uart.c b/cpu/esp8266/periph/uart.c index 58a17e64407e..b1dd3ecb0422 100644 --- a/cpu/esp8266/periph/uart.c +++ b/cpu/esp8266/periph/uart.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -19,147 +19,461 @@ * @} */ -#define ENABLE_DEBUG 0 +#define ENABLE_DEBUG (0) #include "debug.h" -#include "common.h" - +#include "esp_common.h" #include "cpu.h" #include "irq_arch.h" #include "log.h" #include "sched.h" #include "thread.h" +#include "periph/gpio.h" #include "periph/uart.h" -#include "eagle_soc.h" -#include "esp/uart_regs.h" -#include "sdk/sdk.h" +#include "stdio_uart.h" -/** - * @brief Allocate memory to store the callback functions. - */ -static uart_isr_ctx_t isr_ctx[UART_NUMOF]; +#include "esp/common_macros.h" +#include "rom/ets_sys.h" +#include "xtensa/xtensa_api.h" + +#ifdef MCU_ESP32 + +#include "gpio_arch.h" +#include "driver/periph_ctrl.h" +#include "soc/gpio_reg.h" +#include "soc/gpio_sig_map.h" +#include "soc/gpio_struct.h" +#include "soc/rtc.h" +#include "soc/uart_reg.h" +#include "soc/uart_struct.h" -static uint8_t IRAM __uart_rx_one_char (uart_t uart); -static void __uart_tx_one_char(uart_t uart, uint8_t data); -static void __uart_intr_enable (uart_t uart); -static void IRAM __uart_intr_handler (void *para); +#undef UART_CLK_FREQ +#define UART_CLK_FREQ rtc_clk_apb_freq_get() /* APB_CLK is used */ + +#else /* MCU_ESP32 */ + +#include "esp8266/uart_struct.h" + +#ifdef MODULE_ESP_QEMU +#include "esp/uart_regs.h" +#endif /* MODULE_ESP_QEMU */ + +#define UART0 uart0 +#define UART1 uart1 +#define CPU_INUM_UART ETS_UART_INUM + +#endif /* MCU_ESP32 */ + +struct uart_hw_t { + uart_dev_t* regs; /* pointer to register data struct of the UART device */ + uint8_t pin_txd; /* TxD pin used */ + uint8_t pin_rxd; /* RxD pin used */ + bool used; /* indicates whether UART is used */ + uint32_t baudrate; /* used baudrate */ + uart_data_bits_t data; /* used data bits */ + uart_stop_bits_t stop; /* used stop bits */ + uart_parity_t parity; /* used parity bits */ + uart_isr_ctx_t isr_ctx; /* callback functions */ +#ifdef MCU_ESP32 + uint8_t mod; /* peripheral hardware module of the UART interface */ + uint8_t signal_txd; /* TxD signal from the controller */ + uint8_t signal_rxd; /* RxD signal to the controller */ + uint8_t int_src; /* peripheral interrupt source used by the UART device */ +#endif +}; + +/* hardware resources */ +static struct uart_hw_t _uarts[] = { + { + .regs = &UART0, + .used = false, + .baudrate = STDIO_UART_BAUDRATE, + .data = UART_DATA_BITS_8, + .stop = UART_STOP_BITS_1, + .parity = UART_PARITY_NONE, +#ifdef MCU_ESP32 + .mod = PERIPH_UART0_MODULE, + .signal_txd = U0TXD_OUT_IDX, + .signal_rxd = U0RXD_IN_IDX, + .int_src = ETS_UART0_INTR_SOURCE + }, + { + .regs = &UART1, + .used = false, + .baudrate = STDIO_UART_BAUDRATE, + .data = UART_DATA_BITS_8, + .stop = UART_STOP_BITS_1, + .parity = UART_PARITY_NONE, + .mod = PERIPH_UART1_MODULE, + .signal_txd = U1TXD_OUT_IDX, + .signal_rxd = U1RXD_IN_IDX, + .int_src = ETS_UART1_INTR_SOURCE + }, + { + .regs = &UART2, + .used = false, + .baudrate = STDIO_UART_BAUDRATE, + .data = UART_DATA_BITS_8, + .stop = UART_STOP_BITS_1, + .parity = UART_PARITY_NONE, + .mod = PERIPH_UART2_MODULE, + .signal_txd = U2TXD_OUT_IDX, + .signal_rxd = U2RXD_IN_IDX, + .int_src = ETS_UART2_INTR_SOURCE +#endif /* MCU_ESP32 */ + }, +}; + +/* declaration of external functions */ +extern void uart_div_modify(uint8_t uart_no, uint32_t div); + +/* forward declaration of internal functions */ +static int _uart_set_baudrate(uart_t uart, uint32_t baudrate); +static int _uart_set_mode(uart_t uart, uart_data_bits_t data_bits, + uart_parity_t parity, uart_stop_bits_t stop_bits); +static uint8_t IRAM _uart_rx_one_char(uart_t uart); +static void _uart_tx_one_char(uart_t uart, uint8_t data); +static void _uart_intr_enable(uart_t uart); +static void _uart_config (uart_t uart); +static void IRAM _uart_intr_handler(void *para); int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) { - CHECK_PARAM_RET (uart < UART_NUMOF, -1); - DEBUG("%s uart=%d, rate=%d, rx_cb=%p, arg=%p\n", __func__, uart, baudrate, rx_cb, arg); - /* setup the baudrate */ - uart_div_modify(uart, UART_CLK_FREQ / baudrate); + assert(uart < UART_NUMOF_MAX); + assert(uart < UART_NUMOF); - /* register interrupt context */ - isr_ctx[uart].rx_cb = rx_cb; - isr_ctx[uart].arg = arg; + _uarts[uart].pin_txd = uart_config[uart].txd; + _uarts[uart].pin_rxd = uart_config[uart].rxd; - if (rx_cb) { - ets_isr_attach (ETS_UART_INUM, __uart_intr_handler, 0); +#ifdef MCU_ESP32 + /* UART1 and UART2 have configurable pins */ + if ((uart == UART_DEV(1) || uart == UART_DEV(2))) { - /* since reading is done byte for byte we set the RX FIFO FULL */ - /* interrupt level to 1 byte */ - UART(uart).CONF1 = SET_FIELD(UART(uart).CONF1, UART_CONF1_RXFIFO_FULL_THRESHOLD, 1); + /* reset the pins when they were already used as UART pins */ + if (gpio_get_pin_usage(_uarts[uart].pin_txd) == _UART) { + gpio_set_pin_usage(_uarts[uart].pin_txd, _GPIO); + } + if (gpio_get_pin_usage(_uarts[uart].pin_rxd) == _UART) { + gpio_set_pin_usage(_uarts[uart].pin_rxd, _GPIO); + } - /* enable the RX FIFO FULL interrupt */ - __uart_intr_enable (uart); + /* try to initialize the pins as GPIOs first */ + if (gpio_init(_uarts[uart].pin_txd, GPIO_OUT) || + gpio_init(_uarts[uart].pin_rxd, GPIO_IN)) { + return -1; + } + + /* store the usage type in GPIO table */ + gpio_set_pin_usage(_uarts[uart].pin_txd, _UART); + gpio_set_pin_usage(_uarts[uart].pin_rxd, _UART); + + /* connect TxD pin to the TxD output signal through the GPIO matrix */ + GPIO.func_out_sel_cfg[_uarts[uart].pin_txd].func_sel = _uarts[uart].signal_txd; + + /* connect RxD input signal to the RxD pin through the GPIO matrix */ + GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].sig_in_sel = 1; + GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].sig_in_inv = 0; + GPIO.func_in_sel_cfg[_uarts[uart].signal_rxd].func_sel = _uarts[uart].pin_rxd; } +#endif + _uarts[uart].baudrate = baudrate; + + /* register interrupt context */ + _uarts[uart].isr_ctx.rx_cb = rx_cb; + _uarts[uart].isr_ctx.arg = arg; + + /* enable and configure the according UART module */ + uart_poweron(uart); return UART_OK; } +#if MODULE_PERIPH_UART_MODECFG +int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity, + uart_stop_bits_t stop_bits) +{ + return _uart_set_mode(uart, data_bits, parity, stop_bits); +} +#endif + void uart_write(uart_t uart, const uint8_t *data, size_t len) { - CHECK_PARAM (uart < UART_NUMOF); + CHECK_PARAM(uart < UART_NUMOF); for (size_t i = 0; i < len; i++) { - __uart_tx_one_char(uart, data[i]); + _uart_tx_one_char(uart, data[i]); } } void uart_poweron (uart_t uart) { - /* UART can't be powered on/off, just return */ + CHECK_PARAM(uart < UART_NUMOF); + +#ifdef MCU_ESP32 + periph_module_enable(_uarts[uart].mod); +#endif + _uart_config(uart); } void uart_poweroff (uart_t uart) { - /* UART can't be powered on/off, just return */ + CHECK_PARAM(uart < UART_NUMOF); + +#ifdef MCU_ESP32 + periph_module_disable(_uarts[uart].mod); +#endif } -void IRAM __uart_intr_handler (void *arg) +/* systemwide UART initializations */ +void uart_system_init (void) { - /* to satisfy the compiler */ - (void)arg; - - irq_isr_enter (); - - DEBUG("%s \n", __func__); + for (unsigned uart = 0; uart < UART_NUMOF; uart++) { + /* reset all UART interrupt status registers */ + _uarts[uart].regs->int_clr.val = ~0; + } +} - /* - * UART0 and UART1 interrupts are combined togther. So we have to - * iterate over all UART devices and test the INT_STATUS register for - * interrupts - */ - for (int i = 0; i < UART_NUMOF; i++) { - uart_t uart = UART_DEV(0); /* UartDev.buff_uart_no; */ - if (UART(uart).INT_STATUS & UART_INT_STATUS_RXFIFO_FULL) { - /* clear interrupt flag */ - uint8_t data = __uart_rx_one_char (uart); +void uart_print_config(void) +{ + for (unsigned uart = 0; uart < UART_NUMOF; uart++) { + printf("\tUART_DEV(%u)\ttxd=%d rxd=%d\n", uart, + uart_config[uart].txd, uart_config[uart].rxd); + } +} - /* call registered RX callback function */ - isr_ctx[uart].rx_cb(isr_ctx[uart].arg, data); +static void IRAM _uart_intr_handler(void *arg) +{ + /* to satisfy the compiler */ + (void)arg; - /* clear interrupt flag */ - UART(uart).INT_CLEAR |= UART_INT_CLEAR_RXFIFO_FULL; - } - else { - /* TODO handle other type of interrupts, for the moment just clear them */ - UART(uart).INT_CLEAR = 0x1f; + irq_isr_enter(); + + /* UART0, UART1, UART2 peripheral interrupt sources are routed to the same + interrupt, so we have to use the status to distinguish interruptees */ + for (unsigned uart = 0; uart < UART_NUMOF; uart++) { + if (_uarts[uart].used) { + DEBUG("%s uart=%d int_st=%08x\n", __func__, + uart, _uarts[uart].regs->int_st.val); + + if (_uarts[uart].used && _uarts[uart].regs->int_st.rxfifo_full) { + /* read one byte of data */ + uint8_t data = _uart_rx_one_char (uart); + /* if registered, call the RX callback function */ + if (_uarts[uart].isr_ctx.rx_cb) { + _uarts[uart].isr_ctx.rx_cb(_uarts[uart].isr_ctx.arg, data); + } + /* clear interrupt flag */ + _uarts[uart].regs->int_clr.rxfifo_full = 1; + } + + /* TODO handle other types of interrupts, for the moment just clear them */ + _uarts[uart].regs->int_clr.val = ~0x0; } } - irq_isr_exit (); + + irq_isr_exit(); } /* RX/TX FIFO capacity is 128 byte */ -#define UART_FIFO_MAX 1 +#define UART_FIFO_MAX 128 /* receive one data byte with wait */ -static uint8_t IRAM __uart_rx_one_char (uart_t uart) +static uint8_t IRAM _uart_rx_one_char (uart_t uart) { - /* uint8_t fifo_len = FIELD2VAL(UART_STATUS_RXFIFO_COUNT, UART(uart).STATUS); */ - +#if defined(MODULE_ESP_QEMU) && defined(MCU_ESP8266) /* wait until at least von byte is in RX FIFO */ while (!FIELD2VAL(UART_STATUS_RXFIFO_COUNT, UART(uart).STATUS)) {} /* read the lowest byte from RX FIFO register */ return UART(uart).FIFO & 0xff; /* only bit 0 ... 7 */ +#else + /* wait until at least von byte is in RX FIFO */ + while (!_uarts[uart].regs->status.rxfifo_cnt) {} + + /* read the lowest byte from RX FIFO register */ + return _uarts[uart].regs->fifo.rw_byte; +#endif + } /* send one data byte with wait */ -static void __uart_tx_one_char(uart_t uart, uint8_t data) +static void _uart_tx_one_char(uart_t uart, uint8_t data) { - /* wait until at least one byte is avaiable in the TX FIFO */ - while (FIELD2VAL(UART_STATUS_TXFIFO_COUNT, UART(uart).STATUS) >= UART_FIFO_MAX) {} - - /* send the byte by placing it in the TX FIFO */ + /* wait until at least one byte is available in the TX FIFO */ + while (_uarts[uart].regs->status.txfifo_cnt >= UART_FIFO_MAX) {} + + /* send the byte by placing it in the TX FIFO using MPU */ +#ifdef MCU_ESP32 + WRITE_PERI_REG(UART_FIFO_AHB_REG(uart), data); +#else /* MCU_ESP32 */ +#ifdef MODULE_ESP_QEMU UART(uart).FIFO = data; +#else /* MODULE_ESP_QEMU */ + _uarts[uart].regs->fifo.rw_byte = data; +#endif /* MODULE_ESP_QEMU */ +#endif /* MCU_ESP32 */ } -static void __uart_intr_enable(uart_t uart) +static void _uart_intr_enable(uart_t uart) { - UART(uart).INT_ENABLE |= UART_INT_ENABLE_RXFIFO_FULL; - ETS_INTR_ENABLE(ETS_UART_INUM); + _uarts[uart].regs->int_ena.rxfifo_full = 1; + _uarts[uart].regs->int_clr.rxfifo_full = 1; + _uarts[uart].used = true; - DEBUG("%s %08x\n", __func__, UART(uart).INT_ENABLE); + DEBUG("%s %08x\n", __func__, _uarts[uart].regs->int_ena.val); } -void uart_print_config(void) +static void _uart_config(uart_t uart) { - LOG_INFO("\tUART_DEV(0): txd=%d rxd=%d\n", UART0_TXD, UART0_RXD); + assert(uart < UART_NUMOF); + + while (_uarts[uart].regs->status.txfifo_cnt != 0) { } +#if 0 + /* setup the baudrate */ + if (uart == UART_DEV(0) || uart == UART_DEV(1)) { + /* for UART0 and UART1, we can us the ROM function */ + uart_div_modify(uart, (UART_CLK_FREQ << 4) / _uarts[uart].baudrate); + } + else +#endif + if (_uart_set_baudrate(uart, _uarts[uart].baudrate) != UART_OK) { + return; + } + + /* set number of data bits, stop bits and parity mode */ + if (_uart_set_mode(uart, _uarts[uart].data, _uarts[uart].stop, + _uarts[uart].parity) != UART_OK) { + return; + } + + /* reset the FIFOs */ + _uarts[uart].regs->conf0.rxfifo_rst = 1; + _uarts[uart].regs->conf0.rxfifo_rst = 0; + _uarts[uart].regs->conf0.txfifo_rst = 1; + _uarts[uart].regs->conf0.txfifo_rst = 0; + + if (_uarts[uart].isr_ctx.rx_cb) { + /* since reading can only be done byte by byte, we set + UART_RXFIFO_FULL_THRHD interrupt level to 1 byte */ + _uarts[uart].regs->conf1.rxfifo_full_thrhd = 1; + + /* enable the RX FIFO FULL interrupt */ + _uart_intr_enable(uart); + +#ifdef MCU_ESP32 + /* route all UART interrupt sources to same the CPU interrupt */ + intr_matrix_set(PRO_CPU_NUM, _uarts[uart].int_src, CPU_INUM_UART); +#endif /* MCU_ESP32 */ + + /* we have to enable therefore the CPU interrupt here */ + xt_set_interrupt_handler(CPU_INUM_UART, _uart_intr_handler, NULL); + xt_ints_on(BIT(CPU_INUM_UART)); + } +} + +static int _uart_set_baudrate(uart_t uart, uint32_t baudrate) +{ + DEBUG("%s uart=%d, rate=%d\n", __func__, uart, baudrate); + + CHECK_PARAM_RET (uart < UART_NUMOF, -1); + + /* wait until TX FIFO is empty */ + while (_uarts[uart].regs->status.txfifo_cnt != 0) { } + + critical_enter(); + + _uarts[uart].baudrate = baudrate; + +#ifdef MCU_ESP32 + /* use APB_CLK */ + _uarts[uart].regs->conf0.tick_ref_always_on = 1; + /* compute and set the integral and the decimal part */ + uint32_t clk_div = (UART_CLK_FREQ << 4) / _uarts[uart].baudrate; + _uarts[uart].regs->clk_div.div_int = clk_div >> 4; + _uarts[uart].regs->clk_div.div_frag = clk_div & 0xf; +#else + /* compute and set clock divider */ + uint32_t clk_div = UART_CLK_FREQ / _uarts[uart].baudrate; + _uarts[uart].regs->clk_div.val = clk_div & 0xFFFFF; +#endif + + critical_exit(); + + return UART_OK; +} + +static int _uart_set_mode(uart_t uart, uart_data_bits_t data_bits, + uart_parity_t parity, uart_stop_bits_t stop_bits) +{ + DEBUG("%s uart=%d, data_bits=%d parity=%d stop_bits=%d\n", __func__, + uart, data_bits, parity, stop_bits); + + CHECK_PARAM_RET (uart < UART_NUMOF, UART_NODEV); + + critical_enter(); + + /* set number of data bits */ + switch (data_bits) { + case UART_DATA_BITS_5: _uarts[uart].regs->conf0.bit_num = 0; break; + case UART_DATA_BITS_6: _uarts[uart].regs->conf0.bit_num = 1; break; + case UART_DATA_BITS_7: _uarts[uart].regs->conf0.bit_num = 2; break; + case UART_DATA_BITS_8: _uarts[uart].regs->conf0.bit_num = 3; break; + default: LOG_TAG_ERROR("uart", "invalid number of data bits\n"); + critical_exit(); + return UART_NOMODE; + } + /* store changed number of data bits in configuration */ + _uarts[uart].data = data_bits; + + /* set number of stop bits */ + #ifdef MCU_ESP32 + /* workaround for hardware bug when stop bits are set to 2-bit mode. */ + switch (stop_bits) { + case UART_STOP_BITS_1: _uarts[uart].regs->conf0.stop_bit_num = 1; + _uarts[uart].regs->rs485_conf.dl1_en = 0; + break; + case UART_STOP_BITS_2: _uarts[uart].regs->conf0.stop_bit_num = 1; + _uarts[uart].regs->rs485_conf.dl1_en = 1; + break; + default: LOG_TAG_ERROR("uart", "invalid number of stop bits\n"); + critical_exit(); + return UART_NOMODE; + } + #else + switch (stop_bits) { + case UART_STOP_BITS_1: _uarts[uart].regs->conf0.stop_bit_num = 1; break; + case UART_STOP_BITS_2: _uarts[uart].regs->conf0.stop_bit_num = 3; break; + default: LOG_TAG_ERROR("uart", "invalid number of stop bits\n"); + critical_exit(); + return UART_NOMODE; + } + #endif + + /* store changed number of stop bits in configuration */ + _uarts[uart].stop = stop_bits; + + /* set parity mode */ + switch (parity) { + case UART_PARITY_NONE: _uarts[uart].regs->conf0.parity_en = 0; + break; + case UART_PARITY_EVEN: _uarts[uart].regs->conf0.parity = 0; + _uarts[uart].regs->conf0.parity_en = 1; + break; + case UART_PARITY_ODD: _uarts[uart].regs->conf0.parity = 1; + _uarts[uart].regs->conf0.parity_en = 1; + break; + default: LOG_TAG_ERROR("uart", "invalid or unsupported parity mode\n"); + critical_exit(); + return UART_NOMODE; + } + /* store changed parity in configuration */ + _uarts[uart].parity = parity; + + critical_exit(); + + return UART_OK; } diff --git a/cpu/esp8266/sdk/Makefile b/cpu/esp8266/sdk/Makefile index 167ad0f494db..197959704f48 100644 --- a/cpu/esp8266/sdk/Makefile +++ b/cpu/esp8266/sdk/Makefile @@ -1,3 +1,3 @@ -MODULE=sdk +MODULE=esp_sdk include $(RIOTBASE)/Makefile.base diff --git a/cpu/esp8266/sdk/ets.c b/cpu/esp8266/sdk/ets.c index 799d6cb0ea1a..80c17bde95ae 100644 --- a/cpu/esp8266/sdk/ets.c +++ b/cpu/esp8266/sdk/ets.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -16,8 +16,35 @@ * @author Gunar Schorcht * @} */ -#ifndef MODULE_ESP_SDK -#include "sdk/ets.h" +#include -#endif /* MODULE_ESP_SDK */ +#include "eagle_soc.h" +#include "sdk/sdk.h" + +uint8_t ets_get_cpu_frequency(void) +{ + return system_get_cpu_freq(); +} + +void *ets_memcpy(void *dst, const void *src, size_t size) +{ + return memcpy(dst, src, size); +} + +void ets_wdt_disable(void) +{ + SET_PERI_REG_BITS(EDGE_INT_ENABLE_REG, BIT0, 0, BIT0); + SET_PERI_REG_BITS(PERIPHS_WDT_BASEADDR + WDT_CTL_ADDRESS, WDT_CTL_EN_MASK, 0, WDT_CTL_EN_LSB); +} + +void ets_wdt_enable (void) +{ + SET_PERI_REG_BITS(EDGE_INT_ENABLE_REG, BIT0, 1, BIT0); + SET_PERI_REG_BITS(PERIPHS_WDT_BASEADDR + WDT_CTL_ADDRESS, WDT_CTL_EN_MASK, 1, WDT_CTL_EN_LSB); +} + +void ets_install_putc1(void (*p)(char c)) +{ + os_install_putc1(p); +} diff --git a/cpu/esp8266/sdk/ets.h b/cpu/esp8266/sdk/ets.h index 2b2eca408812..f8abc8802940 100644 --- a/cpu/esp8266/sdk/ets.h +++ b/cpu/esp8266/sdk/ets.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -21,27 +21,25 @@ #ifndef DOXYGEN -#include #include +#include +#include -#include "c_types.h" -#include "ets_sys.h" +#include "rom/ets_sys.h" #ifdef __cplusplus extern "C" { #endif -/* interrupts that are not defined in espressif/ets_sys.h */ +/* interrupts that are not defined in rom/ets_sys.h */ #define ETS_WDEV_INUM 0 /* WDEV process FIQ interrupt */ #define ETS_RTC_INUM 3 /* RTC interrupt */ #define ETS_CCOM_INUM 6 /* CCOMPARE0 match interrupt */ -#define ETS_SOFT_INUM 7 /* software interrupt */ -#define ETS_WDT_INUM 8 /* SDK watchdog timer */ #define ETS_FRC2_INUM 10 /* SDK FRC2 timer interrupt */ /* * The following functions are mappings or dummies for source code - * compatibility of SDK and NON-SDK version + * compatibility of NONOS-SDK and RTOS-SDK version */ #include "xtensa/xtensa_api.h" @@ -50,30 +48,20 @@ extern "C" { #define ets_isr_unmask(x) xt_ints_on(x) #define ets_isr_attach(i,f,a) xt_set_interrupt_handler(i,f,a) -#define _xtos_set_exception_handler(n,f) xt_set_exception_handler(n,f) +#define ETS_INTR_ENABLE(inum) ets_isr_unmask((1< - -#include "irq_arch.h" -#include "mutex.h" -#include "thread.h" - -#include "esp/common_macros.h" -#include "sdk/ets_task.h" -#include "sdk/sdk.h" - -static uint8_t min_prio = 0; - -/* helper function for *ets_run* */ -uint8_t ets_highest_1_bit (uint32_t mask) -{ - __asm__ volatile ("nsau %0, %1;" :"=r"(mask) : "r"(mask)); - return 32 - mask; -} - -/* - * Perform the execution of all pending ETS tasks. This is necessary to - * keep the underlying ETS system used by the SDK alive. It is called from - * the RIOT thread *ets_task_func*. - */ -void IRAM ets_tasks_run (void) -{ - #if ENABLE_DEBUG - uint32_t _entry = phy_get_mactime(); - uint32_t _exit; - ets_printf("ets_tasks_run @%lu\n", _entry); - #endif - - /* reset hardware watchdog here */ - system_soft_wdt_feed(); - - while (1) { - uint8_t hbit; - int state = irq_disable(); - hbit = ets_highest_1_bit (ets_task_exec_mask); - if (min_prio < hbit) { - ets_task_tcb_t* task = &ets_task_tab[hbit-1]; - ETSEvent * event = &task->queue[task->qposr++]; - if (task->qposr == task->qlength) { - task->qposr = 0; - } - if (--task->qpending == 0) { - ets_task_exec_mask &= ~task->maskbit; - } - ets_task_min_prio = hbit; - irq_restore(state); - task->task(event); - ets_task_min_prio = min_prio; - } - else { - irq_restore(state); - break; - } - } - - #if ENABLE_DEBUG - _exit = phy_get_mactime(); - ets_printf("ets_tasks_run @%lu for %lu us\n", _entry, _exit - _entry); - #endif - - /* reset hardware watchdog here again */ - system_soft_wdt_feed(); -} - - -#define THREAD_FLAG_ETS_THREAD (1 << 0) -static volatile thread_t* ets_thread = NULL; - -/* - * Thread *ets_task_func* is waiting for the thread flag THREAD_FLAG_ETS_THREAD - * indicating that ETS tasks have pending events and need to be executed. When - * the thread flag is set, it calls the *ets_run* function, which performs - * all ETS tasks with pending events exactly once. The thread flag is set by - * the *ets_post* function, which is called at the end of an ETS interrupt - * service routine. - */ -void *ets_task_func(void *arg) -{ - (void) arg; - - ets_thread = sched_active_thread; - while (1) { - thread_flags_wait_one(THREAD_FLAG_ETS_THREAD); - ets_tasks_run(); - } - - return NULL; -} - -/* helper macro for *ets_post */ -#define irom_cache_enabled() (*((uint32_t*)0x60000208) & (1 << 17)) - -/* ETS timer task priority */ -#define TIMER_TASK_PRIORITY 31 - -/* reference to the *ets_post* ROM function */ -typedef uint32_t (*ets_post_function_t)(uint32_t prio, ETSSignal sig, ETSParam par); -static ets_post_function_t ets_post_rom = (ets_post_function_t)0x40000e24; - -/* - * Overwritten version of ROM function *ets_post*. - * - * ETS doesn't process interrupts directly in interrupt service routines. - * Instead, they use the *ets_post* ROM function to send an event to one of the - * ETS tasks, which then processes the interrupts asynchronously. Context - * switches are not possible in interrupt service routines. - * - * Please note: *ets_post* is executed in interrupt context - */ -uint32_t IRAM ets_post (uint32_t prio, ETSSignal sig, ETSParam par) -{ - /* This function is executed in interrupt context */ - uint32_t ret; - - critical_enter(); - - /* test whether we are in hardware timer interrupt handling routine */ - if (prio == TIMER_TASK_PRIORITY) { - /* first call ETS system post function */ - ret = ets_post_rom (prio, sig, par); - - /* handle only pending timer events */ - if (irom_cache_enabled()) { - ets_timer_handler_isr(); - } - } - else { - /* simply call ROM ets_post function */ - ret = ets_post_rom (prio, sig, par); - } - /* since only timer events are handled we have to reset watch dog timer */ - if (irom_cache_enabled()) { - system_soft_wdt_feed(); - } - - if (ets_thread && irom_cache_enabled()) { - thread_flags_set((thread_t*)ets_thread, THREAD_FLAG_ETS_THREAD); - } - - critical_exit(); - - return ret; -} - -void ets_tasks_init(void) -{ - /* there is nothing to be done here at the moment */ -} - -#endif /* MODULE_ESP_SDK */ diff --git a/cpu/esp8266/sdk/ets_task.h b/cpu/esp8266/sdk/ets_task.h deleted file mode 100644 index 4c031a1ca347..000000000000 --- a/cpu/esp8266/sdk/ets_task.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2018 Gunar Schorcht - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ -#ifndef ETS_TASK_H -#define ETS_TASK_H - -#ifndef DOXYGEN - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef MODULE_ESP_SDK - -#include "ets_sys.h" - -extern uint8_t ets_task_min_prio; - -/* Task control block definition as used for ETS task functions */ - -typedef struct { - ETSTask task; /* +0 task function */ - ETSEvent* queue; /* +4 event queue (ring buffer) */ - uint8_t qlength; /* +8 event queue length */ - uint8_t qposw; /* +9 event queue position for write */ - uint8_t qposr; /* +10 event queue position for read */ - uint8_t qpending; /* +11 pending events */ - uint32_t maskbit; /* +12 task mask bit */ -} ets_task_tcb_t; - -/* ROM variables, defined in esp8266.riot-os.app.ld */ -/* source: disassembly of boot rom at https://github.com/trebisky/esp8266 */ - -extern uint8_t ets_task_min_prio; /* 0x3fffc6fc */ -extern void* ets_idle_cb; /* 0x3fffdab0 */ -extern void* ets_idle_arg; /* 0x3fffdab4 */ -extern uint32_t ets_task_exec_mask; /* 0x3fffdab8 */ -extern ets_task_tcb_t ets_task_tab[32]; /* 0x3fffdac0 */ - -extern uint32_t ets_post (uint32_t prio, ETSSignal sig, ETSParam par); - -void ets_tasks_run (void); -void ets_tasks_init (void); - -#else /* MODULE_ESP_SDK */ - -#define ets_tasks_run() -#define ets_tasks_init() - -#endif /* MODULE_ESP_SDK */ - -#ifdef __cplusplus -} -#endif - -#endif /* DOXYGEN */ -#endif /* ETS_TASK_H */ diff --git a/cpu/esp8266/sdk/lwip.c b/cpu/esp8266/sdk/lwip.c deleted file mode 100644 index ecf9ea08dfd9..000000000000 --- a/cpu/esp8266/sdk/lwip.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (C) 2018 Gunar Schorcht - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup cpu_esp8266 - * @{ - * - * @file - * @brief lwIP functions required as symbols by the SDK - * - * This file defines a number of lwIP functions that are required as symbols by - * Espressif's SDK libraries. Since RIOT doesn't need lwIP, these functions are - * only dummies without real functionality. Using these functions instead of - * the lwIP functions as provided with the SDK saves arround 4 kBytes of RAM. - * - * @author Gunar Schorcht - * @} - */ - -#ifdef MODULE_ESP_SDK - -#include "lwip/err.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/pbuf.h" -#include "lwip/tcp_impl.h" -#include "netif/etharp.h" - -#define ENABLE_DEBUG (0) -#include "debug.h" -#include "log.h" - -#ifndef ERR_OK -#define ERR_OK 0 -#endif - -const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; - -err_t ethernet_input(struct pbuf *pb, struct netif* netif) -{ - DEBUG("%s\n", __func__); - (void)pb; - (void)netif; - return ERR_OK; -} - -err_t etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) -{ - DEBUG("%s\n", __func__); - (void)netif; - (void)q; - (void)ipaddr; - return ERR_OK; -} - -err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr) -{ - DEBUG("%s\n", __func__); - (void)netif; - (void)ipaddr; - return ERR_OK; -} - -void etharp_tmr(void) -{ - DEBUG("%s\n", __func__); -} - -void etharp_cleanup_netif(struct netif *netif) -{ - DEBUG("%s\n", __func__); - (void)netif; -} - -void dhcp_cleanup(struct netif *netif) -{ - DEBUG("%s\n", __func__); - (void)netif; -} - -err_t dhcp_start(struct netif *netif) -{ - DEBUG("%s\n", __func__); - (void)netif; - return ERR_OK; -} - -err_t dhcp_renew(struct netif *netif) -{ - DEBUG("%s\n", __func__); - (void)netif; - return ERR_OK; -} - -err_t dhcp_release(struct netif *netif) -{ - DEBUG("%s\n", __func__); - (void)netif; - return ERR_OK; -} - -void dhcp_stop(struct netif *netif) -{ - DEBUG("%s\n", __func__); - (void)netif; -} - -void dhcp_network_changed(struct netif *netif) -{ - DEBUG("%s\n", __func__); - (void)netif; -} - -void dhcp_coarse_tmr(void) -{ - DEBUG("%s\n", __func__); -} - -void dhcp_fine_tmr(void) -{ - DEBUG("%s\n", __func__); -} - -void dhcps_start(struct ip_info *info) -{ - DEBUG("%s\n", __func__); - (void)info; -} - -void dhcps_stop(void) -{ - DEBUG("%s\n", __func__); -} - -void dhcps_coarse_tmr(void) -{ - DEBUG("%s\n", __func__); -} - -union tcp_listen_pcbs_t tcp_listen_pcbs; -struct tcp_pcb *tcp_active_pcbs; -struct tcp_pcb *tcp_tw_pcbs; - -void tcp_seg_free(struct tcp_seg *seg) -{ - DEBUG("%s\n", __func__); - (void)seg; -} - -void tcp_abort (struct tcp_pcb *pcb) -{ - DEBUG("%s\n", __func__); - (void)pcb; -} - -void tcp_tmr(void) -{ - DEBUG("%s\n", __func__); -} - -void igmp_init(void) -{ - DEBUG("%s\n", __func__); -} - -err_t igmp_start(struct netif *netif) -{ - DEBUG("%s\n", __func__); - (void)netif; - return ERR_OK; -} - -err_t igmp_stop(struct netif *netif) -{ - DEBUG("%s\n", __func__); - (void)netif; - return ERR_OK; -} - -void igmp_report_groups(struct netif *netif) -{ - DEBUG("%s\n", __func__); - (void)netif; -} - -void igmp_tmr(void) -{ - DEBUG("%s\n", __func__); -} - -void dns_init(void) -{ - DEBUG("%s\n", __func__); -} - -void dns_tmr(void) -{ - DEBUG("%s\n", __func__); -} - -uint32_t espconn_init(uint32 arg) -{ - DEBUG("%s\n", __func__); - (void)arg; - return 1; -} - -extern struct netif * eagle_lwip_getif(uint8_t index); - -void esp_lwip_init(void) -{ - netif_set_default((struct netif *)eagle_lwip_getif(0)); -} - -#endif /* MODULE_ESP_SDK */ diff --git a/cpu/esp8266/sdk/main.c b/cpu/esp8266/sdk/main.c deleted file mode 100644 index 3c62ed12bb75..000000000000 --- a/cpu/esp8266/sdk/main.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2018 Gunar Schorcht - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup cpu_esp8266_sdk - * @{ - * - * @file - * @brief ESP8266 SDK libmain function - * - * @author Gunar Schorcht - * @} - */ - -#ifndef MODULE_ESP_SDK - -#include - -#include "c_types.h" - -#include "common.h" -#include "cpu_conf.h" -#include "irq.h" -#include "irq_arch.h" -#include "log.h" - -#include "esp/rtcmem_regs.h" -#include "spi_flash.h" -#include "sdk/ets.h" -#include "sdk/main.h" -#include "sdk/rom.h" - -static char _printf_buf[PRINTF_BUFSIZ]; - -int IRAM os_printf_plus (const char* format, ...) -{ - va_list arglist; - va_start(arglist, format); - - int ret = vsnprintf(_printf_buf, PRINTF_BUFSIZ, format, arglist); - - if (ret > 0) { - ets_printf (_printf_buf); - } - - va_end(arglist); - - return ret; -} - -SpiFlashOpResult IRAM spi_flash_read (uint32_t faddr, uint32_t *dst, size_t size) -{ - /* - * For simplicity, we use the ROM function. Since we need to disable the - * IROM cache function for that purpose, we have to be IRAM. - * Please note, faddr, src and size have to be aligned to 4 byte. - */ - - SpiFlashOpResult ret; - - CHECK_PARAM_RET (dst != NULL, SPI_FLASH_RESULT_ERR); - CHECK_PARAM_RET (faddr + size <= flashchip->chip_size, SPI_FLASH_RESULT_ERR); - - critical_enter (); - Cache_Read_Disable (); - - ret = SPIRead (faddr, dst, size); - - Cache_Read_Enable(0, 0, 1); - critical_exit (); - - return ret; -} - -SpiFlashOpResult IRAM spi_flash_write (uint32_t faddr, uint32_t *src, size_t size) -{ - /* - * For simplicity, we use the ROM function. Since we need to disable the - * IROM cache function for that purpose, we have to be in IRAM. - * Please note, faddr, src and size have to be aligned to 4 byte - */ - - SpiFlashOpResult ret; - - CHECK_PARAM_RET (src != NULL, SPI_FLASH_RESULT_ERR); - CHECK_PARAM_RET (faddr + size <= flashchip->chip_size, SPI_FLASH_RESULT_ERR); - - critical_enter (); - Cache_Read_Disable (); - - ret = SPIWrite (faddr, src, size); - - Cache_Read_Enable(0, 0, 1); - critical_exit (); - - return ret; -} - -SpiFlashOpResult IRAM spi_flash_erase_sector(uint16_t sec) -{ - CHECK_PARAM_RET (sec < flashchip->chip_size / flashchip->sector_size, SPI_FLASH_RESULT_ERR); - - critical_enter (); - Cache_Read_Disable(); - - SpiFlashOpResult ret = SPIEraseSector (sec); - - Cache_Read_Enable(0, 0, 1); - critical_exit (); - - return ret; -} - -void system_deep_sleep(uint32_t time_in_us) -{ - /* TODO implement */ - (void)time_in_us; - NOT_YET_IMPLEMENTED(); -} - -void system_restart(void) -{ - /* TODO it's just a hard reset at the moment */ - __asm__ volatile (" call0 0x40000080 "); -} - -extern bool system_update_cpu_freq(uint8 freq) -{ - if (freq == 160) { - DPORT.CPU_CLOCK |= DPORT_CPU_CLOCK_X2; - ets_update_cpu_frequency(160); - } - else { - DPORT.CPU_CLOCK &= ~DPORT_CPU_CLOCK_X2; - ets_update_cpu_frequency(80); - } - return true; -} - -/** - * Following code is completly or at least partially from - * https://github.com/pvvx/esp8266web - * (c) PV` 2015 - * - * @{ - */ - -uint8_t ICACHE_FLASH_ATTR system_get_checksum(uint8_t *ptr, uint32_t len) -{ - uint8_t checksum = 0xEF; - while (len--) { - checksum ^= *ptr++; - } - return checksum; -} - -#define RTCMEM_SIZE 0x300 /* user RTC RAM 768 bytes, 192 dword registers */ - -static bool IRAM _system_rtc_mem_access (uint32_t src, void *dst, uint32_t size, bool write) -{ - /* src hast to be smaller than 192 */ - CHECK_PARAM_RET (src <= (RTCMEM_SIZE >> 2), false); - /* src times 4 plus size must less than RTCMEM_SIZE */ - CHECK_PARAM_RET (((src << 2) + size) < RTCMEM_SIZE, false); - /* des_addr has to be a multiple of 4 */ - CHECK_PARAM_RET (((uint32_t)dst & 0x3) == 0, false); - - /* align size to next higher multiple of 4 */ - if (size & 0x3) { - size = (size + 4) & ~0x3; - } - - for (uint32_t i = 0; i < (size >> 2); i++) { - if (write) { - RTCMEM_SYSTEM[src + i] = ((uint32_t*)dst)[i]; - } - else { - ((uint32_t*)dst)[i] = RTCMEM_SYSTEM[src + i]; - } - } - - return true; -} - -bool IRAM system_rtc_mem_read (uint32_t src_addr, void *des_addr, uint32_t save_size) -{ - return _system_rtc_mem_access (src_addr, des_addr, save_size, false); -} - -bool IRAM system_rtc_mem_write (uint32_t src_addr, void *des_addr, uint32_t save_size) -{ - return _system_rtc_mem_access (src_addr, des_addr, save_size, true); -} - -/** @} */ - -#endif /* MODULE_ESP_SDK */ diff --git a/cpu/esp8266/sdk/main.h b/cpu/esp8266/sdk/main.h deleted file mode 100644 index c946101c3194..000000000000 --- a/cpu/esp8266/sdk/main.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2018 Gunar Schorcht - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup cpu_esp8266_sdk - * @{ - * - * @file - * @brief ESP8266 SDK libmain function prototypes - * - * @author Gunar Schorcht - * @} - */ - -#ifndef MAIN_H -#define MAIN_H - -#ifndef DOXYGEN - -#include -#include - -#include "c_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef MODULE_ESP_SDK -#include "esp/dport_regs.h" - -/* - * The following functions are mappings or dummies for source code - * compatibility of SDK and NON-SDK version - */ - -#define system_get_time phy_get_mactime -#define system_get_chip_id() (((DPORT.OTP_MAC1 & 0xffff) << 8) + ((DPORT.OTP_MAC0 >> 24) & 0xff)) -#define system_get_cpu_freq ets_get_cpu_frequency - -extern int os_printf_plus (const char* format, ...); - -extern void system_deep_sleep (uint32_t time_in_us); -extern uint8_t system_get_checksum(uint8_t *ptr, uint32_t len); -extern void system_restart (void); -extern bool system_update_cpu_freq(uint8 freq); - -extern bool system_rtc_mem_read(uint32_t src_addr, void *des_addr, uint32_t save_size); -extern bool system_rtc_mem_write(uint32_t src_addr, void *des_addr, uint32_t save_size); - -#endif /* MODULE_ESP_SDK */ - -extern void NmiTimSetFunc(void (*func)(void)); - -#ifdef __cplusplus -} -#endif - -#endif /* DOXYGEN */ -#endif /* MAIN_H */ diff --git a/cpu/esp8266/sdk/phy.c b/cpu/esp8266/sdk/phy.c deleted file mode 100644 index 2c7d4a3ab24a..000000000000 --- a/cpu/esp8266/sdk/phy.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2018 Gunar Schorcht - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup cpu_esp8266_sdk - * @{ - * - * @file - * @brief ESP8266 SDK libphy functions - * - * @author Gunar Schorcht - * @} - */ - -#ifndef MODULE_ESP_SDK - -#include "sdk/phy.h" - -#endif /* MODULE_ESP_SDK */ diff --git a/cpu/esp8266/sdk/phy.h b/cpu/esp8266/sdk/phy.h index 8e06abc8045d..5909cdad0849 100644 --- a/cpu/esp8266/sdk/phy.h +++ b/cpu/esp8266/sdk/phy.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -25,29 +25,10 @@ #include #include -#include "c_types.h" - #ifdef __cplusplus extern "C" { #endif -#ifndef MODULE_ESP_SDK -/* - * The following functions are mappings or dummies for source code - * compatibility of SDK and NON-SDK version - */ - -#include "esp/dport_regs.h" - -extern void phy_afterwake_set_rfoption(int op); -extern int phy_check_data_table(void * gdctbl, int x, int flg); -extern int register_chipv6_phy(uint8_t * esp_init_data); -extern void sleep_reset_analog_rtcreg_8266(void); -extern uint32_t test_tout(bool); -extern void write_data_to_rtc(uint8_t *); - -#endif /* MODULE_ESP_SDK */ - extern uint32_t phy_get_mactime(void); #ifdef __cplusplus diff --git a/cpu/esp8266/sdk/pp.c b/cpu/esp8266/sdk/pp.c deleted file mode 100644 index 930de41b2b52..000000000000 --- a/cpu/esp8266/sdk/pp.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2018 Gunar Schorcht - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup cpu_esp8266_sdk - * @{ - * - * @file - * @brief ESP8266 other ROM functions - * - * @author Gunar Schorcht - * @} - */ - -#ifndef MODULE_ESP_SDK - -#include "sdk/pp.h" - -#endif /* MODULE_ESP_SDK */ diff --git a/cpu/esp8266/sdk/pp.h b/cpu/esp8266/sdk/pp.h deleted file mode 100644 index 490900436460..000000000000 --- a/cpu/esp8266/sdk/pp.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2018 Gunar Schorcht - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup cpu_esp8266_sdk - * @{ - * - * @file - * @brief ESP8266 SDK libpp function prototypes - * - * @author Gunar Schorcht - * @} - */ - -#ifndef PP_H -#define PP_H - -#ifndef DOXYGEN - -#ifdef __cplusplus -extern "C" { -#endif - -#include "c_types.h" - -#ifndef MODULE_ESP_SDK -/* - * The following functions are mappings or dummies for source code - * compatibility of SDK and NON-SDK version - */ - -#define system_soft_wdt_feed() - -#endif /* MODULE_ESP_SDK */ - -#ifdef __cplusplus -} -#endif - -#endif /* DOXYGEN */ -#endif /* PP_H */ diff --git a/cpu/esp8266/sdk/rom.c b/cpu/esp8266/sdk/rom.c deleted file mode 100644 index 377f10c0258a..000000000000 --- a/cpu/esp8266/sdk/rom.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2018 Gunar Schorcht - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup cpu_esp8266_sdk - * @{ - * - * @file - * @brief ESP8266 other ROM functions - * - * @author Gunar Schorcht - * @} - */ - -#ifndef MODULE_ESP_SDK - -#include "sdk/rom.h" - -#endif /* MODULE_ESP_SDK */ diff --git a/cpu/esp8266/sdk/rom.h b/cpu/esp8266/sdk/rom.h deleted file mode 100644 index e76862b375c6..000000000000 --- a/cpu/esp8266/sdk/rom.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2018 Gunar Schorcht - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup cpu_esp8266_sdk - * @{ - * - * @file - * @brief ESP8266 other ROM function prototypes - * - * @author Gunar Schorcht - * @} - */ - -#ifndef ROM_H -#define ROM_H - -#ifndef DOXYGEN - -#include -#include - -#include "c_types.h" -#include "spi_flash.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef MODULE_ESP_SDK -/* - * The following functions are mappings or dummies for source code - * compatibility of SDK and NON-SDK version - */ - -extern uint8_t rom_i2c_readReg(uint32_t block, uint32_t host_id, uint32_t reg_add); -extern uint8_t rom_i2c_readReg_Mask(uint32_t block, uint32_t host_id, - uint32_t reg_add,uint32_t Msb, uint32_t Lsb); -extern void rom_i2c_writeReg (uint32_t block, uint32_t host_id, - uint32_t reg_add, uint32_t data); -extern void rom_i2c_writeReg_Mask(uint32_t block, uint32_t host_id, - uint32_t reg_add, uint32_t Msb, uint32_t Lsb, - uint32_t indata); - -extern uint32_t rtc_get_reset_reason(void); - -#endif /* MODULE_ESP_SDK */ - -/* pointer to flash chip data structure */ -extern SpiFlashChip* flashchip; - -extern SpiFlashOpResult spi_flash_attach(void); - -void Cache_Read_Disable(void); -void Cache_Read_Enable (uint32_t odd_even, uint32_t mb_count, uint32_t no_idea); - -SpiFlashOpResult Wait_SPI_Idle(SpiFlashChip *chip); -SpiFlashOpResult SPI_write_enable(SpiFlashChip *chip); - -SpiFlashOpResult SPIEraseArea (uint32_t off, size_t len); -SpiFlashOpResult SPIEraseBlock (uint32_t num); -SpiFlashOpResult SPIEraseSector(uint32_t num); -SpiFlashOpResult SPIEraseChip (void); - -SpiFlashOpResult SPILock (void); -SpiFlashOpResult SPIUnlock(void); - -SpiFlashOpResult SPIRead (uint32_t off, uint32_t *dst, size_t size); -SpiFlashOpResult SPIWrite (uint32_t off, const uint32_t *src, size_t size); - -int SPIReadModeCnfig (uint32_t); - -/* set elements of flashchip, see struct SpiFlashChip; */ -SpiFlashOpResult SPIParamCfg (uint32_t deviceId, - uint32_t chip_size, - uint32_t block_size, - uint32_t sector_size, - uint32_t page_size, - uint32_t status_mask); - -extern void uartAttach (void); -extern void uart_div_modify(uint8 uart_no, uint32_t DivLatchValue); -extern void Uart_Init (uint8 uart_no); - -#ifdef __cplusplus -} -#endif - -#endif /* DOXYGEN */ -#endif /* ROM_H */ diff --git a/cpu/esp8266/sdk/sdk.h b/cpu/esp8266/sdk/sdk.h index c36ff451ade5..0ac779c78143 100644 --- a/cpu/esp8266/sdk/sdk.h +++ b/cpu/esp8266/sdk/sdk.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -20,25 +20,16 @@ #ifndef SDK_H #define SDK_H -#include "c_types.h" -#include "ets_sys.h" +#include #include "sdk/ets.h" -#include "sdk/main.h" #include "sdk/phy.h" -#include "sdk/pp.h" -#include "sdk/rom.h" -#include "sdk/user.h" +#include "sdk/system.h" #ifdef __cplusplus extern "C" { #endif -#ifdef MODULE_ESP_SDK -#include "espressif/osapi.h" -#include "espressif/user_interface.h" -#endif /* MODULE_ESP_SDK */ - #ifdef __cplusplus } #endif diff --git a/cpu/esp8266/sdk/system.c b/cpu/esp8266/sdk/system.c new file mode 100644 index 000000000000..c280c2297e2d --- /dev/null +++ b/cpu/esp8266/sdk/system.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_esp8266_sdk + * @{ + * + * @file + * @brief ESP8266 user defined SDK functions + * + * @author Gunar Schorcht + * @} + */ + +#include "sdk/sdk.h" + +#include "esp/dport_regs.h" +#include "esp_sleep.h" +#include "esp_system.h" + +uint32_t system_get_chip_id(void) +{ + /* Chip ID as determined by NONOS SDK */ + return (((DPORT.OTP_MAC1 << 8) & 0xffffff00) + ((DPORT.OTP_MAC0 >> 24) & 0xff)); +} + +const char* system_get_sdk_version(void) +{ + return esp_get_idf_version(); +} + +void system_deep_sleep(uint32_t time_in_us) +{ + /* TODO test */ + esp_deep_sleep(time_in_us); +} + +void system_restart(void) +{ + esp_restart(); +} + +void system_update_cpu_freq(uint8_t freq) +{ + if (freq == 160) { + rtc_clk_cpu_freq_set(RTC_CPU_FREQ_160M); + } + else { + rtc_clk_cpu_freq_set(RTC_CPU_FREQ_80M); + } +} diff --git a/cpu/esp8266/sdk/system.h b/cpu/esp8266/sdk/system.h new file mode 100644 index 000000000000..336865ae3a44 --- /dev/null +++ b/cpu/esp8266/sdk/system.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_esp8266_sdk + * @{ + * + * @file + * @brief ESP8266 user defined SDK function prototypes + * + * @author Gunar Schorcht + * @} + */ + +#ifndef SYSTEM_H +#define SYSTEM_H + +#ifndef DOXYGEN + +#include +#include + +#include "esp_task_wdt.h" +#include "sdk/ets.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Functions for NONOS SDK compatibility + * + * @{ + */ +extern uint8_t system_get_cpu_freq(void); +extern void system_update_cpu_freq(uint8_t); +extern uint32_t system_get_chip_id(void); +extern const char* system_get_sdk_version(void); + +extern void system_deep_sleep(uint32_t time_in_us); +extern void system_restart(void); + +#define system_wdt_init esp_task_wdt_init +#define system_wdt_feed esp_task_wdt_reset +#define system_wdt_start pp_soft_wdt_stop +#define system_wdt_stop pp_soft_wdt_restart + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* DOXYGEN */ +#endif /* SYSTEM_H */ diff --git a/cpu/esp8266/sdk/user.c b/cpu/esp8266/sdk/user.c deleted file mode 100644 index 707077ead1d7..000000000000 --- a/cpu/esp8266/sdk/user.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2018 Gunar Schorcht - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup cpu_esp8266_sdk - * @{ - * - * @file - * @brief ESP8266 user defined SDK functions - * - * @author Gunar Schorcht - * @} - */ - -#include "c_types.h" - -#include "common.h" -#include "cpu_conf.h" - -#include "esp/uart_regs.h" -#include "spi_flash.h" -#include "sdk/rom.h" -#include "sdk/user.h" - -uint32_t __attribute__((weak)) user_rf_cal_sector_set(void) -{ - uint32_t sec_num = flashchip->chip_size / flashchip->sector_size; - return sec_num - 5; -} - -#ifndef MODULE_ESP_SDK - -void uart_tx_flush (uint32_t num) -{ - while ((UART(num).STATUS >> UART_STATUS_TXFIFO_COUNT_S) & UART_STATUS_TXFIFO_COUNT_M) {} -} - -/** - * Following code is completly or at least partially from - * https://github.com/pvvx/esp8266web - * (c) PV` 2015 - * - * @{ - */ - -void IRAM system_set_pll (uint8_t crystal_26m_en) -{ - if(rom_i2c_readReg(103,4,1) != 136) { /* 8: 40MHz, 136: 26MHz */ - if (crystal_26m_en == 1) { /* 0: 40MHz, 1: 26MHz */ - /* set 80MHz PLL CPU */ - rom_i2c_writeReg(103,4,1,136); - rom_i2c_writeReg(103,4,2,145); - } - } -} - -/** @} */ - -#endif diff --git a/cpu/esp8266/sdk/user.h b/cpu/esp8266/sdk/user.h deleted file mode 100644 index ac0e13e35848..000000000000 --- a/cpu/esp8266/sdk/user.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2018 Gunar Schorcht - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - */ - -/** - * @ingroup cpu_esp8266_sdk - * @{ - * - * @file - * @brief ESP8266 user defined SDK function prototypes - * - * @author Gunar Schorcht - * @} - */ - -#ifndef USER_H -#define USER_H - -#ifndef DOXYGEN - -#include -#include - -#include "c_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef MODULE_ESP_SDK - -extern uint32_t user_rf_cal_sector_set(void); -extern void uart_tx_flush (uint32_t); -extern void system_set_pll (uint8_t); - -#endif /* MODULE_ESP_SDK */ - -#ifdef __cplusplus -} -#endif - -#endif /* DOXYGEN */ -#endif /* USER_H */ diff --git a/cpu/esp8266/startup.c b/cpu/esp8266/startup.c index 06aa705f55bc..a1649b595e93 100644 --- a/cpu/esp8266/startup.c +++ b/cpu/esp8266/startup.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -16,686 +16,82 @@ * @author Gunar Schorcht * @} */ - #define ENABLE_DEBUG 0 #include "debug.h" +#include +#include +#include +#include #include -#include #include "kernel_init.h" -#include "log.h" #include "periph/init.h" - -#include "c_types.h" -#include "spi_flash.h" +#include "periph/uart.h" #include "board.h" -#include "common.h" + +#include "esp/common_macros.h" +#include "esp_log.h" #include "exceptions.h" #include "stdio_base.h" #include "syscalls.h" -#include "tools.h" #include "thread_arch.h" -#include "esp/iomux_regs.h" -#include "esp/spi_regs.h" -#include "esp/xtensa_ops.h" +#include "rom_functions.h" #include "sdk/sdk.h" #if MODULE_ESP_GDBSTUB -#include "esp-gdbstub/gdbstub.h" -#endif - -extern void board_init(void); -extern void board_print_config(void); - -uint32_t hwrand (void); - -#ifdef MODULE_NEWLIB_SYSCALLS_DEFAULT -/* initialization as it should be called from newlibc */ -extern void _init(void); +#include "gdbstub.h" #endif -extern uint8_t _bss_start; -extern uint8_t _bss_end; -extern uint8_t _sheap; -extern uint8_t _eheap; - -#ifdef MODULE_ESP_SDK - -#include "sdk/ets_task.h" - -/* EST Task priority */ -#define ETS_TASK_PRIORITY (1) - -/* stack for the ETS task */ -static char ets_task_stack[ETS_THREAD_STACKSIZE]; -/* ETS task code */ -extern void *ets_task_func(void *arg); - -/** - * @brief System main loop called by the ETS - * - * This function is called by ETS after all initializations has been - * finished to start periodic processing of defined ETS tasks. We - * overwrite this ETS function to take over the control and to start RIOT. - */ -void ets_run(void) -{ - #if ENABLE_DEBUG - register uint32_t *sp __asm__ ("a1"); - ets_uart_printf("_stack %p\n", sp); - ets_uart_printf("_bss_start %p\n", &_bss_start); - ets_uart_printf("_bss_end %p\n", &_bss_end); - ets_uart_printf("_heap_start %p\n", &_sheap); - ets_uart_printf("_heap_end %p\n", &_eheap); - ets_uart_printf("_heap_free %lu\n", get_free_heap_size()); - #endif - - /* init min task priority */ - ets_task_min_prio = 0; - - #ifdef MODULE_NEWLIB_SYSCALLS_DEFAULT - _init(); - #endif - - ets_tasks_init(); - - /* enable interrupts used by ETS/SDK */ - ets_isr_unmask(BIT(ETS_FRC2_INUM)); - ets_isr_unmask(BIT(ETS_WDEV_INUM)); - ets_isr_unmask(BIT(ETS_WDT_INUM)); - - #ifdef MODULE_ESP_GDBSTUB - gdbstub_init(); - #endif - - #if ENABLE_DEBUG==0 - /* disable SDK messages */ - system_set_os_print(0); - #endif - - #ifdef CONTEXT_SWITCH_BY_INT - extern void IRAM thread_yield_isr(void* arg); - ets_isr_attach(ETS_SOFT_INUM, thread_yield_isr, NULL); - ets_isr_unmask(BIT(ETS_SOFT_INUM)); - #endif - - /* initialize dummy lwIP library to link it even if esp_wifi is not used */ - extern void esp_lwip_init(void); - esp_lwip_init(); +/* external esp function declarations */ +extern uint32_t hwrand (void); - thread_create(ets_task_stack, sizeof(ets_task_stack), - ETS_TASK_PRIORITY, - THREAD_CREATE_WOUT_YIELD | THREAD_CREATE_STACKTEST, - ets_task_func, NULL, "ets"); - - - /* does not return */ - kernel_init(); -} - -/** - * @brief Initialize the CPU, the board and the peripherals - * - * This function is called by ESP8266 SDK when all system initializations - * has been finished. - */ -void system_init(void) +void esp_riot_init(void) { - LOG_INFO("\nStarting ESP8266 CPU with ID: %08x", system_get_chip_id()); - LOG_INFO("\nSDK Version %s\n\n", system_get_sdk_version()); - - /* avoid reconnection all the time */ - wifi_station_disconnect(); - - /* set exception handlers */ - init_exceptions (); - - /* init random number generator */ - srand(hwrand()); - - /* init flash drive */ - extern void flash_drive_init (void); - flash_drive_init(); - - /* initialize stdio*/ - stdio_init(); - - /* trigger static peripheral initialization */ - periph_init(); - - /* trigger board initialization */ - board_init(); - - /* print memory info */ - print_meminfo(); + /* enable cached read from flash */ + Cache_Read_Enable_New(); - /* print the board config */ - board_print_config(); -} - - -/** - * @brief Entry point in user space after a system reset - * - * This function is called after system reset by the ESP8266 SDK. In this - * functions following steps are neccessary: - * - * 1. Reinit system timer as microsecond timer (precision is 500 us) - * 2. Set the UART parameters for serial output - * 3. Set the system initialization callback - */ + /* initialize the ISR stack for usage measurements */ + thread_isr_stack_init(); -void IRAM user_init (void) -{ +#ifndef MCU_ESP8266 + /* initialize newlib system calls */ syscalls_init (); - thread_isr_stack_init (); - - /* set system frequency */ - system_update_cpu_freq(ESP8266_CPU_FREQUENCY); - - /* reinit system timer as microsecond timer */ - system_timer_reinit (); - - /* setup the serial communication */ - uart_div_modify(0, UART_CLK_FREQ / STDIO_UART_BAUDRATE); - - /* once the ETS initialization is done we can start with our code as callback */ - system_init_done_cb(system_init); - - /* keep wifi interface in null mode per default */ - wifi_set_opmode_current (0); -} - -#else /* MODULE_ESP_SDK */ - -#include "esp/dport_regs.h" -#include "esp/phy_info.h" -#include "esp/spiflash.h" -#include "user_config.h" - -/** - * @brief Defines the structure of the file header in SPI flash - * - * @see https://github.com/espressif/esptool/wiki/Firmware-Image-Format - */ -typedef struct __attribute__((packed)) -{ - uint8_t magic; /* always 0xe9 */ - uint8_t segments; /* number of segments */ - uint8_t mode; /* 0 - qio, 1 - qout, 2 - dio, 3 - dout */ - uint8_t speed:4; /* 0 - 40 MHz, 1 - 26 MHz, 2 - 20 MHz, 15 - 80 MHz */ - uint8_t size:4; /* 0 - 512 kB, 1 - 256 kB, 2 - 1 MB, 3 - 2 MB, 4 - 4 MB */ - -} _spi_flash_header; - -#define SPI_FLASH_SECTOR_SIZE 4096 - -struct s_info { - uint32 ap_ip; /* +00 */ - uint32 ap_mask; /* +04 */ - uint32 ap_gw; /* +08 */ - uint32 st_ip; /* +0C */ - uint32 st_mask; /* +10 */ - uint32 st_gw; /* +14 */ - uint8 ap_mac[6]; /* +18 */ - uint8 st_mac[6]; /* +1E */ -} __attribute__((packed, aligned(4))); - -static struct s_info info; - -enum rst_reason { - REASON_DEFAULT_RST = 0, - REASON_WDT_RST = 1, - REASON_EXCEPTION_RST = 2, - REASON_SOFT_WDT_RST = 3, - REASON_SOFT_RESTART = 4, - REASON_DEEP_SLEEP_AWAKE = 5, - REASON_EXT_SYS_RST = 6 -}; - -struct rst_info{ - uint32 reason; - uint32 exccause; - uint32 epc1; - uint32 epc2; - uint32 epc3; - uint32 excvaddr; - uint32 depc; -}; - -/** - * @brief System configuration store formats - * - * source https://github.com/pvvx/esp8266web - * (c) PV` 2015 - * - * @{ - */ - -/* SDK 2.0.0 */ -#define wifi_config_size 0x494 /* 1172 bytes */ -#define g_ic_size (wifi_config_size + 532) /* 1704 bytes */ - -struct ets_store_wifi_hdr { /* Sector flash addr flashchip->chip_size-0x1000 (0x4027F000) */ - uint8 bank; /* +00 = 0, 1 WiFi config flash addr: */ - /* 0 - flashchip->chip_size-0x3000 (0x7D000), */ - /* 1 - flashchip->chip_size-0x2000 */ - uint8 unused[3]; /* +01 = 0xff, 0xff, 0xff */ - uint32 flag; /* +04 = 0x55aa55aa */ - uint32 wr_cnt; /* +08 = 0x00000001 */ - uint32 len[2]; /* +12 = 0x00000020, 0xffffffff */ - uint32 chk[2]; /* +20 = 0x000000ed, 0xffffffff */ - uint32 flag2; /* +28 = 0xaa55aa55 */ -}; - -static const uint8_t -ets_store_wifi_hdr_default[sizeof(struct ets_store_wifi_hdr)] = -{ - 0x00, 0xff, 0xff, 0xff, 0xaa, 0x55, 0xaa, 0x55, - 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xed, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x55, 0xaa, 0x55, 0xaa -}; - -struct s_wifi_store { /* WiFi config flash addr: flashchip->chip_size - 0x3000 or -0x2000 */ - /* SDK >= 2.0.0 */ - uint8 boot_info[8]; /* +000 0x000 (boot_info[1]) boot_version */ - uint8 wfmode[4]; /* +008 0x008 */ - uint32 st_ssid_len; /* +012 0x00c */ - uint8 st_ssid[32]; /* +016 0x010 */ - uint8 field_048[7]; /* +048 0x030 */ - uint8 st_passw[64]; /* +055 0x037 */ - uint8 field_119; /* +119 0x077 */ - uint8 data_120[32]; /* +120 0x078 */ - uint8 field_152[17]; /* +152 0x098 */ - uint8 field_169; /* +169 0x0a9 */ - uint8 field_170[6]; /* +170 0x0aa */ - uint32 ap_ssid_len; /* +176 0x0b0 */ - uint8 ap_ssid[32]; /* +180 0x0b4 */ - uint8 ap_passw[64]; /* +212 0x0d4 */ - uint8 field_276[32]; /* +276 0x114 */ - uint8 field_308; /* +308 0x134 */ - uint8 wfchl; /* +309 0x135 */ - uint8 field_310; /* +310 0x136 */ - uint8 field_311; /* +311 0x137 */ - uint8 field_312; /* +312 0x138 */ - uint8 field_313; /* +313 0x139 */ - uint8 field_314; /* +314 0x13a */ - uint8 field_315; /* +315 0x13b */ - uint16 field_316; /* +316 0x13c */ - uint8 field_318[2]; /* +318 0x13e */ - uint32 st1ssid_len; /* +320 0x140 */ - uint8 st1ssid[32]; /* +324 0x144 */ - uint8 st1passw[64]; /* +356 0x164 */ - uint8 field_420[400]; /* +420 0x1a4 */ - uint32 field_820[3]; /* +820 0x334 */ - uint8 field_832[4]; /* +832 0x340 wifi_station_set_auto_connect */ - uint32 phy_mode; /* +836 0x344 */ - uint8 field_840[36]; /* +840 0x348 */ - uint16 beacon; /* +876 0x36c 876+532 g_ic+1408 */ - uint8 field_878[2]; /* +878 0x36e */ - uint32 field_880; /* +880 0x370 */ - uint32 field_884; /* +884 0x374 */ - uint32 field_888; /* +888 0x378 */ - uint8 field_892[284]; /* +892 0x37c ... 1176 0x498 */ -}; - -struct s_g_ic { - uint32 boot_info; /* +0000 g_ic+0 0x3FFF2324 boot_version? */ - uint32 field_004; /* +0004 g_ic+4 */ - uint32 field_008; /* +0008 g_ic+8 */ - uint32 field_00C; /* +000C g_ic+12 */ - struct netif **netif1; /* +0010 g_ic+16 */ - struct netif **netif2; /* +0014 g_ic+20 */ - uint32 field_018; /* +0018 g_ic+24 */ - uint32 field_01C; /* +001C g_ic+28 */ - uint32 field_020; /* +0020 g_ic+32 */ - uint32 field_024; /* +0024 g_ic+36 */ - uint32 field_028; /* +0028 g_ic+40 */ - uint8 field_02C[84]; /* +002C g_ic+44 */ - uint32 field_080; /* +0080 g_ic+128 */ - uint8 field_084[200]; /* +0084 g_ic+132 */ - /* [0x12c] */ - void * field_14C; /* +014C g_ic+332 */ - uint32 ratetable; /* +0150 g_ic+336 */ - uint8 field_154[44]; /* +0154 g_ic+340 */ - uint32 field_180; /* +0180 g_ic+384 */ - /* [0x170..0x180] wifi_get_user_ie */ - void * field_184; /* +0184 g_ic+388 user_ie_manufacturer_recv_cb */ - uint32 field_188; /* +0188 g_ic+392 */ - uint32 field_18C; /* +018C g_ic+396 */ - uint32 field_190; /* +0190 g_ic+400 */ - uint32 field_194; /* +0194 g_ic+404 */ - uint32 field_198; /* +0198 g_ic+408 */ - uint32 field_19C; /* +019C g_ic+412 */ - uint32 field_1A0; /* +01A0 g_ic+416 */ - uint32 field_1A4; /* +01A4 g_ic+420 */ - uint32 field_1A8; /* +01A8 g_ic+424 */ - uint32 field_1AC; /* +01AC g_ic+428 */ - uint32 field_1B0; /* +01B0 g_ic+432 */ - uint32 field_1B4; /* +01B4 g_ic+436 */ - uint32 field_1B8; /* +01B8 g_ic+440 */ - uint32 field_1BC; /* +01BC g_ic+444 */ - uint32 field_1C0; /* +01C0 g_ic+448 */ - uint32 field_1C4; /* +01C4 g_ic+452 */ - uint32 field_1C8[19]; /* +01C8 g_ic+456 ...532 */ - struct s_wifi_store wifi_store; /* g_ic+??? */ -}; - -typedef union _u_g_ic{ - struct s_g_ic g; - uint8 c[g_ic_size]; - uint16 w[g_ic_size/2]; - uint32 d[g_ic_size/4]; -} u_g_ic; - -static u_g_ic g_ic; - -/** }@ */ - -/** - * Following functions are from https://github.com/pvvx/esp8266web - * (c) PV` 2015 - * - * @{ - */ -void read_macaddr_from_otp(uint8_t* mac) -{ - /* fixed prefix */ - mac[0] = 0x18; - mac[1] = 0xfe; - mac[2] = 0x34; - - if ((!(DPORT.OTP_CHIPID & (1 << 15))) || - ((DPORT.OTP_MAC0 == 0) && (DPORT.OTP_MAC1 == 0))) { - mac[3] = 0x18; - mac[4] = 0xfe; - mac[5] = 0x34; - } - else { - mac[3] = (DPORT.OTP_MAC1 >> 8) & 0xff; - mac[4] = DPORT.OTP_MAC1 & 0xff; - mac[5] = (DPORT.OTP_MAC0 >> 24) & 0xff; - } -} - -int ICACHE_FLASH_ATTR flash_data_check(uint8 *check_buf) -{ - uint32 cbuf[32]; - uint32 *pcbuf = cbuf; - uint8 *pbuf = check_buf; - int i = 27; - while (i--) { - *pcbuf = pbuf[0] | (pbuf[1]<<8) | (pbuf[2]<<16) | (pbuf[3]<<24); - pcbuf++; - pbuf+=4; - } - cbuf[24] = (DPORT.OTP_MAC1 & 0xFFFFFFF) | ((DPORT.OTP_CHIPID & 0xF000) << 16); - cbuf[25] = (DPORT.OTP_MAC2 & 0xFFFFFFF) | (DPORT.OTP_MAC0 & 0xFF000000); - pcbuf = cbuf; - uint32 xsum = 0; - do { - xsum += *pcbuf++; - } while (pcbuf != &cbuf[26]); - xsum ^= 0xFFFFFFFF; - if (cbuf[26] != xsum) { - return 1; - } - return 0; -} - -/** }@ */ - - -/** - * @brief Startup function hook placed at 0x40100000 - */ -void __attribute__((section(".UserEnter.text"))) NORETURN _call_user_start_hook(void) -{ - __asm__ volatile ( - " vectors_base: .word 0x40100000 \n" /* must contain entry point */ - " \n" - " _call_user_start: \n" /* system startup function */ - " .global _call_user_start \n" - " l32r a2, vectors_base \n" /* set vector base */ - " wsr a2, vecbase \n" - " call0 cpu_user_start \n" /* call startup function */ - ); - UNREACHABLE(); -} - -void ICACHE_FLASH_ATTR start_phase2 (void); - -/** - * @brief Startup function - * - * This function is the entry point in the user application. It is called - * after a system reset to startup the system. - */ -void __attribute__((noreturn)) IRAM cpu_user_start (void) -{ - register uint32_t *sp __asm__ ("a1"); (void)sp; - - /* PHASE 1: startup in SDK */ - - struct rst_info rst_if = { .reason = 0 }; - system_rtc_mem_read(0, &rst_if, sizeof(struct rst_info)); - - /** - * Setup the serial communication speed. After cold start UART_CLK_FREQ is - * only 26/40 (65 %). So the baud rate would be only 74880. To have 115200 - * at the beginning of the cold start, we have to set it to 177231 baud. - * This is changed later in function system_set_pll. - */ - system_set_pll(1); /* parameter is fix (from esp_init_data_default.bin byte 48) */ - - #if 0 - if (rst_if.reason > REASON_DEFAULT_RST) { - /* warm start */ - uart_div_modify(0, UART_CLK_FREQ / STDIO_UART_BAUDRATE); - } - else { - /* cold start */ - uart_div_modify(0, UART_CLK_FREQ / 177231); - } - #else - uart_div_modify(0, UART_CLK_FREQ / STDIO_UART_BAUDRATE); - #endif - - /* flush uart_tx_buffer */ - ets_uart_printf(" \n"); - - #if ENABLE_DEBUG - ets_uart_printf("reset reason: %d %d\n", rst_if.reason, rtc_get_reset_reason()); - ets_uart_printf("exccause=%ld excvaddr=%08lx\n", rst_if.exccause, rst_if.excvaddr); - ets_uart_printf("epc1=%08lx epc2=%08lx epc3=%08lx\n", rst_if.epc1, rst_if.epc2, rst_if.epc3); - ets_uart_printf("depc=%ld\n", rst_if.depc); - ets_uart_printf("_stack %p\n", sp); - ets_uart_printf("_bss_start %p\n", &_bss_start); - ets_uart_printf("_bss_end %p\n", &_bss_end); - ets_uart_printf("_heap_start %p\n", &_sheap); - ets_uart_printf("_heap_end %p\n", &_eheap); - ets_uart_printf("_heap_free %lu\n", get_free_heap_size()); - #endif - - uint32_t flash_sectors; - uint32_t flash_size; - - _spi_flash_header flash_header; - - SPI(0).USER0 |= SPI_USER0_CS_SETUP; - SPIRead(0, (uint32_t*)&flash_header, 4); - - assert (flash_header.magic == 0xe9); - - /* SPI flash sectors a 4.096 byte */ - switch (flash_header.size) { - case 0: flash_sectors = 128; break; /* 512 kByte */ - case 1: flash_sectors = 64; break; /* 256 kByte */ - case 2: flash_sectors = 256; break; /* 1 MByte */ - case 3: flash_sectors = 512; break; /* 2 MByte */ - case 4: flash_sectors = 1024; break; /* 4 MByte */ - default: flash_sectors = 128; break; /* default 512 kByte */ - } - - flash_size = flash_sectors * SPI_FLASH_SECTOR_SIZE; - - flashchip->chip_size = flash_size; - flashchip->sector_size = SPI_FLASH_SECTOR_SIZE; - - /* - * SPI flash speed params - * speed = 80MHz / clkdiv_pre / clkcnt_N - */ - uint32_t clkdiv_pre = 1; /* default 40 MHz = 80 MHz / 1 / 2 */ - uint32_t clkcnt_N = 2; - - switch (flash_header.speed) { - case 0: clkdiv_pre = 1; /* 40 MHz = 80 MHz / 1 / 2 */ - clkcnt_N = 2; - break; - - case 1: clkdiv_pre = 1; /* 26 MHz = 80 MHz / 1 / 3 */ - clkcnt_N = 3; - break; - - case 2: clkdiv_pre = 1; /* 20 MHz = 80 MHz / 1 / 4 */ - clkcnt_N = 4; - break; - - case 15: clkdiv_pre = 0; /* clock is equal to system clock */ - break; - - default: break; - } - - if (clkdiv_pre) { - IOMUX.CONF &= ~IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK; - SPI(0).CLOCK = VAL2FIELD_M(SPI_CLOCK_DIV_PRE, clkdiv_pre - 1) | - VAL2FIELD_M(SPI_CLOCK_COUNT_NUM, clkcnt_N - 1) | - VAL2FIELD_M(SPI_CLOCK_COUNT_HIGH, clkcnt_N/2 - 1) | - VAL2FIELD_M(SPI_CLOCK_COUNT_LOW, clkcnt_N - 1); - } - else { - IOMUX.CONF |= IOMUX_CONF_SPI0_CLOCK_EQU_SYS_CLOCK; - SPI(0).CLOCK |= SPI_CLOCK_EQU_SYS_CLOCK; - } - - ets_uart_printf("Flash size: %lu byte, speed %d MHz", - flash_size, clkdiv_pre ? 80 / clkdiv_pre / clkcnt_N : 80); - - switch (flash_header.mode) { - case 0: ets_printf(", mode QIO\n"); break; - case 1: ets_printf(", mode QOUT\n"); break; - case 2: ets_printf(", mode DIO\n"); break; - case 3: ets_printf(", mode DOUT\n"); break; - default: ets_printf("\n"); - } - - ets_uart_printf("\nStarting ESP8266 CPU with ID: %08x\n\n", system_get_chip_id()); - - /* clear .bss to avoid startup problems because of compiler optimization options */ - memset(&_bss_start, 0x0, &_bss_end-&_bss_start); - - /** - * Following parts of code are partially from or inspired by the - * following projects: - * - * [esp8266web](https://github.com/pvvx/esp8266web) - * (c) PV` 2015 - * - * [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos.git). - * Copyright (C) 2015 Superhouse Automation Pty Ltd - * BSD Licensed as described in the file LICENSE - * - * @{ - */ - struct ets_store_wifi_hdr binfo; - struct s_wifi_store wscfg; - - /* load boot info (32 byte) from last sector and */ - uint32_t binfo_addr = flash_size - SPI_FLASH_SECTOR_SIZE; - SPIRead (binfo_addr, (uint32_t*)&binfo, sizeof(binfo)); - - /* load the system config (1176 byte) from last 3 or 2 sectors */ - uint32_t wscfg_addr = flash_size - (binfo.bank ? 2 : 3) * SPI_FLASH_SECTOR_SIZE; - SPIRead (wscfg_addr, (uint32_t*)&wscfg, sizeof(wscfg)); - - Cache_Read_Enable(0, 0, 1); - - #if ENABLE_DEBUG - printf("boot_inf sector @0x%x\n", flash_size - SPI_FLASH_SECTOR_SIZE); - esp_hexdump(&binfo, sizeof(binfo), 'b', 16); - #endif - - LOG_INFO("load boot_inf 0x%x, len %d, chk %02x\n", - binfo_addr, sizeof(binfo), - system_get_checksum((uint8_t*)&binfo, sizeof(binfo))); - LOG_INFO("load wifi_cfg 0x%x, len %d, chk %02x\n", - wscfg_addr, sizeof(wscfg), - system_get_checksum((uint8_t*)&wscfg, sizeof(wscfg))); - - /* check whether boot_inf sector could be loaded */ - if (binfo.bank > 0 && binfo.flag == 0xffffffff) { - LOG_INFO("no boot_inf sector @0x%x, write a default one to flash\n", binfo_addr); - memcpy (&binfo, ets_store_wifi_hdr_default, sizeof(binfo)); - spi_flash_write (binfo_addr, (uint32_t*)&binfo, sizeof(binfo)); - - } - - /* check the checksum */ - if (binfo.flag == 0x55aa55aa && - binfo.chk[binfo.bank] == system_get_checksum((uint8_t*)&wscfg, binfo.len[binfo.bank])) { - /* checksum test is ok */ - } - else { - /* checksum error but continue */ - LOG_INFO("flash check sum error @0x%x\n", wscfg_addr); - - /* check whether there is no wifi_cfg sector */ - uint8_t* wscfg_sec = (uint8_t*)&wscfg; - size_t i = 0; - for ( ; i < sizeof(wscfg); i++) { - if (wscfg_sec[i] != 0xff) { - break; - } - } +#endif - /* no data different from 0xff found, we assume that the flash was erased */ - if (i == sizeof(wscfg)) { - /* TODO write a default wifi_cfg sector automatically into the flash in that case */ - LOG_INFO("\nno wifi_cfg sector found, use following command:\n" - "esptool.py write_flash 0x%x $(RIOT_CPU)/bin/wifi_cfg_default.bin\n\n", - wscfg_addr); - } + /* set system frequency if not 80 MHz */ + if (ESP8266_CPU_FREQUENCY != 80) { + system_update_cpu_freq(ESP8266_CPU_FREQUENCY); } - memcpy(&g_ic.g.wifi_store, &wscfg, sizeof(wscfg)); - uart_tx_flush(0); - uart_tx_flush(1); + ets_printf("\n"); + ets_printf("Starting ESP8266 CPU with ID: %08x\n", system_get_chip_id()); + ets_printf("ESP8266-RTOS-SDK Version %s\n\n", system_get_sdk_version()); + ets_printf("CPU clock frequency: %d MHz\n", system_get_cpu_freq()); + extern void heap_stats(void); + heap_stats(); + ets_printf("\n"); + /* set exception handlers */ init_exceptions (); - /* PHASE 2: sdk_init in SDK */ - - start_phase2(); - - /** }@ */ + /* systemwide UART initialization */ + extern void uart_system_init (void); + uart_system_init(); - /* set system frequency */ - system_update_cpu_freq(ESP8266_CPU_FREQUENCY); - - /* PHASE 3: start RIOT-OS kernel */ + /* init watchdogs */ + system_wdt_init(); /* init random number generator */ srand(hwrand()); +#if MODULE_MTD /* init flash drive */ - extern void flash_drive_init (void); - flash_drive_init(); + extern void spi_flash_drive_init (void); + spi_flash_drive_init(); +#endif /* initialize stdio*/ stdio_init(); @@ -703,164 +99,44 @@ void __attribute__((noreturn)) IRAM cpu_user_start (void) /* trigger static peripheral initialization */ periph_init(); - /* initialize the board and startup the kernel */ + /* trigger board initialization */ board_init(); - /* print memory info */ - print_meminfo(); - /* print the board config */ board_print_config(); - #ifdef MODULE_NEWLIB_SYSCALLS_DEFAULT - _init(); - #endif + /* initialize ESP system event loop */ + extern void esp_event_handler_init(void); + esp_event_handler_init(); - #ifdef MODULE_ESP_GDBSTUB - gdbstub_init(); - #endif - - #ifdef CONTEXT_SWITCH_BY_INT + /* activate software interrupt based context switch */ extern void IRAM thread_yield_isr(void* arg); ets_isr_attach(ETS_SOFT_INUM, thread_yield_isr, NULL); ets_isr_unmask(BIT(ETS_SOFT_INUM)); - #endif - - /* startup the kernel */ - kernel_init(); - /* should not be reached */ - UNREACHABLE() ; +#ifdef MODULE_ESP_GDBSTUB + gdbstub_init(); +#endif } - -void start_phase2 (void) +void esp_riot_start(void) { - uint32_t flash_size = flashchip->chip_size; - struct rst_info rst_if; - - system_rtc_mem_read(0, &rst_if, sizeof(struct rst_info)); - - /** - * Following parts of code are partially from or inspired by the - * following projects: - * - * [esp8266web](https://github.com/pvvx/esp8266web) - * (c) PV` 2015 - * - * [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos.git). - * Copyright (C) 2015 Superhouse Automation Pty Ltd - * BSD Licensed as described in the file LICENSE - * - * @{ - */ - - /* changes clock freqeuncy and should be done before system_set_pll */ - sleep_reset_analog_rtcreg_8266(); - - /* set correct system clock and adopt UART frequency */ - system_set_pll(1); /* parameter is fixed (from esp_init_data_default.bin byte 48) */ - uart_div_modify(0, UART_CLK_FREQ / STDIO_UART_BAUDRATE); - uart_tx_flush(0); - uart_tx_flush(1); - - syscalls_init (); - thread_isr_stack_init (); - - read_macaddr_from_otp(info.st_mac); - LOG_INFO("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - info.st_mac[0], info.st_mac[1], info.st_mac[2], - info.st_mac[3], info.st_mac[4], info.st_mac[5]); - - /* load esp_init_data_default.bin */ - uint8_t* pbuf = malloc(1024); (void)pbuf; - uint32_t phy_info_addr = flash_size - 4 * SPI_FLASH_SECTOR_SIZE; - - sdk_phy_info_t* phy_info = (sdk_phy_info_t*)pbuf; - spi_flash_read (phy_info_addr, (uint32_t*)phy_info, sizeof(sdk_phy_info_t)); - - LOG_INFO("load phy_info 0x%x, len %d, chk %02x\n", - phy_info_addr, sizeof(sdk_phy_info_t), - system_get_checksum((uint8_t*)phy_info, sizeof(sdk_phy_info_t))); - - /* load rf_cal_sec (default rf_cal_sec = flash_sectors - 5) */ - uint32_t rf_cal_sec = user_rf_cal_sector_set(); - uint32_t rf_cal_sec_addr = rf_cal_sec * SPI_FLASH_SECTOR_SIZE; - spi_flash_read (rf_cal_sec_addr, (uint32_t*)(pbuf + 128), 628); - - LOG_INFO("rf_cal_sec=%d\n", rf_cal_sec); - LOG_INFO("load rf_cal 0x%x, len %d, chk %02x\n", - rf_cal_sec_addr, 628, system_get_checksum(pbuf + 128, 628)); - LOG_INFO("reset reason: %d %d\n", rst_if.reason, rtc_get_reset_reason()); - - #if ENABLE_DEBUG - printf("phy_info sector @0x%x\n", phy_info_addr); - esp_hexdump(pbuf, 128, 'b', 16); - - printf("rf_cal sector @0x%x\n", rf_cal_sec_addr); - /* esp_hexdump(pbuf+128, 628, 'b', 16); */ - #endif - - sdk_phy_info_t default_phy_info; - get_default_phy_info(&default_phy_info); - - if (phy_info->version != default_phy_info.version) { - /* check whether there is no phy_info sector */ - uint8_t* phy_info_sec = (uint8_t*)phy_info; - size_t i = 0; - for ( ; i < sizeof(sdk_phy_info_t); i++) { - if (phy_info_sec[i] != 0xff) { - break; - } - } - - /* no data different from 0xff found, we assume that the flash was erased */ - if (i == sizeof(sdk_phy_info_t)) { - /* write a default default phy_info sector into the flash */ - LOG_INFO("no phy_info sector found @0x%x, " - "writing esp_init_data_default.bin into flash\n", - phy_info_addr); - spi_flash_write (phy_info_addr, - (uint32_t*)&default_phy_info, sizeof(sdk_phy_info_t)); - } - - LOG_INFO("set default esp_init_data!\n"); - memcpy(pbuf, &default_phy_info, sizeof(sdk_phy_info_t)); - } - - extern uint8_t* phy_rx_gain_dc_table; - extern uint8_t phy_rx_gain_dc_flag; - - phy_rx_gain_dc_table = &pbuf[0x100]; - phy_rx_gain_dc_flag = 0; - - int xflg = (flash_data_check(&pbuf[128]) != 0 || - phy_check_data_table(phy_rx_gain_dc_table, 125, 1) != 0) ? 1 : 0; - - if (rst_if.reason != REASON_DEEP_SLEEP_AWAKE) { - phy_afterwake_set_rfoption(1); - if (xflg == 0) { - write_data_to_rtc(pbuf+128); - } - } - - g_ic.c[491] = ((phy_info->freq_correct_mode & 7 )== 3) ? 1 : 0; - pbuf[0xf8] = 0; - - /* clear RTC memory */ - memset(&rst_if, 0, sizeof(struct rst_info)); - system_rtc_mem_write(0, &rst_if, sizeof(struct rst_info)); - - uart_tx_flush(0); - uart_tx_flush(1); - - if (register_chipv6_phy(pbuf)) { - LOG_ERROR ("register_chipv6_phy failed"); - } - - free (pbuf); + /* does not return */ + kernel_init(); +} - /** @} */ +void __wrap_pp_attach(void) +{ +#ifdef MODULE_ESP_WIFI_ANY + extern void __real_pp_attach(void); + __real_pp_attach(); +#endif } -#endif /* MODULE_ESP_SDK */ +void __wrap_pm_attach(void) +{ +#ifdef MODULE_ESP_WIFI_ANY + extern void __real_pm_attach(void); + __real_pm_attach(); +#endif +} diff --git a/cpu/esp8266/syscalls.c b/cpu/esp8266/syscalls.c index a3b99087c933..b8486903c17e 100644 --- a/cpu/esp8266/syscalls.c +++ b/cpu/esp8266/syscalls.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -18,342 +18,589 @@ * @} */ -#define ENABLE_DEBUG 0 -#define MEMLEAK_DEBUG 0 -#include "debug.h" - -#include -#include -#include -#include +#include "periph/pm.h" +#include "timex.h" -#include -#include -#include +#include #include #include -#include - -#include "ets_sys.h" -#include "c_types.h" +#include +#include +#include +#include +#include -#include "common.h" -#include "cpu_conf.h" -#include "irq.h" -#include "kernel_defines.h" -#include "log.h" #include "mutex.h" #include "rmutex.h" -#include "sched.h" -#include "syscalls.h" -#include "esp/xtensa_ops.h" +#include "esp_common.h" #include "esp/common_macros.h" - +#include "esp_attr.h" #include "sdk/sdk.h" +#include "syscalls.h" -#ifdef MODULE_ESP_SDK -/** - * Map memory management functions to SDK memory management functions. - * This is necessary to use the same heap as the SDK internally does. - * Furthermore, these functions at least avoid interrupts during the - * execution of memory management functions. Memory management functions - * of ETS are not used and have not to be considered therefore. - */ -extern void *pvPortMalloc (size_t size, const char *, unsigned); -extern void vPortFree (void *ptr, const char *, unsigned); -extern void *pvPortZalloc (size_t size, const char *, unsigned); -extern void *pvPortCalloc (size_t nmemb, size_t size, const char *, unsigned); -extern void *pvPortRealloc (void *ptr, size_t size, const char *, unsigned); -extern unsigned int xPortGetFreeHeapSize(void); +#ifdef MODULE_STDIO_UART +#include "stdio_uart.h" +#endif -void *__real_malloc(size_t size); -void __real_free(void *ptr); -void *__real_calloc(size_t nmemb, size_t size); -void *__real_realloc(void *ptr, size_t size); -void *__real__malloc_r (struct _reent *r, size_t size); -void __real__free_r (struct _reent *r, void *ptr); -void *__real__realloc_r (struct _reent *r, void *ptr, size_t size); +#ifdef MODULE_ESP_IDF_HEAP +#include "esp_heap_caps.h" +#else +#include "malloc.h" +#endif -extern uint8_t _eheap; /* end of heap (defined in esp8266.riot-os.app.ld) */ -extern uint8_t _sheap; /* start of heap (defined in esp8266.riot-os.app.ld) */ +#define ENABLE_DEBUG (0) +#include "debug.h" -void* IRAM __wrap_malloc(size_t size) -{ - #if MEMLEAK_DEBUG - static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; - return pvPortMalloc(size, mem_debug_file, __LINE__); - #else - return pvPortMalloc(size, "", 0); - #endif -} +#define MHZ 1000000UL -void IRAM __wrap_free(void *ptr) -{ - #if MEMLEAK_DEBUG - static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; - return vPortFree (ptr, mem_debug_file, __LINE__); - #else - return vPortFree (ptr, "", 0); - #endif -} +#ifndef MODULE_PTHREAD -void* IRAM __wrap_calloc(size_t nmemb, size_t size) +#define PTHREAD_CANCEL_DISABLE 1 +/* + * This is a dummy function to avoid undefined references when linking + * against newlib and module pthread is not used. + */ +int pthread_setcancelstate(int state, int *oldstate) { - #if MEMLEAK_DEBUG - static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; - return pvPortCalloc(nmemb, size, mem_debug_file, __LINE__); - #else - return pvPortCalloc(nmemb, size, "", 0); - #endif + if (oldstate) { + *oldstate = PTHREAD_CANCEL_DISABLE; + } + return 0; } +#endif /* MODULE_PTHREAD */ -void* IRAM __wrap_realloc(void *ptr, size_t size) -{ - #if MEMLEAK_DEBUG - static const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__; - return pvPortRealloc(ptr, size, mem_debug_file, __LINE__); - #else - return pvPortRealloc(ptr, size, "", 0); - #endif -} +/* + * TODO: When the lock functions in this section are enabled, an application + * crashes when an ISR calls a `newlib` function that uses `_lock_acquire` + * or `_log_acquire_recursive` to be thread-safe, for example, `puts` in + * `tests/isr_yield_higher`. The reason is that the implementation of these + * functions uses `mutex` and `rmutex` that do not work in the interrupt + * context. Therefore, the lock functions are disabled for the moment, and + * instead `newlib`'s dummy lock functions are used which do not guarantee + * thread safety. + */ + +#if 0 + +/** + * @name Locking functions + * + * Following functions implement the lock mechanism for newlib. + */ -void* IRAM __wrap__malloc_r (struct _reent *r, size_t size) +/** + * _malloc_rmtx is defined as static variable to avoid recursive calls of + * malloc when _malloc_r tries to lock __malloc_lock_object the first + * time. All other mutexes that are used for the lock mechanism are allocated + * dynamically. + */ +static rmutex_t _malloc_rmtx = RMUTEX_INIT; + +/** + * To properly handle the static rmutex _malloc_rmtx, we have to know + * the address of newlib's static variable __malloc_lock_object. + */ +static _lock_t *__malloc_static_object = NULL; + +void IRAM _lock_init(_lock_t *lock) { - return __wrap_malloc (size); + assert(lock != NULL); + + mutex_t* mtx = malloc(sizeof(mutex_t)); + + if (mtx) { + memset(mtx, 0, sizeof(mutex_t)); + *lock = (_lock_t)mtx; + } } -void IRAM __wrap__free_r (struct _reent *r, void *ptr) +void IRAM _lock_init_recursive(_lock_t *lock) { - __wrap_free (ptr); + assert(lock != NULL); + + /** + * Since we don't have direct access to newlib's static variable + * __malloc_lock_object, we have to rely on the fact that function + * _lock_aqcuire_recursive, and thus function _lock_init_recursive + * is called for the first time with newlib's static variable + * __malloc_lock_object as parameter. This is ensured by calling + * malloc in the function syscalls_init. + */ + if (__malloc_static_object == NULL) { + *lock = (_lock_t)&_malloc_rmtx; + __malloc_static_object = lock; + return; + } + + /* _malloc_rmtx is static and has not to be allocated */ + if (lock == __malloc_static_object) { + return; + } + + rmutex_t* rmtx = malloc(sizeof(rmutex_t)); + + if (rmtx) { + memset(rmtx, 0, sizeof(rmutex_t)); + *lock = (_lock_t)rmtx; + } } -void IRAM *__wrap__realloc_r (struct _reent *r, void *ptr, size_t size) +void IRAM _lock_close(_lock_t *lock) { - return __wrap_realloc (ptr, size); + assert(lock != NULL); + assert(lock != __malloc_static_object); + + free((void*)*lock); + *lock = 0; } -unsigned int get_free_heap_size (void) +void IRAM _lock_close_recursive(_lock_t *lock) { - return xPortGetFreeHeapSize(); + assert(lock != NULL); + assert(lock != __malloc_static_object); + + free((void*)*lock); + *lock = 0; } -void IRAM syscalls_init (void) +void IRAM _lock_acquire(_lock_t *lock) { -} + assert(lock != NULL); -#else /* MODULE_ESP_SDK */ -/* - * To use the same heap as SDK internally does, SDK memory management - * functions have to be replaced by newlib memory functions. In that case, - * the _malloc_lock/_unlock functions have to be defined. Memory management - * functions of ETS are not used and have not to be considered here. - */ + /* if the lock data structure is still not allocated, initialize it first */ + if (*lock == 0) { + _lock_init(lock); + } -void* IRAM pvPortMalloc (size_t size, const char *file, unsigned line) -{ - (void)file; - (void)line; + /* if scheduler is not running, we have not to lock the mutex */ + if (sched_active_thread == NULL) { + return; + } - return malloc (size); + assert(!irq_is_in()); + mutex_lock((mutex_t*)*lock); } -void IRAM vPortFree (void *ptr, const char *file, unsigned line) +void IRAM _lock_acquire_recursive(_lock_t *lock) { - (void)file; - (void)line; + assert(lock != NULL); - free (ptr); + /* if the lock data structure is still not allocated, initialize it first */ + if (*lock == 0) { + _lock_init_recursive(lock); + } + + /* if scheduler is not running, we have not to lock the rmutex */ + if (sched_active_thread == NULL) { + return; + } + + assert(!irq_is_in()); + rmutex_lock((rmutex_t*)*lock); } -void* IRAM pvPortCalloc (size_t nmemb, size_t size, const char *file, unsigned line) +int IRAM _lock_try_acquire(_lock_t *lock) { - (void)file; - (void)line; + assert(lock != NULL); - void *ptr = malloc (nmemb*size); - if (ptr) { - memset (ptr, 0x0, nmemb*size); + /* if the lock data structure is still not allocated, initialize it first */ + if (*lock == 0) { + _lock_init(lock); } - return ptr; -} -void* IRAM pvPortZalloc (size_t size, const char *file, unsigned line) -{ - (void)file; - (void)line; + /* if scheduler is not running, we have not to lock the mutex */ + if (sched_active_thread == NULL) { + return 0; + } - void *ptr = malloc (size); - if (ptr) { - memset (ptr, 0x0, size); + if (irq_is_in()) { + return 0; } - return ptr; + + return mutex_trylock((mutex_t*)*lock); } -void* IRAM pvPortRealloc (void *ptr, size_t size, const char *file, unsigned line) +int IRAM _lock_try_acquire_recursive(_lock_t *lock) { - (void)file; - (void)line; + assert(lock != NULL); + + /* if the lock data structure is still not allocated, initialize it first */ + if (*lock == 0) { + _lock_init_recursive(lock); + } + + /* if scheduler is not running, we have not to lock the rmutex */ + if (sched_active_thread == NULL) { + return 0; + } - return realloc (ptr, size); + if (irq_is_in()) { + return 0; + } + + return rmutex_trylock((rmutex_t*)*lock); } -size_t IRAM xPortWantedSizeAlign(size_t size) +void IRAM _lock_release(_lock_t *lock) { - /* allign the size to a multiple of 8 */ - return (size & 0x7) ? (size & ~0x7) + 8 : size; + assert(lock != NULL && *lock != 0); + + /* if scheduler is not running, we have not to unlock the mutex */ + if (sched_active_thread == NULL) { + return; + } + + mutex_unlock((mutex_t*)*lock); } -size_t IRAM xPortGetFreeHeapSize (void) +void IRAM _lock_release_recursive(_lock_t *lock) { - return get_free_heap_size (); + assert(lock != NULL && *lock != 0); + + /* if scheduler is not running, we have not to unlock the rmutex */ + if (sched_active_thread == NULL) { + return; + } + + rmutex_unlock((rmutex_t*)*lock); } -/* - * Following functions implement the lock mechanism in newlib. The only static - * mutex defined here is the __malloc_recursive_mutex to avoid that memory - * management functions try to lock before RIOT's threads are running. - * These lock/unlock functions cannot be used in the SDK version since some ISR - * in SDK use malloc/free which does not work in interrupt context. +#endif + +/** + * @name Memory allocation functions */ -extern _lock_t __malloc_recursive_mutex; +#ifdef MODULE_ESP_IDF_HEAP -static rmutex_t _malloc_rmtx = RMUTEX_INIT; +#define MALLOC_CAP_DEFAULT MALLOC_CAP_8BIT +#define heap_caps_malloc_default(s) heap_caps_malloc(s, MALLOC_CAP_DEFAULT) +#define heap_caps_realloc_default(p,s) heap_caps_realloc(p, s, MALLOC_CAP_DEFAULT) -void IRAM syscalls_init (void) +void* IRAM_ATTR __wrap__malloc_r(struct _reent *r, size_t size) { - __malloc_recursive_mutex = (_lock_t)&_malloc_rmtx; + return heap_caps_malloc_default( size ); } -void IRAM _lock_init(_lock_t *lock) +void IRAM_ATTR __wrap__free_r(struct _reent *r, void *ptr) { - CHECK_PARAM (sched_active_thread != 0); - CHECK_PARAM (lock != NULL); - CHECK_PARAM (*lock != ((_lock_t)&_malloc_rmtx)); + heap_caps_free( ptr ); +} - mutex_t* mtx = malloc (sizeof(mutex_t)); +void* IRAM_ATTR __wrap__realloc_r(struct _reent *r, void* ptr, size_t size) +{ + return heap_caps_realloc_default( ptr, size ); +} - if (mtx) { - memset (mtx, 0, sizeof(mutex_t)); - *lock = (_lock_t)mtx; +void* IRAM_ATTR __wrap__calloc_r(struct _reent *r, size_t count, size_t size) +{ + void *result = heap_caps_malloc_default(count * size); + if (result) { + bzero(result, count * size); } + return result; } -void IRAM _lock_init_recursive(_lock_t *lock) +unsigned int get_free_heap_size(void) { - CHECK_PARAM (sched_active_thread != 0); - CHECK_PARAM (lock != NULL); - CHECK_PARAM (*lock != ((_lock_t)&_malloc_rmtx)); - - rmutex_t* rmtx = malloc (sizeof(rmutex_t)); + return heap_caps_get_free_size(MALLOC_CAP_DEFAULT); +} - if (rmtx) { - memset (rmtx, 0, sizeof(rmutex_t)); - *lock = (_lock_t)rmtx; +void heap_stats(void) +{ + extern heap_region_t g_heap_region[HEAP_REGIONS_MAX]; + + for (int i = 0; i < HEAP_REGIONS_MAX; i++) { + ets_printf("Heap region %u @%p: %u (used %u, free %u) [bytes]\n", i, + g_heap_region[i].start_addr, + g_heap_region[i].total_size, + g_heap_region[i].total_size - g_heap_region[i].free_bytes, + g_heap_region[i].free_bytes); } } -void IRAM _lock_close(_lock_t *lock) +#else /* MODULE_ESP_IDF_HEAP */ + +/* for compatibility with ESP-IDF heap functions */ + +void* _heap_caps_malloc(size_t size, uint32_t caps, const char *file, size_t line) { - CHECK_PARAM (lock != NULL); - CHECK_PARAM (*lock != ((_lock_t)&_malloc_rmtx)); + (void)caps; + return malloc(size); +} - free ((void*)*lock); - *lock = 0; +void* _heap_caps_calloc(size_t n, size_t size, uint32_t caps, const char *file, size_t line) +{ + (void)caps; + return calloc(n, size); } -void IRAM _lock_close_recursive(_lock_t *lock) +void* _heap_caps_realloc(void *ptr, size_t size, uint32_t caps, const char *file, size_t line) { - CHECK_PARAM (lock != NULL); - CHECK_PARAM (*lock != ((_lock_t)&_malloc_rmtx)); + return realloc(ptr, size); +} - free ((void*)*lock); - *lock = 0; +void *_heap_caps_zalloc(size_t size, uint32_t caps, const char *file, size_t line) +{ + void *ptr = malloc(size); + if (ptr) { + memset(ptr, 0, size); + } + return ptr; } -void IRAM _lock_acquire(_lock_t *lock) +void _heap_caps_free(void *ptr, const char *file, size_t line) { - CHECK_PARAM (sched_active_thread != 0); - CHECK_PARAM (lock != NULL && *lock != 0); + (void)file; + (void)line; + free(ptr); +} - mutex_lock ((mutex_t*)*lock); +void heap_caps_init(void) +{ } -void IRAM _lock_acquire_recursive(_lock_t *lock) +extern uint8_t _eheap; /* end of heap (defined in esp32.common.ld) */ +extern uint8_t _sheap; /* start of heap (defined in esp32.common.ld) */ + +unsigned int IRAM get_free_heap_size(void) { - CHECK_PARAM (sched_active_thread != 0); - CHECK_PARAM (lock != NULL && *lock != 0); + struct mallinfo minfo = mallinfo(); + return &_eheap - &_sheap - minfo.uordblks; +} - rmutex_lock ((rmutex_t*)*lock); +void heap_stats(void) +{ + ets_printf("heap: %u (used %u, free %u) [bytes]\n", + &_eheap - &_sheap, &_eheap - &_sheap - get_free_heap_size(), + get_free_heap_size()); } -int IRAM _lock_try_acquire(_lock_t *lock) +/* alias for compatibility with espressif/wifi_libs */ +uint32_t esp_get_free_heap_size( void ) __attribute__((alias("get_free_heap_size"))); + +#endif /* MODULE_ESP_IDF_HEAP */ + +/** + * @name Other system functions + */ + +int _rename_r(struct _reent *r, const char *from, const char *to) { - CHECK_PARAM_RET (sched_active_thread != 0, 0); - CHECK_PARAM_RET (lock != NULL && *lock != 0, 0); + return 0; +} - return rmutex_trylock ((rmutex_t*)*lock); +void _abort(void) +{ + ets_printf("#! abort called: powering off\n"); + pm_off(); + while (1) { }; } -int IRAM _lock_try_acquire_recursive(_lock_t *lock) +void _exit_r(struct _reent *r, int status) { - CHECK_PARAM_RET (sched_active_thread != 0, 0); - CHECK_PARAM_RET (lock != NULL && *lock != 0, 0); + _exit(status); +} - return mutex_trylock ((mutex_t*)*lock); +struct _reent* __getreent(void) { + return _GLOBAL_REENT; } -void IRAM _lock_release(_lock_t *lock) +#ifdef MCU_ESP32 +static int _no_sys_func(struct _reent *r) { - CHECK_PARAM (sched_active_thread != 0); - CHECK_PARAM (lock != NULL && *lock != 0); - - mutex_unlock ((mutex_t*)*lock); + DEBUG("%s: system function does not exist\n", __func__); + r->_errno = ENOSYS; + return -1; } +#endif -void IRAM _lock_release_recursive(_lock_t *lock) +static struct _reent s_reent; + +#ifdef MCU_ESP32 +static struct syscall_stub_table s_stub_table = +{ + .__getreent = &__getreent, + + ._malloc_r = &_malloc_r, + ._free_r = &_free_r, + ._realloc_r = &_realloc_r, + ._calloc_r = &_calloc_r, + ._sbrk_r = &_sbrk_r, + + ._system_r = (int (*)(struct _reent *, const char*))&_no_sys_func, + ._raise_r = (void (*)(struct _reent *))&_no_sys_func, + ._abort = &_abort, + ._exit_r = &_exit_r, + ._getpid_r = &_getpid_r, + ._kill_r = &_kill_r, + + ._times_r = &_times_r, + ._gettimeofday_r = _gettimeofday_r, + + ._open_r = &_open_r, + ._close_r = &_close_r, + ._lseek_r = (int (*)(struct _reent *r, int, int, int))&_lseek_r, + ._fstat_r = &_fstat_r, + ._stat_r = &_stat_r, + ._write_r = (int (*)(struct _reent *r, int, const void *, int))&_write_r, + ._read_r = (int (*)(struct _reent *r, int, void *, int))&_read_r, + ._unlink_r = &_unlink_r, + ._link_r = (int (*)(struct _reent *r, const char*, const char*))&_no_sys_func, + ._rename_r = (int (*)(struct _reent *r, const char*, const char*))&_no_sys_func, + + ._lock_init = &_lock_init, + ._lock_init_recursive = &_lock_init_recursive, + ._lock_close = &_lock_close, + ._lock_close_recursive = &_lock_close_recursive, + ._lock_acquire = &_lock_acquire, + ._lock_acquire_recursive = &_lock_acquire_recursive, + ._lock_try_acquire = &_lock_try_acquire, + ._lock_try_acquire_recursive = &_lock_try_acquire_recursive, + ._lock_release = &_lock_release, + ._lock_release_recursive = &_lock_release_recursive, + + #if CONFIG_NEWLIB_NANO_FORMAT + ._printf_float = &_printf_float, + ._scanf_float = &_scanf_float, + #else /* CONFIG_NEWLIB_NANO_FORMAT */ + ._printf_float = NULL, + ._scanf_float = NULL, + #endif /* CONFIG_NEWLIB_NANO_FORMAT */ +}; +#endif + +void syscalls_init(void) { - CHECK_PARAM (sched_active_thread != 0); - CHECK_PARAM (lock != NULL && *lock != 0); +#ifdef MCU_ESP32 + /* enable the system timer in us (TMG0 is enabled by default) */ + TIMER_SYSTEM.config.divider = rtc_clk_apb_freq_get()/MHZ; + TIMER_SYSTEM.config.autoreload = 0; + TIMER_SYSTEM.config.enable = 1; + syscall_table_ptr_pro = &s_stub_table; + syscall_table_ptr_app = &s_stub_table; +#endif + _GLOBAL_REENT = &s_reent; + + environ = malloc(sizeof(char*)); + environ[0] = NULL; + + /* + * initialization of newlib, includes the ctors initialization + */ + extern void __libc_init_array(void); + __libc_init_array(); +} + +uint32_t system_get_time(void) +{ + return phy_get_mactime(); +} - rmutex_unlock ((rmutex_t*)*lock); +uint32_t system_get_time_ms(void) +{ + return phy_get_mactime() / US_PER_MS; } -#define _cheap heap_top +#ifdef MCU_ESP32 +uint64_t system_get_time_64(void) +{ + uint64_t ret; + /* latch 64 bit timer value before read */ + TIMER_SYSTEM.update = 0; + /* wait until instructions have been finished */ + __asm__ volatile ("isync"); + /* read the current timer value */ + ret = TIMER_SYSTEM.cnt_low; + ret += ((uint64_t)TIMER_SYSTEM.cnt_high) << 32; + return ret; +} -extern char *heap_top; -extern char _eheap; /* end of heap (defined in esp8266.riot-os.app.ld) */ -extern char _sheap; /* start of heap (defined in esp8266.riot-os.app.ld) */ +/* alias for compatibility with espressif/wifi_libs */ +int64_t esp_timer_get_time(void) __attribute__((alias("system_get_time_64"))); -unsigned int IRAM get_free_heap_size (void) +static IRAM void system_wdt_int_handler(void *arg) { - struct mallinfo minfo = mallinfo(); - return &_eheap - &_sheap - minfo.uordblks; + TIMERG0.int_clr_timers.wdt=1; /* clear interrupt */ + system_wdt_feed(); } -#endif /* MODULE_ESP_SDK */ - -void heap_stats(void) +void IRAM system_wdt_feed(void) { - ets_printf("heap: %u (used %d, free %u) [bytes]\n", - &_eheap - &_sheap, &_eheap - &_sheap - get_free_heap_size(), - get_free_heap_size()); + DEBUG("%s\n", __func__); + TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; /* disable write protection */ + TIMERG0.wdt_feed=1; /* reset MWDT */ + TIMERG0.wdt_wprotect=0; /* enable write protection */ } -int _rename_r (struct _reent *r, const char* old, const char* new) +void system_wdt_init(void) { - DEBUG("%s: system function does not exist\n", __func__); - r->_errno = ENOSYS; - return -1; + /* disable boot watchdogs */ + TIMERG0.wdt_config0.flashboot_mod_en = 0; + RTCCNTL.wdt_config0.flashboot_mod_en = 0; + + /* enable system watchdog */ + TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; /* disable write protection */ + TIMERG0.wdt_config0.stg0 = TIMG_WDT_STG_SEL_INT; /* stage0 timeout: interrupt */ + TIMERG0.wdt_config0.stg1 = TIMG_WDT_STG_SEL_RESET_SYSTEM; /* stage1 timeout: sys reset */ + TIMERG0.wdt_config0.sys_reset_length = 7; /* sys reset signal length: 3.2 us */ + TIMERG0.wdt_config0.cpu_reset_length = 7; /* sys reset signal length: 3.2 us */ + TIMERG0.wdt_config0.edge_int_en = 0; + TIMERG0.wdt_config0.level_int_en = 1; + + /* MWDT clock = 80 * 12,5 ns = 1 us */ + TIMERG0.wdt_config1.clk_prescale = 80; + + /* define stage timeouts */ + TIMERG0.wdt_config2 = 2 * US_PER_SEC; /* stage 0: 2 s (interrupt) */ + TIMERG0.wdt_config3 = 4 * US_PER_SEC; /* stage 1: 4 s (sys reset) */ + + TIMERG0.wdt_config0.en = 1; /* enable MWDT */ + TIMERG0.wdt_feed = 1; /* reset MWDT */ + TIMERG0.wdt_wprotect = 0; /* enable write protection */ + + DEBUG("%s TIMERG0 wdt_config0=%08x wdt_config1=%08x wdt_config2=%08x\n", + __func__, TIMERG0.wdt_config0.val, TIMERG0.wdt_config1.val, + TIMERG0.wdt_config2); + + /* route WDT peripheral interrupt source to CPU_INUM_WDT */ + intr_matrix_set(PRO_CPU_NUM, ETS_TG0_WDT_LEVEL_INTR_SOURCE, CPU_INUM_WDT); + /* set the interrupt handler and activate the interrupt */ + xt_set_interrupt_handler(CPU_INUM_WDT, system_wdt_int_handler, NULL); + xt_ints_on(BIT(CPU_INUM_WDT)); +} + +void system_wdt_stop(void) +{ + xt_ints_off(BIT(CPU_INUM_WDT)); + TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; /* disable write protection */ + TIMERG0.wdt_config0.en = 0; /* disable MWDT */ + TIMERG0.wdt_feed = 1; /* reset MWDT */ + TIMERG0.wdt_wprotect = 0; /* enable write protection */ } -#include +void system_wdt_start(void) +{ + TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; /* disable write protection */ + TIMERG0.wdt_config0.en = 1; /* disable MWDT */ + TIMERG0.wdt_feed = 1; /* reset MWDT */ + TIMERG0.wdt_wprotect = 0; /* enable write protection */ + xt_ints_on(BIT(CPU_INUM_WDT)); +} +#endif -double __ieee754_remainder(double x, double y) { - return x - y * floor(x/y); +__attribute__((weak)) void +_system_prevent_memset_lto(void *const s, int c, const size_t n) +{ + (void)s; + (void)c; + (void)n; } -float __ieee754_remainderf(float x, float y) { - return x - y * floor(x/y); +void *system_secure_memset(void *s, int c, size_t n) +{ + memset(s, c, n); + _system_prevent_memset_lto(s, c, n); + return s; } diff --git a/cpu/esp8266/thread_arch.c b/cpu/esp8266/thread_arch.c index eca968959ac0..7ed987d99dc9 100644 --- a/cpu/esp8266/thread_arch.c +++ b/cpu/esp8266/thread_arch.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -45,7 +45,7 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#define ENABLE_DEBUG 0 +#define ENABLE_DEBUG (0) #include "debug.h" #include @@ -58,15 +58,23 @@ #include "thread.h" #include "sched.h" -#include "common.h" -#include "esp/common_macros.h" -#include "esp/xtensa_ops.h" -#include "sdk/ets_task.h" -#include "sdk/rom.h" -#include "sdk/sdk.h" +#include "esp_common.h" +#include "irq_arch.h" +#include "syscalls.h" #include "tools.h" + +#include "esp_attr.h" +#include "esp/xtensa_ops.h" +#include "rom/ets_sys.h" #include "xtensa/xtensa_context.h" +#ifdef MCU_ESP32 +#include "soc/dport_reg.h" +#else /* MCU_ESP32 */ +#include "esp8266/rom_functions.h" +#include "sdk/sdk.h" +#endif /* MCU_ESP32 */ + /* User exception dispatcher when exiting */ extern void _xt_user_exit(void); @@ -80,21 +88,29 @@ extern void _frxt_setup_switch(void); extern void vPortYield(void); extern void vPortYieldFromInt(void); +#ifdef __XTENSA_CALL0_ABI__ +#define task_exit sched_task_exit +#else /* __XTENSA_CALL0_ABI__ */ +/* forward declarations */ +NORETURN void task_exit(void); +#endif /* __XTENSA_CALL0_ABI__ */ + char* thread_stack_init(thread_task_func_t task_func, void *arg, void *stack_start, int stack_size) { - /* - * Stack layout after task stack initialization + /* Stack layout after task stack initialization * * +------------------------+ * | | TOP * | thread_control_block | - * stack_start + stack_size ==> | | + * stack_start + stack_size ==> | | top_of_stack+1 * +------------------------+ * top_of_stack ==> | | - * | XT_CP_FRAME | + * | XT_CP_SA | * | (optional) | - * top_of_stack + 1 - XT_CP_SIZE ==> | | - * +------------------------+ + * | ... | ... + * | cpstored | XT_CPSTORED + * top_of_stack + 1 - XT_CP_SIZE ==> | cpenable | XT_CPENABLE + * (cp_state) +------------------------+ * | | * | XT_STK_FRAME | * | | XT_STK_... @@ -126,39 +142,43 @@ char* thread_stack_init(thread_task_func_t task_func, void *arg, void *stack_sta uint8_t *top_of_stack; uint8_t *sp; - top_of_stack = (uint8_t*)((uint32_t)stack_start + stack_size-1); + top_of_stack = (uint8_t*)((uint32_t)stack_start + stack_size - 1); + + /* BEGIN - code from FreeRTOS port for Xtensa from Cadence */ + + /* Create interrupt stack frame aligned to 16 byte boundary */ + sp = (uint8_t*)(((uint32_t)(top_of_stack + 1) - XT_STK_FRMSZ - XT_CP_SIZE) & ~0xf); /* Clear whole stack with a known value to assist debugging */ #if !defined(DEVELHELP) && !defined(SCHED_TEST_STACK) - /* Unfortunatly, this affects thread_measure_stack_free function */ + /* Unfortunately, this affects thread_measure_stack_free function */ memset(stack_start, 0, stack_size); + #else + memset(sp, 0, XT_STK_FRMSZ + XT_CP_SIZE); #endif - /* BEGIN - code from FreeRTOS port for Xtensa from Cadence */ - - /* Create interrupt stack frame aligned to 16 byte boundary */ - sp = (uint8_t*)(((uint32_t)(top_of_stack+1) - XT_STK_FRMSZ - XT_CP_SIZE) & ~0xf); - /* ensure that stack is big enough */ assert (sp > (uint8_t*)stack_start); XtExcFrame* exc_frame = (XtExcFrame*)sp; - /* Explicitly initialize certain saved registers */ + /* Explicitly initialize certain saved registers for call0 ABI */ exc_frame->pc = (uint32_t)task_func; /* task entry point */ - exc_frame->a0 = (uint32_t)sched_task_exit; /* task exit point (CHANGED) */ + exc_frame->a0 = (uint32_t)task_exit; /* task exit point*/ exc_frame->a1 = (uint32_t)sp + XT_STK_FRMSZ; /* physical top of stack frame */ - exc_frame->a2 = (uint32_t)arg; /* parameters for task_func */ exc_frame->exit = (uint32_t)_xt_user_exit; /* user exception exit dispatcher */ /* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */ /* Also set entry point argument parameter. */ #ifdef __XTENSA_CALL0_ABI__ - /* CALL0 ABI */ + /* for CALL0 ABI set in parameter a2 to task argument */ exc_frame->ps = PS_UM | PS_EXCM; + exc_frame->a2 = (uint32_t)arg; /* parameters for task_func */ #else - /* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */ + /* for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */ exc_frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1); + exc_frame->a4 = (uint32_t)task_exit; /* task exit point*/ + exc_frame->a6 = (uint32_t)arg; /* parameters for task_func */ #endif #ifdef XT_USE_SWPRI @@ -174,7 +194,7 @@ char* thread_stack_init(thread_task_func_t task_func, void *arg, void *stack_sta */ uint32_t *p; - p = (uint32_t *)(((uint32_t) pxTopOfStack - XT_CP_SIZE)); + p = (uint32_t *)(((uint32_t)(top_of_stack + 1) - XT_CP_SIZE)); p[0] = 0; p[1] = 0; p[2] = (((uint32_t) p) + 12 + XCHAL_TOTAL_SA_ALIGN - 1) & -XCHAL_TOTAL_SA_ALIGN; @@ -188,54 +208,97 @@ char* thread_stack_init(thread_task_func_t task_func, void *arg, void *stack_sta return (char*)sp; } +#ifdef MCU_ESP8266 +extern int MacIsrSigPostDefHdl(void); +unsigned int ets_soft_int_type = ETS_SOFT_INT_NONE; +#endif -unsigned sched_interrupt_nesting = 0; /* Interrupt nesting level */ - -#ifdef CONTEXT_SWITCH_BY_INT /** - * Context switches are realized using software interrupts + * Context switches are realized using software interrupts since interrupt + * entry and exit functions are the only way to save and restore complete + * context including spilling the register windows to the stack */ -void IRAM thread_yield_isr(void* arg) +void IRAM_ATTR thread_yield_isr(void* arg) { +#ifdef MCU_ESP8266 + ETS_NMI_LOCK(); + + if (ets_soft_int_type == ETS_SOFT_INT_HDL_MAC) { + ets_soft_int_type = MacIsrSigPostDefHdl() ? ETS_SOFT_INT_YIELD + : ETS_SOFT_INT_NONE; + } + + if (ets_soft_int_type == ETS_SOFT_INT_YIELD) { + /* + * set the context switch flag (indicates that context has to be + * switched on exit from interrupt in _frxt_int_exit + */ + ets_soft_int_type = ETS_SOFT_INT_NONE; + _frxt_setup_switch(); + } + + ETS_NMI_UNLOCK(); +#else + /* clear the interrupt first */ + DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, 0); /* set the context switch flag (indicates that context has to be switched is switch on exit from interrupt in _frxt_int_exit */ + _frxt_setup_switch(); -} #endif +} -void thread_yield_higher(void) +/** + * If we are already in an interrupt handler, the function simply sets the + * context switch flag, which indicates that the context has to be switched + * in the _frxt_int_exit function when exiting the interrupt. Otherwise, we + * will generate a software interrupt to force the context switch when + * terminating the software interrupt (see thread_yield_isr). + */ +void IRAM_ATTR thread_yield_higher(void) { /* reset hardware watchdog */ - system_soft_wdt_feed(); + system_wdt_feed(); /* yield next task */ #if defined(ENABLE_DEBUG) && defined(DEVELHELP) if (sched_active_thread) { - DEBUG("%u old task %u %s %u\n", phy_get_mactime(), + DEBUG("%u old task %u %s %u\n", system_get_time(), sched_active_thread->pid, sched_active_thread->name, sched_active_thread->sp - sched_active_thread-> stack_start); } #endif - if (!irq_is_in()) { - #ifdef CONTEXT_SWITCH_BY_INT +#ifdef MCU_ESP32 + /* generate the software interrupt to switch the context */ + DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, DPORT_CPU_INTR_FROM_CPU_0); +#else /* MCU_ESP32 */ + critical_enter(); + ets_soft_int_type = ETS_SOFT_INT_YIELD; WSR(BIT(ETS_SOFT_INUM), interrupt); - #else - vPortYield(); - #endif + critical_exit(); +#endif /* MCU_ESP32 */ } else { + /* set the context switch flag */ _frxt_setup_switch(); } #if defined(ENABLE_DEBUG) && defined(DEVELHELP) if (sched_active_thread) { - DEBUG("%u new task %u %s %u\n", phy_get_mactime(), + DEBUG("%u new task %u %s %u\n", system_get_time(), sched_active_thread->pid, sched_active_thread->name, sched_active_thread->sp - sched_active_thread-> stack_start); } #endif + /* + * Instruction fetch synchronize: Waits for all previously fetched load, + * store, cache, and special register write instructions that affect + * instruction fetch to be performed before fetching the next instruction. + */ + __asm__("isync"); + return; } @@ -265,7 +328,7 @@ void thread_print_stack(void) return; } -#if defined(DEVELHELP) +#ifdef DEVELHELP extern uint8_t port_IntStack; extern uint8_t port_IntStackTop; @@ -273,9 +336,14 @@ extern uint8_t port_IntStackTop; void thread_isr_stack_init(void) { /* code from thread.c, please see the copyright notice there */ +#ifdef MCU_ESP32 + #define sp (&port_IntStackTop) +#else /* MCU_ESP32 */ + register uint32_t *sp __asm__ ("a1"); +#endif /* MCU_ESP32 */ /* assign each int of the stack the value of it's address */ - uintptr_t *stackmax = (uintptr_t *)&port_IntStackTop; + uintptr_t *stackmax = (uintptr_t *)sp; uintptr_t *stackp = (uintptr_t *)&port_IntStack; while (stackp < stackmax) { @@ -314,10 +382,71 @@ void thread_isr_stack_init(void) {} #endif /* DEVELHELP */ +#ifndef __XTENSA_CALL0_ABI__ +static bool _initial_exit = true; +#endif /* __XTENSA_CALL0_ABI__ */ + NORETURN void cpu_switch_context_exit(void) { + DEBUG("%s\n", __func__); + /* Switch context to the highest priority ready task without context save */ +#ifdef __XTENSA_CALL0_ABI__ _frxt_dispatch(); +#else /* __XTENSA_CALL0_ABI__ */ + if (_initial_exit) { + _initial_exit = false; + __asm__ volatile ("call0 _frxt_dispatch"); + } + else { + task_exit(); + } +#endif /* __XTENSA_CALL0_ABI__ */ + UNREACHABLE(); +} + +#ifndef __XTENSA_CALL0_ABI__ +/** + * The function is used on task exit to switch to the context to the next + * running task. It realizes only the second half of a complete context by + * simulating the exit from an interrupt handling where a context switch is + * forced. The old context is not saved here since it is no longer needed. + */ +NORETURN void task_exit(void) +{ + DEBUG("sched_task_exit: ending thread %" PRIkernel_pid "...\n", + sched_active_thread ? sched_active_thread->pid : KERNEL_PID_UNDEF); + + (void) irq_disable(); + + /* remove old task from scheduling if it is not already done */ + if (sched_active_thread) { + sched_threads[sched_active_pid] = NULL; + sched_num_threads--; + sched_set_status((thread_t *)sched_active_thread, STATUS_STOPPED); + sched_active_thread = NULL; + } + + /* determine the new running task */ + sched_run(); + + /* set the context switch flag (indicates that context has to be switched + is switch on exit from interrupt in _frxt_int_exit */ + _frxt_setup_switch(); + + /* set interrupt nesting level to the right value */ + irq_interrupt_nesting++; + + /* reset windowed registers */ + __asm__ volatile ("movi a2, 0\n" + "wsr a2, windowstart\n" + "wsr a2, windowbase\n" + "rsync\n"); + + /* exit from simulated interrupt to switch to the new context */ + __asm__ volatile ("call0 _frxt_int_exit"); + /* should not be executed */ UNREACHABLE(); } +#endif /* __XTENSA_CALL0_ABI__ */ diff --git a/cpu/esp8266/tools.c b/cpu/esp8266/tools.c index 1aadb7e66c9f..b840aea01f75 100644 --- a/cpu/esp8266/tools.c +++ b/cpu/esp8266/tools.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Gunar Schorcht + * Copyright (C) 2019 Gunar Schorcht * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -19,11 +19,16 @@ */ #include -#include #include +#ifdef MCU_ESP8266 +#include +#include "sdk/sdk.h" +#else +#include "rom/ets_sys.h" +#endif + #include "esp/common_macros.h" -#include "sdk/ets.h" #include "tools.h" extern void malloc_stats (void); @@ -58,19 +63,18 @@ void esp_hexdump (const void* addr, uint32_t num, char width, uint8_t per_line) while (count < num) { if (count % per_line == 0) { - printf ("%08x: ", (uint32_t)((uint8_t*)addr+count*size)); + ets_printf ("%08" PRIx32 ": ", (uint32_t)((uint8_t*)addr+count*size)); } switch (width) { - case 'b': printf("%02" PRIx8 " ", addr8[count++]); break; - case 'h': printf("%04" PRIx16 " ", addr16[count++]); break; - case 'w': printf("%08" PRIx32 " ", addr32[count++]); break; - case 'g': printf("%016" PRIx64 " ", addr64[count++]); break; - - default : printf("."); count++; break; + case 'b': ets_printf("%02" PRIx8 " ", addr8[count++]); break; + case 'h': ets_printf("%04" PRIx16 " ", addr16[count++]); break; + case 'w': ets_printf("%08" PRIx32 " ", addr32[count++]); break; + case 'g': ets_printf("%016" PRIx64 " ", addr64[count++]); break; + default : ets_printf("."); count++; break; } if (count % per_line == 0) { - printf ("\n"); + ets_printf ("\n"); } } - printf ("\n"); + ets_printf ("\n"); } diff --git a/cpu/esp8266/vendor/Makefile b/cpu/esp8266/vendor/Makefile index 8494f6c158ba..cac5d5e11f31 100644 --- a/cpu/esp8266/vendor/Makefile +++ b/cpu/esp8266/vendor/Makefile @@ -1,7 +1,7 @@ # Add a list of subdirectories, that should also be built: -DIRS += esp +DIRS += esp-idf -ifeq ($(ENABLE_GDBSTUB), 1) +ifneq (, $(filter esp_gdbstub, $(USEMODULE))) DIRS += esp-gdbstub endif diff --git a/cpu/esp8266/vendor/README.md b/cpu/esp8266/vendor/README.md index 72553a7d0ebf..e37afe435756 100644 --- a/cpu/esp8266/vendor/README.md +++ b/cpu/esp8266/vendor/README.md @@ -8,6 +8,6 @@ The files that are part of [esp-open-rtos](https://github.com/SuperHouse/esp-ope The files in this directory are a modified version of [esp-gdbstub](https://github.com/espressif/esp-gdbstub). The files are copyright of Espressif Systems (Shanghai) Pte., Ltd. and are licensed under the Espressif MIT license. -### espressif +### esp-idf -The files in this directory are either from the [ESP8266_NONOS_SDK](https://github.com/espressif/ESP8266_NONOS_SDK.git) or from the [ESP_RTOS_SDK](https://github.com/espressif/ESP8266_RTOS_SDK.git) for ESP8266. All of these files are copyright of Espressif Systems (Shanghai) Pte., Ltd. Please note the copyright notice in these files. +The files in this directory and all subdirectories are from the [ESP8266 RTOS SDK](https://github.com/espressif/ESP8266_RTOS_SDK), the official development framework for ESP8266. All of these files are under copyright of Espressif Systems (Shanghai) PTE LTD or their respective owners and licensed under the Apache License, Version 2.0. Please refer the copyright notice in these files for details. diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbcmds b/cpu/esp8266/vendor/esp-gdbstub/gdbcmds index 61dfdbeda79e..92cce5151557 100644 --- a/cpu/esp8266/vendor/esp-gdbstub/gdbcmds +++ b/cpu/esp8266/vendor/esp-gdbstub/gdbcmds @@ -1,4 +1,3 @@ -file ../ld/esp8266.riot-os.sdk.app.ld #set remotedebug 1 set remotelogfile gdb_rsp_logfile.txt set serial baud 115200 diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-cfg.h b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-cfg.h index 849d733220d5..1a02b0cc8af3 100644 --- a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-cfg.h +++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-cfg.h @@ -5,60 +5,75 @@ extern "C" { #endif -/* -Enable this define if you're using the RTOS SDK. It will use a custom exception handler instead of the HAL -and do some other magic to make everything work and compile under FreeRTOS. -*/ -#ifndef GDBSTUB_FREERTOS -#define GDBSTUB_FREERTOS 1 +/** + * @brief Enable own stack for gdbstub + * + * Enable this to make the exception and debugging handlers switch to a + * private stack. This will use GDBSTUB_STACK_SIZE of RAM, but may be useful + * if you're debugging stack or stack pointer corruption problems. It's + * normally disabled because not many situations need it. If for some reason + * the GDB communication stops when you run into an error in your code, try + * enabling this. + */ +#ifndef GDBSTUB_USE_OWN_STACK +#define GDBSTUB_USE_OWN_STACK (0) #endif -/* -Enable this to make the exception and debugging handlers switch to a private stack. This will use -up 1K of RAM, but may be useful if you're debugging stack or stack pointer corruption problems. It's -normally disabled because not many situations need it. If for some reason the GDB communication -stops when you run into an error in your code, try enabling this. -*/ -#ifndef GDBSTUB_USE_OWN_STACK -#define GDBSTUB_USE_OWN_STACK 0 +/** + * @brief Size of gdbstub stack + * + * If own stack is enale for gdbstub (\ref GDBSTUB_USE_OWN_STACK), + * GDBSTUB_STACK_SIZE defines the size of this stack. + */ +#ifndef GDBSTUB_STACK_SIZE +#define GDBSTUB_STACK_SIZE (1024) #endif -/* -If this is defined, gdbstub will break the program when you press Ctrl-C in gdb. it does this by -hooking the UART interrupt. Unfortunately, this means receiving stuff over the serial port won't -work for your program anymore. This will fail if your program sets an UART interrupt handler after -the gdbstub_init call. -*/ +/** + * @brief Enable Ctrl-C handling + * + * If Ctrl-C is enabled, gdbstub interrupts the program when you press the + * Ctrl-C key either in gdb or, if used, in the console window. Ctrl-C handling + * is realized by hooking the UART interrupt. + */ #ifndef GDBSTUB_CTRLC_BREAK -#define GDBSTUB_CTRLC_BREAK 1 +#define GDBSTUB_CTRLC_BREAK (1) #endif -/* -Enabling this will redirect console output to GDB. This basically means that printf/os_printf output -will show up in your gdb session, which is useful if you use gdb to do stuff. It also means that if -you use a normal terminal, you can't read the printfs anymore. -*/ +/** + * @brief Redirect console output to GDB + * + * Enabling this will redirect console output to GDB. This basically means + * that printf/os_printf output will show up in your gdb session, which is + * useful if you use gdb to do stuff. It also means that if you use a normal + * terminal, you can't read the printfs anymore. + */ #ifndef GDBSTUB_REDIRECT_CONSOLE_OUTPUT -#define GDBSTUB_REDIRECT_CONSOLE_OUTPUT 1 +#define GDBSTUB_REDIRECT_CONSOLE_OUTPUT (1) #endif -/* -Enable this if you want the GDB stub to wait for you to attach GDB before running. It does this by -breaking in the init routine; use the gdb 'c' command (continue) to start the program. -*/ +/** + * @brief Break on init + * + * Enable this if you want the GDB stub to wait for you to attach GDB before + * running. It does this by breaking in the init routine; use the gdb 'c' + * command (continue) to start the program. + */ #ifndef GDBSTUB_BREAK_ON_INIT -#define GDBSTUB_BREAK_ON_INIT 1 +#define GDBSTUB_BREAK_ON_INIT (1) #endif -/* -Function attributes for function types. -Gdbstub functions are placed in flash or IRAM using attributes, as defined here. The gdbinit function -(and related) can always be in flash, because it's called in the normal code flow. The rest of the -gdbstub functions can be in flash too, but only if there's no chance of them being called when the -flash somehow is disabled (eg during SPI operations or flash write/erase operations). If the routines -are called when the flash is disabled (eg due to a Ctrl-C at the wrong time), the ESP8266 will most -likely crash. -*/ +/** + * @brief Function attributes for function types. + * + * gdbstub functions are placed in flash or IRAM using attributes, as defined + * here. The gdbinit function (and related) can always be in flash, because + * it's called in the normal code flow. The rest of the gdbstub functions can + * be in flash too, but only if there's no chance of them being called when the + * flash somehow is disabled (eg during SPI operations or flash write/erase + * operations). If the routines are called when the flash is disabled (e.g. + * due to a Ctrl-C at the wrong time), the ESP8266 will most likely crash. + */ #define ATTR_GDBINIT ICACHE_FLASH_ATTR #ifndef ATTR_GDBFN #define ATTR_GDBFN diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.S b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.S index 8ff28da66e5b..a1f79dcc4d47 100644 --- a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.S +++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.S @@ -8,397 +8,398 @@ #include "gdbstub-cfg.h" +#include "gdbstub-exc.h" #include #include #include -#define DEBUG_PC (EPC + XCHAL_DEBUGLEVEL) -#define DEBUG_EXCSAVE (EXCSAVE + XCHAL_DEBUGLEVEL) -#define DEBUG_PS (EPS + XCHAL_DEBUGLEVEL) +#include "xtensa/xtensa_context.h" +#define DEBUG_PC (EPC + XCHAL_DEBUGLEVEL) +#define DEBUG_EXCSAVE (EXCSAVE + XCHAL_DEBUGLEVEL) +#define DEBUG_PS (EPS + XCHAL_DEBUGLEVEL) -.global gdbstub_savedRegs +.global gdbstub_regs +.global gdbstub_debug_exception_entry #if GDBSTUB_USE_OWN_STACK .global gdbstub_exceptionStack #endif - .text -.literal_position + .text + .literal_position - .text - .align 4 + .text + .align 4 +/** + * @brief Debugging exception routine; it's called by the debugging vector + */ +gdbstub_debug_exception_entry: -/* -The savedRegs struct: - uint32_t pc; - uint32_t ps; - uint32_t sar; - uint32_t vpri; - uint32_t a0; - uint32_t a[14]; //a2..a15 - uint32_t litbase; - uint32_t sr176; - uint32_t sr208; - uint32_t a1; - uint32_t reason; -*/ + /* + * All registers except A2 are intact when we arrive here. The original + * contents of A2 was save in the EXCSAVE2/DEBUG_EXCSAVE register by + * _DebugExceptionVector stub. EPC2/DEBUG_PC register contains the + * original PC and EPC2/DEBUG_PC the original PS register + */ + + /* Save all regs to standard exception frame structure XtExcFrame */ + movi a2, gdbstub_regs + + s32i a0, a2, XT_STK_A0 /* save A0 (return address) before we used it */ + s32i a1, a2, XT_STK_A1 /* save A1 (stack pointer) */ + + rsr a0, DEBUG_PC /* read original PC from EPC2 and save it */ + s32i a0, a2, XT_STK_PC + + rsr a0, DEBUG_PS /* read original PS from ESP2 and save it */ + s32i a0, a2, XT_STK_PS + + rsr a0, DEBUG_EXCSAVE /* read original A2 from EXCSAVE2 and save it */ + s32i a0, a2, XT_STK_A2 + + s32i a3, a2, XT_STK_A3 /* save remaining A registers */ + s32i a4, a2, XT_STK_A4 + s32i a5, a2, XT_STK_A5 + s32i a6, a2, XT_STK_A6 + s32i a7, a2, XT_STK_A7 + s32i a8, a2, XT_STK_A8 + s32i a9, a2, XT_STK_A9 + s32i a10, a2, XT_STK_A10 + s32i a11, a2, XT_STK_A11 + s32i a12, a2, XT_STK_A12 + s32i a13, a2, XT_STK_A13 + s32i a14, a2, XT_STK_A14 + s32i a15, a2, XT_STK_A15 + + rsr a0, SAR /* read SAR and save it */ + s32i a0, a2, XT_STK_SAR + +#if XCHAL_HAVE_LOOPS + rsr a0, lbeg + s32i a0, a2, XT_STK_LBEG + rsr a0, lend + s32i a0, a2, XT_STK_LEND + rsr a0, lcount + s32i a0, a2, XT_STK_LCOUNT +#endif -/* -This is the debugging exception routine; it's called by the debugging vector +#ifdef XT_USE_SWPRI + rsr a0, vpri + s32i a0, a2, XT_STK_VPRI +#endif -We arrive here with all regs intact except for a2. The old contents of A2 are saved -into the DEBUG_EXCSAVE special function register. EPC is the original PC. -*/ -gdbstub_debug_exception_entry: -/* - //Minimum no-op debug exception handler, for debug - rsr a2,DEBUG_PC - addi a2,a2,3 - wsr a2,DEBUG_PC - xsr a2, DEBUG_EXCSAVE - rfi XCHAL_DEBUGLEVEL -*/ - -//Save all regs to structure - movi a2, gdbstub_savedRegs - s32i a0, a2, 0x10 - s32i a1, a2, 0x58 - rsr a0, DEBUG_PS - s32i a0, a2, 0x04 - rsr a0, DEBUG_EXCSAVE //was R2 - s32i a0, a2, 0x14 - s32i a3, a2, 0x18 - s32i a4, a2, 0x1c - s32i a5, a2, 0x20 - s32i a6, a2, 0x24 - s32i a7, a2, 0x28 - s32i a8, a2, 0x2c - s32i a9, a2, 0x30 - s32i a10, a2, 0x34 - s32i a11, a2, 0x38 - s32i a12, a2, 0x3c - s32i a13, a2, 0x40 - s32i a14, a2, 0x44 - s32i a15, a2, 0x48 - rsr a0, SAR - s32i a0, a2, 0x08 - rsr a0, LITBASE - s32i a0, a2, 0x4C - rsr a0, 176 - s32i a0, a2, 0x50 - rsr a0, 208 - s32i a0, a2, 0x54 - rsr a0, DEBUGCAUSE - s32i a0, a2, 0x5C - rsr a4, DEBUG_PC - s32i a4, a2, 0x00 +#ifdef XT_USE_OVLY + rsr a0, ovly + s32i a0, a2, XT_STK_OVLY +#endif + + /* Save additional registers required for gdb_stub */ + movi a2, gdbstub_regs + XtExcFrameSize + rsr a0, LITBASE + s32i a0, a2, XT_STK_LITBASE + rsr a0, 176 + s32i a0, a2, XT_STK_SR176 + rsr a0, 208 + s32i a0, a2, XT_STK_SR208 + rsr a0, DEBUGCAUSE + s32i a0, a2, XT_STK_REASON #if GDBSTUB_USE_OWN_STACK - //Move to our own stack - movi a1, exceptionStack+255*4 + /* Move to our own stack */ + movi a1, gdbstub_exceptionStack + GDBSTUB_STACK_SIZE - 4 #endif -//If ICOUNT is -1, disable it by setting it to 0, otherwise we will keep triggering on the same instruction. - rsr a2, ICOUNT - movi a3, -1 - bne a2, a3, noIcountReset - movi a3, 0 - wsr a3, ICOUNT -noIcountReset: + /* + * If ICOUNT is -1, disable it by setting it to 0, otherwise we will + * keep triggering on the same instruction. + */ + rsr a2, ICOUNT + movi a3, -1 + bne a2, a3, noIcountReset + movi a3, 0 + wsr a3, ICOUNT - rsr a2, ps - addi a2, a2, -PS_EXCM_MASK - wsr a2, ps - rsync +noIcountReset: + rsr a2, ps + addi a2, a2, -PS_EXCM_MASK + wsr a2, ps + rsync -//Call into the C code to do the actual handling. - call0 gdbstub_handle_debug_exception + /* Call into the C code to do the actual handling. */ + call0 gdbstub_handle_debug_exception DebugExceptionExit: - rsr a2, ps - addi a2, a2, PS_EXCM_MASK - wsr a2, ps - rsync - - //Restore registers from the gdbstub_savedRegs struct - movi a2, gdbstub_savedRegs - l32i a0, a2, 0x00 - wsr a0, DEBUG_PC -// l32i a0, a2, 0x54 -// wsr a0, 208 - l32i a0, a2, 0x50 - //wsr a0, 176 //Some versions of gcc do not understand this... - .byte 0x00, 176, 0x13 //so we hand-assemble the instruction. - l32i a0, a2, 0x4C - wsr a0, LITBASE - l32i a0, a2, 0x08 - wsr a0, SAR - l32i a15, a2, 0x48 - l32i a14, a2, 0x44 - l32i a13, a2, 0x40 - l32i a12, a2, 0x3c - l32i a11, a2, 0x38 - l32i a10, a2, 0x34 - l32i a9, a2, 0x30 - l32i a8, a2, 0x2c - l32i a7, a2, 0x28 - l32i a6, a2, 0x24 - l32i a5, a2, 0x20 - l32i a4, a2, 0x1c - l32i a3, a2, 0x18 - l32i a0, a2, 0x14 - wsr a0, DEBUG_EXCSAVE //was R2 - l32i a0, a2, 0x04 - wsr a0, DEBUG_PS - l32i a1, a2, 0x58 - l32i a0, a2, 0x10 - - //Read back vector-saved a2 value, put back address of this routine. - movi a2, gdbstub_debug_exception_entry - xsr a2, DEBUG_EXCSAVE - - //All done. Return to where we came from. - rfi XCHAL_DEBUGLEVEL - - - -#if GDBSTUB_FREERTOS -/* -FreeRTOS exception handling code. For some reason or another, we can't just hook the main exception vector: it -seems FreeRTOS uses that for something else too (interrupts). FreeRTOS has its own fatal exception handler, and we -hook that. Unfortunately, that one is called from a few different places (eg directly in the DoubleExceptionVector) -so the precise location of the original register values are somewhat of a mystery when we arrive here... - -As a 'solution', we'll just decode the most common case of the user_fatal_exception_handler being called from -the user exception handler vector: -- excsave1 - orig a0 -- a1: stack frame: - sf+16: orig a1 - sf+8: ps - sf+4: epc - sf+12: orig a0 - sf: magic no? -*/ - .global gdbstub_handle_user_exception - .global gdbstub_user_exception_entry - .align 4 -gdbstub_user_exception_entry: -//Save all regs to structure - movi a0, gdbstub_savedRegs - s32i a1, a0, 0x14 //was a2 - s32i a3, a0, 0x18 - s32i a4, a0, 0x1c - s32i a5, a0, 0x20 - s32i a6, a0, 0x24 - s32i a7, a0, 0x28 - s32i a8, a0, 0x2c - s32i a9, a0, 0x30 - s32i a10, a0, 0x34 - s32i a11, a0, 0x38 - s32i a12, a0, 0x3c - s32i a13, a0, 0x40 - s32i a14, a0, 0x44 - s32i a15, a0, 0x48 - rsr a2, SAR - s32i a2, a0, 0x08 - rsr a2, LITBASE - s32i a2, a0, 0x4C - rsr a2, 176 - s32i a2, a0, 0x50 - rsr a2, 208 - s32i a2, a0, 0x54 - rsr a2, EXCCAUSE - s32i a2, a0, 0x5C - -//Get the rest of the regs from the stack struct - l32i a3, a1, 12 - s32i a3, a0, 0x10 - l32i a3, a1, 16 - s32i a3, a0, 0x58 - l32i a3, a1, 8 - s32i a3, a0, 0x04 - l32i a3, a1, 4 - s32i a3, a0, 0x00 - -#if GDBSTUB_USE_OWN_STACK - movi a1, exceptionStack+255*4 + rsr a2, ps + addi a2, a2, PS_EXCM_MASK + wsr a2, ps + rsync + + /* Restore registers from the gdbstub_regs struct. */ + + movi a2, gdbstub_regs + XtExcFrameSize + +#if 0 + /* TODO: check whether it is really necessary to recover SR178 and SR208 + * Some versions of gcc do not understand instruction 'wsr ' where n is + * the decimal number of the special register. A hand-assembled version of + * instruction would have to be used instead. + * + * .byte 0x00, , 0x13 + * + * However, writing to SR176 or SR208 leads to an IllegalInstruction + * exception + */ + + l32i a0, a2, XT_STK_SR208 + wsr a0, 208 + l32i a0, a2, XT_STK_SR176 + wsr a0, 176 #endif - rsr a2, ps - addi a2, a2, -PS_EXCM_MASK - wsr a2, ps - rsync + l32i a0, a2, XT_STK_LITBASE + wsr a0, LITBASE - call0 gdbstub_handle_user_exception - -UserExceptionExit: - -/* -Okay, from here on, it Does Not Work. There's not really any continuing from an exception in the -FreeRTOS case; there isn't any effort put in reversing the mess the exception code made yet. Maybe this -is still something we need to implement later, if there's any demand for it, or maybe we should modify -FreeRTOS to allow this in the future. (Which will then kill backwards compatibility... hmmm.) -*/ - j UserExceptionExit - - - .global gdbstub_handle_uart_int - .global gdbstub_uart_entry - .align 4 -gdbstub_uart_entry: - //On entry, the stack frame is at SP+16. - //This is a small stub to present that as the first arg to the gdbstub_handle_uart function. - movi a2, 16 - add a2, a2, a1 - movi a3, gdbstub_handle_uart_int - jx a3 + movi a2, gdbstub_regs +#ifdef XT_USE_OVLY + l32i a0, a2, XT_STK_OVLY + wsr a0, ovly #endif +#ifdef XT_USE_SWPRI + l32i a0, a2, XT_STK_VPRI + wsr a0, vpri +#endif +#if XCHAL_HAVE_LOOPS + l32i a0, a2, XT_STK_LCOUNT + wsr a0, lcount + l32i a0, a2, XT_STK_LEND + wsr a0, lend + l32i a0, a2, XT_STK_LBEG + wsr a0, lbeg +#endif - .global gdbstub_save_extra_sfrs_for_exception - .align 4 -//The Xtensa OS HAL does not save all the special function register things. This bit of assembly -//fills the gdbstub_savedRegs struct with them. + l32i a0, a2, XT_STK_SAR + wsr a0, sar + l32i a15, a2, XT_STK_A15 + l32i a14, a2, XT_STK_A14 + l32i a13, a2, XT_STK_A13 + l32i a12, a2, XT_STK_A12 + l32i a11, a2, XT_STK_A11 + l32i a10, a2, XT_STK_A10 + l32i a9, a2, XT_STK_A9 + l32i a8, a2, XT_STK_A8 + l32i a7, a2, XT_STK_A7 + l32i a6, a2, XT_STK_A6 + l32i a5, a2, XT_STK_A5 + l32i a4, a2, XT_STK_A4 + l32i a3, a2, XT_STK_A3 + + l32i a0, a2, XT_STK_A2 /* read original A2 and save it to EXCSAVE2 */ + wsr a0, DEBUG_EXCSAVE + l32i a0, a2, XT_STK_PS /* read original PS and save it to EPS2 */ + wsr a0, DEBUG_PS + l32i a0, a2, XT_STK_PC /* read original PC and save it to EPS2 */ + wsr a0, DEBUG_PC + + l32i a1, a2, XT_STK_A1 /* restore A1 (stack pointer) */ + l32i a0, a2, XT_STK_A0 /* restore A0 (return address) */ + + /* Read back vector-saved a2 value, put back address of this routine. */ + movi a2, gdbstub_debug_exception_entry + xsr a2, DEBUG_EXCSAVE + + /* All done. Return to where we came from. */ + rfi XCHAL_DEBUGLEVEL + + + .global gdbstub_save_extra_sfrs_for_exception + .align 4 +/* + * The Xtensa standard exception handlers does not save all the special + * function register things. This bit of assembly fills the gdbstub_regs struct + * with them. + */ gdbstub_save_extra_sfrs_for_exception: - movi a2, gdbstub_savedRegs - rsr a3, LITBASE - s32i a3, a2, 0x4C - rsr a3, 176 - s32i a3, a2, 0x50 - rsr a3, 208 - s32i a3, a2, 0x54 - rsr a3, EXCCAUSE - s32i a3, a2, 0x5C - ret - - .global gdbstub_init_debug_entry - .global _DebugExceptionVector - .align 4 + + /* a14-a15 are only saved by standard exception handlers for Windowed ABI */ + #ifdef __XTENSA_CALL0_ABI__ + movi a2, gdbstub_regs + s32i a14, a2, XT_STK_A14 + s32i a15, a2, XT_STK_A15 + #endif + + /* Save additional registers required for gdb_stub */ + movi a2, gdbstub_regs + XtExcFrameSize + rsr a3, LITBASE + s32i a3, a2, XT_STK_LITBASE + rsr a3, 176 + s32i a3, a2, XT_STK_SR176 + rsr a3, 208 + s32i a3, a2, XT_STK_SR208 + rsr a3, EXCCAUSE + s32i a3, a2, XT_STK_REASON + + ret + + + .global gdbstub_init_debug_entry + .global _DebugExceptionVector + .align 4 +/* + * This puts the following 2 instructions into the debug exception vector: + * xsr a2, DEBUG_EXCSAVE + * jx a2 + */ gdbstub_init_debug_entry: -//This puts the following 2 instructions into the debug exception vector: -// xsr a2, DEBUG_EXCSAVE -// jx a2 - movi a2, _DebugExceptionVector - movi a3, 0xa061d220 - s32i a3, a2, 0 - movi a3, 0x00000002 - s32i a3, a2, 4 -//Tell the just-installed debug vector where to go. - movi a2, gdbstub_debug_exception_entry - wsr a2, DEBUG_EXCSAVE + movi a2, _DebugExceptionVector + movi a3, 0xa061d220 + s32i a3, a2, 0 + movi a3, 0x00000002 + s32i a3, a2, 4 - ret + /* Tell the just-installed debug vector where to go. */ + movi a2, gdbstub_debug_exception_entry + wsr a2, DEBUG_EXCSAVE + ret -//Set up ICOUNT register to step one single instruction - .global gdbstub_icount_ena_single_step - .align 4 + + .global gdbstub_icount_ena_single_step + .align 4 +/* + * Set up ICOUNT register to step one single instruction + */ gdbstub_icount_ena_single_step: - movi a3, XCHAL_DEBUGLEVEL //Only count steps in non-debug mode - movi a2, -2 - wsr a3, ICOUNTLEVEL - wsr a2, ICOUNT - isync - ret + movi a3, XCHAL_DEBUGLEVEL /* Only count steps in non-debug mode */ + movi a2, -2 + wsr a3, ICOUNTLEVEL + wsr a2, ICOUNT + isync + ret +/* + * The following routines all assume that only one breakpoint and watchpoint + * is available, which is the case for the ESP8266 Xtensa core. + */ -//These routines all assume only one breakpoint and watchpoint is available, which -//is the case for the ESP8266 Xtensa core. + .global gdbstub_set_hw_breakpoint + .align 4 +/* + * set an hw breakpoint + * paramters: a2 = addr, a3 = len (unused here) + */ +gdbstub_set_hw_breakpoint: +call0 40000080 + rsr a4, IBREAKENABLE + bbsi a4, 0, return_w_error + wsr a2, IBREAKA + movi a2, 1 + wsr a2, IBREAKENABLE + isync + movi a2, 1 + ret - .global gdbstub_set_hw_breakpoint -gdbstub_set_hw_breakpoint: - //a2 - addr, a3 - len (unused here) - rsr a4, IBREAKENABLE - bbsi a4, 0, return_w_error - wsr a2, IBREAKA - movi a2, 1 - wsr a2, IBREAKENABLE - isync - movi a2, 1 - ret - - .global gdbstub_del_hw_breakpoint + + .global gdbstub_del_hw_breakpoint + .align 4 +/* + * delete an hw breakpoint + * paramters: a2 = addr + */ gdbstub_del_hw_breakpoint: - //a2 - addr - rsr a5, IBREAKENABLE - bbci a5, 0, return_w_error - rsr a3, IBREAKA - bne a3, a2, return_w_error - movi a2,0 - wsr a2, IBREAKENABLE - isync - movi a2, 1 - ret - - .global gdbstub_set_hw_watchpoint - //a2 - addr, a3 - mask, a4 - type (1=read, 2=write, 3=access) + + rsr a5, IBREAKENABLE + bbci a5, 0, return_w_error + rsr a3, IBREAKA + bne a3, a2, return_w_error + movi a2,0 + wsr a2, IBREAKENABLE + isync + movi a2, 1 + ret + + + .global gdbstub_set_hw_watchpoint + .align 4 +/* + * set an hw breakpoint + * paramters: a2 = addr, a3 = mask, a4 = type (1=read, 2=write, 3=access) + */ gdbstub_set_hw_watchpoint: - //Check if any of the masked address bits are set. If so, that is an error. - movi a5,0x0000003F - xor a5, a5, a3 - bany a2, a5, return_w_error - //Check if watchpoint already is set - rsr a5, DBREAKC - movi a6, 0xC0000000 - bany a6, a5, return_w_error - //Set watchpoint - wsr a2, DBREAKA - - //Combine type and mask - movi a6, 0x3F - and a3, a3, a6 - slli a4, a4, 30 - or a3, a3, a4 - wsr a3, DBREAKC - -// movi a2, 1 - mov a2, a3 - isync - ret - - - .global gdbstub_del_hw_watchpoint - //a2 - addr + + /* Check if any of the masked address bits are set. If so, that is an error. */ + movi a5,0x0000003F + xor a5, a5, a3 + bany a2, a5, return_w_error + + /* Check if watchpoint already is set */ + rsr a5, DBREAKC + movi a6, 0xC0000000 + bany a6, a5, return_w_error + + /* Set watchpoint */ + wsr a2, DBREAKA + + /* Combine type and mask */ + movi a6, 0x3F + and a3, a3, a6 + slli a4, a4, 30 + or a3, a3, a4 + wsr a3, DBREAKC + + mov a2, a3 + isync + ret + + + .global gdbstub_del_hw_watchpoint + .align 4 +/* + * delete a hw breakpoint + * paramters: a2 = addr + */ gdbstub_del_hw_watchpoint: - //See if the address matches - rsr a3, DBREAKA - bne a3, a2, return_w_error - //See if the bp actually is set - rsr a3, DBREAKC - movi a2, 0xC0000000 - bnone a3, a2, return_w_error - //Disable bp - movi a2,0 - wsr a2,DBREAKC - movi a2,1 - isync - ret + /* see if the address matches */ + rsr a3, DBREAKA + bne a3, a2, return_w_error + /* see if the bp actually is set */ + rsr a3, DBREAKC + movi a2, 0xC0000000 + bnone a3, a2, return_w_error + /* Disable bp */ + movi a2,0 + wsr a2,DBREAKC + movi a2,1 + isync + ret return_w_error: - movi a2, 0 - ret + movi a2, 0 + ret -//Breakpoint, with an attempt at a functional function prologue and epilogue... - .global gdbstub_do_break_breakpoint_addr - .global gdbstub_do_break - .align 4 + .global gdbstub_do_break_breakpoint_addr + .global gdbstub_do_break + .align 4 +/* + * Breakpoint, with an attempt at a functional function prologue and epilogue... + */ gdbstub_do_break: - addi a1, a1, -16 - s32i a15, a1, 12 - mov a15, a1 + addi a1, a1, -16 + s32i a15, a1, 12 + mov a15, a1 gdbstub_do_break_breakpoint_addr: - break 0,0 + break 0,0 - mov a1, a15 - l32i a15, a1, 12 - addi a1, a1, 16 - ret + mov a1, a15 + l32i a15, a1, 12 + addi a1, a1, 16 + ret diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.h b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.h index cecee2ad8e9f..63faaddbc27c 100644 --- a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.h +++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.h @@ -6,7 +6,6 @@ extern "C" { #endif void gdbstub_init_debug_entry(void); -void gdbstub_do_break(void); void gdbstub_icount_ena_single_step(void); void gdbstub_save_extra_sfrs_for_exception(void); void gdbstub_uart_entry(void); diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-exc.h b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-exc.h new file mode 100644 index 000000000000..bbcc266baea4 --- /dev/null +++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-exc.h @@ -0,0 +1,25 @@ +#ifndef GDBSTUB_EXC_H +#define GDBSTUB_EXC_H + +#include "xtensa/xtensa_context.h" + +/** + * @brief Structure of additional registers in excpeption fram as used by GDB + */ +STRUCT_BEGIN +STRUCT_FIELD (long, 4, XT_STK_LITBASE, litbase) +STRUCT_FIELD (long, 4, XT_STK_SR176, sr176) +STRUCT_FIELD (long, 4, XT_STK_SR208, sr208) +/* + * 'reason' is abused for both the debug and the exception vector: + * if bit 7 is set, this contains an exception reason, otherwise it + * contains a debug vector bitmap. + */ +STRUCT_FIELD (long, 4, XT_STK_REASON, reason) +STRUCT_END(XtExcFrameGdb) + +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* GDBSTUB_EXC_H */ diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub.c b/cpu/esp8266/vendor/esp-gdbstub/gdbstub.c index 5c80cdfdb116..3933f1dad7fe 100644 --- a/cpu/esp8266/vendor/esp-gdbstub/gdbstub.c +++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub.c @@ -7,54 +7,47 @@ * License: ESPRESSIF MIT License *******************************************************************************/ +#include #include -#include "gdbstub.h" -#include "ets_sys.h" #include "eagle_soc.h" -#include "c_types.h" -#include "gpio.h" +#include "esp_attr.h" +#include "esp_common.h" +#include "periph/uart.h" +#include "rom/ets_sys.h" +#include "sdk/sdk.h" #include "xtensa/corebits.h" #include "gdbstub.h" +#include "gdbstub-exc.h" #include "gdbstub-entry.h" #include "gdbstub-cfg.h" -// From xtruntime-frames.h -struct XTensa_exception_frame_s { - uint32_t pc; - uint32_t ps; - uint32_t sar; - uint32_t vpri; - uint32_t a0; - uint32_t a[14]; //a2..a15 - // These are added manually by the exception code; the HAL doesn't - // set these on an exception. - uint32_t litbase; - uint32_t sr176; - uint32_t sr208; - uint32_t a1; - // 'reason' is abused for both the debug and the exception vector: if bit 7 is set, - // this contains an exception reason, otherwise it contains a debug vector bitmap. - uint32_t reason; -}; +#if GDBSTUB_CTRLC_BREAK +#include "isrpipe.h" +#include "sched.h" +#include "thread.h" +#endif +#if GDBSTUB_BREAK_ON_INIT +#include "irq.h" +#endif -struct XTensa_rtos_int_frame_s { - uint32_t exitPtr; - uint32_t pc; - uint32_t ps; - uint32_t a[16]; - uint32_t sar; -}; +#define ets_isr_t xt_handler -// OS-less SDK defines. Defines some headers for things that aren't in the -// include files, plus the xthal stack frame struct. -#include "sdk/sdk.h" +/* register frame structure as used by gdbstub */ +typedef struct { + XtExcFrame exc_frame; /* exception frame as used by exception handlers */ + XtExcFrameGdb exc_frame_gdb; /* gdb exception frame extensions */ +} gdb_exception_frame_t; + +/* + * Defines some things that aren't in the include files + */ #define EXCEPTION_GDB_SP_OFFSET 0x100 -//We need some UART register defines. +/* We need some UART register defines. */ #define ETS_UART_INUM 5 #define REG_UART_BASE( i ) (0x60000000+(i)*0xf00) #define UART_STATUS( i ) (REG_UART_BASE( i ) + 0x1C) @@ -70,144 +63,150 @@ struct XTensa_rtos_int_frame_s { #define UART_RXFIFO_TOUT_INT_CLR (BIT(8)) #define UART_RXFIFO_FULL_INT_CLR (BIT(0)) -// Length of buffer used to reserve GDB commands. Has to be at least able to -// fit the G command, which implies a minimum size of about 190 bytes. +/* + * Length of buffer used to reserve GDB commands. Has to be at least able to + * fit the G command, which implies a minimum size of about 190 bytes. + */ #define PBUFLEN 256 -// Length of gdb stdout buffer, for console redirection -#define OBUFLEN 32 +/* Length of gdb stdout buffer, for console redirection */ +#define OBUFLEN 256 + +/* + * The asm stub saves the Xtensa registers here when a debugging exception + * happens. + */ +gdb_exception_frame_t gdbstub_regs; -// The asm stub saves the Xtensa registers here when a debugging exception -// happens. -struct XTensa_exception_frame_s gdbstub_savedRegs; #if GDBSTUB_USE_OWN_STACK -// This is the debugging exception stack. -int exceptionStack[256]; +/* This is the debugging exception stack. */ +int gdbstub_exceptionStack[GDBSTUB_STACK_SIZE / sizeof(int)]; #endif -static unsigned char cmd[PBUFLEN]; // GDB command input buffer -static char chsum; // Running checksum of the output packet +static unsigned char cmd[PBUFLEN]; /* GDB command input buffer */ +static char chsum; /* Running checksum of the out put packet */ #if GDBSTUB_REDIRECT_CONSOLE_OUTPUT -static unsigned char obuf[OBUFLEN]; // GDB stdout buffer -static int obufpos=0; // Current position in the buffer +static unsigned char obuf[OBUFLEN]; /* GDB stdout buffer */ +static int obufpos=0; /* Current position in the buffer */ #endif -static int32_t singleStepPs = -1; // Stores ps when single-stepping - // instruction. -1 when not in use. +static int32_t singleStepPs = -1; /* Stores ps when single-stepping */ + /* instruction. -1 when not in use. */ -// Small function to feed the hardware watchdog. Needed to stop the ESP from -// resetting due to a watchdog timeout while reading a command. -static void ATTR_GDBFN keepWDTalive(void) -{ - uint64_t *wdtval = (uint64_t*)0x3ff21048; - uint64_t *wdtovf = (uint64_t*)0x3ff210cc; - int *wdtctl = (int*)0x3ff210c8; - *wdtovf = *wdtval+1600000; - *wdtctl |= (1 << 31); -} +static bool gdbstub_initialized = false; -// Receive a char from the uart. Uses polling and feeds the watchdog. +/* Receive a char from the UART. Uses polling and feeds the watchdog. */ static int ATTR_GDBFN gdbRecvChar(void) { int i; - while (((READ_PERI_REG(UART_STATUS(0)) >> UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT)==0) - keepWDTalive(); + while (((READ_PERI_REG(UART_STATUS(0)) >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT)==0) { + WDT_FEED(); + } i = READ_PERI_REG(UART_FIFO(0)); return i; } -// Send a char to the uart. +/* Send a char to the UART. */ static void ATTR_GDBFN gdbSendChar(char c) { - while (((READ_PERI_REG(UART_STATUS(0)) >> UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) - ; - WRITE_PERI_REG(UART_FIFO(0), c); + uart_write(UART_DEV(0), (const uint8_t *)&c, 1); } -// Send the start of a packet; reset checksum calculation. +/* Send the start of a packet; reset checksum calculation. */ static void ATTR_GDBFN gdbPacketStart(void) { chsum=0; gdbSendChar('$'); } -// Send a char as part of a packet +/* Send a char as part of a packet */ static void ATTR_GDBFN gdbPacketChar(char c) { - if (c == '#' || c == '$' || c == '}' || c == '*') - { + if (c == '#' || c == '$' || c == '}' || c == '*') { gdbSendChar('}'); gdbSendChar(c ^ 0x20); chsum += (c ^ 0x20) +'}'; } - else - { + else { gdbSendChar(c); chsum += c; } } -// Send a string as part of a packet +/* Send a string as part of a packet */ static void ATTR_GDBFN gdbPacketStr(char *c) { - while (*c != 0) - { + while (*c != 0) { gdbPacketChar(*c); c++; } } -// Send a hex val as part of a packet. 'bits'/4 dictates the number of hex chars sent. +/* Send a hex val as part of a packet. 'bits'/4 dictates the number of hex chars sent. */ static void ATTR_GDBFN gdbPacketHex(int val, int bits) { char hexChars[]="0123456789abcdef"; int i; - for (i = bits; i > 0; i -= 4) + for (i = bits; i > 0; i -= 4) { gdbPacketChar(hexChars[(val >> (i-4)) & 0xf]); + } } -// Finish sending a packet. +/* Finish sending a packet. */ static void ATTR_GDBFN gdbPacketEnd(void) { gdbSendChar('#'); gdbPacketHex(chsum, 8); } -// Error states used by the routines that grab stuff from the incoming gdb packet +/* + * Error states used by the routines that grab stuff from the incoming + * gdb packet + */ #define ST_ENDPACKET -1 #define ST_ERR -2 #define ST_OK -3 #define ST_CONT -4 -// Grab a hex value from the gdb packet. Ptr will get positioned on the end -// of the hex string, as far as the routine has read into it. Bits/4 indicates -// the max amount of hex chars it gobbles up. Bits can be -1 to eat up as much -// hex chars as possible. -static long ATTR_GDBFN gdbGetHexVal(unsigned char **ptr, int bits) { +/* + * Grab a hex value from the gdb packet. Ptr will get positioned on the end + * of the hex string, as far as the routine has read into it. Bits/4 indicates + * the max amount of hex chars it gobbles up. Bits can be -1 to eat up as much + * hex chars as possible. + */ +static long ATTR_GDBFN gdbGetHexVal(unsigned char **ptr, int bits) +{ int i; - int no; - unsigned int v=0; - no=bits/4; - if (bits==-1) no=64; - for (i=0; i='0' && c<='9') { + if (c >= '0' && c <= '9') { v <<= 4; - v|=(c-'0'); - } else if (c>='A' && c<='F') { + v |= (c - '0'); + } + else if (c >= 'A' && c <= 'F') { v <<= 4; - v|=(c-'A')+10; - } else if (c>='a' && c<='f') { + v |= (c - 'A') + 10; + } + else if (c >= 'a' && c <= 'f') { v <<= 4; - v|=(c-'a')+10; - } else if (c=='#') { - if (bits==-1) { + v |= (c - 'a') + 10; + } + else if (c == '#') { + if (bits == -1) { (*ptr)--; return v; } return ST_ENDPACKET; - } else { - if (bits==-1) { + } + else { + if (bits == -1) { (*ptr)--; return v; } @@ -217,7 +216,7 @@ static long ATTR_GDBFN gdbGetHexVal(unsigned char **ptr, int bits) { return v; } -// Swap an int into the form gdb wants it +/* Swap an int into the form gdb wants it */ static int ATTR_GDBFN iswap(int i) { int r; @@ -228,41 +227,43 @@ static int ATTR_GDBFN iswap(int i) return r; } -// Read a byte from the ESP8266 memory. +/* Read a byte from the ESP8266 memory. */ static unsigned char ATTR_GDBFN readbyte(unsigned int p) { int *i = (int*)(p & (~3)); - if (p < 0x20000000 || p >= 0x60000000) + if (p < 0x20000000 || p >= 0x60000000) { return -1; + } return *i >> ((p & 3) * 8); } -// Write a byte to the ESP8266 memory. +/* Write a byte to the ESP8266 memory. */ static void ATTR_GDBFN writeByte(unsigned int p, unsigned char d) { int *i = (int*)(p & (~3)); - if (p < 0x20000000 || p >= 0x60000000) return; + if (p < 0x20000000 || p >= 0x60000000) { + return; + } if ((p & 3) == 0) *i = (*i & 0xffffff00) | (d << 0); if ((p & 3) == 1) *i = (*i & 0xffff00ff) | (d << 8); if ((p & 3) == 2) *i = (*i & 0xff00ffff) | (d << 16); if ((p & 3) == 3) *i = (*i & 0x00ffffff) | (d << 24); } -// Returns 1 if it makes sense to write to addr p +/* Returns 1 if it makes sense to write to addr p */ static int ATTR_GDBFN validWrAddr(int p) { - if (p >= 0x3ff00000 && p < 0x40000000) return 1; - if (p >= 0x40100000 && p < 0x40140000) return 1; - if (p >= 0x60000000 && p < 0x60002000) return 1; - return 0; + return ((p >= 0x3ff00000 && p < 0x40000000) || + (p >= 0x40100000 && p < 0x40140000) || + (p >= 0x60000000 && p < 0x60002000)) ? 1 : 0; } /* -Register file in the format lx106 gdb port expects it. -Inspired by gdb/regformats/reg-xtensa.dat from -https://github.com/jcmvbkbc/crosstool-NG/blob/lx106-g%2B%2B/overlays/xtensa_lx106.tar -As decoded by Cesanta. -*/ + * Register file in the format lx106 gdb port expects it. + * Inspired by gdb/regformats/reg-xtensa.dat from + * https://github.com/jcmvbkbc/crosstool-NG/blob/lx106-g%2B%2B/overlays/xtensa_lx106.tar + * As decoded by Cesanta. + */ struct regfile { uint32_t a[16]; @@ -274,201 +275,285 @@ struct regfile uint32_t ps; }; - -//Send the reason execution is stopped to GDB. +/* Send the reason execution is stopped to GDB. */ static void ATTR_GDBFN sendReason(void) { #if 0 - char *reason=""; //default + char *reason=""; /* default */ #endif + gdbPacketStart(); gdbPacketChar('T'); - if (gdbstub_savedRegs.reason == 0xff) - { - gdbPacketHex(2, 8); //sigint + if (gdbstub_regs.exc_frame_gdb.reason == 0xff) { + gdbPacketHex(2, 8); /* sigint */ } - else if (gdbstub_savedRegs.reason & 0x80) + else if (gdbstub_regs.exc_frame_gdb.reason & 0x80) { - // exception-to-signal mapping - char exceptionSignal[] = { 4, 31, 11, 11, 2, 6 , 8, 0, 6, 7, 0, 0, 7, 7, 7, 7}; - unsigned int i=0; - // We stopped because of an exception. - // Convert exception code to a signal number and send it. - i = gdbstub_savedRegs.reason & 0x7f; + /* exception-to-signal mapping */ + char exceptionSignal[] = { + SIGILL, /* IllegalInstructionCause >> SIGILL - 4 */ + SIGUSR2, /* SyscallCause >> SIGUSR2 - 31 */ + SIGSEGV, /* InstructionFetchErrorCause >> SIGSEGV - 11 */ + SIGSEGV, /* LoadStoreErrorCause >> SIGSEGV - 11 */ + SIGINT, /* Level1InterruptCause >> SIGINT - 2 */ + SIGABRT, /* AllocaCause >> SIGABRT - 6 */ + SIGFPE, /* IntegerDivideByZeroCause >> SIGFPE - 8 */ + 0, /* not used >> 0 */ + SIGABRT, /* PrivilegedCause >> SIGABRT - 6 */ + SIGEMT, /* LoadStoreAlignmentCause >> SIGEMT - 7 */ + 0, /* not used >> 0 */ + 0, /* not used >> 0 */ + SIGEMT, /* InstrPIFDataErrorCause >> SIGEMT - 7 */ + SIGEMT, /* LoadStorePIFDataErrorCause >> SIGEMT - 7 */ + SIGEMT, /* InstrPIFAddrErrorCause >> SIGEMT - 7 */ + SIGEMT /* LoadStorePIFAddrErrorCause >> SIGEMT - 7 */ + }; + unsigned int i = 0; + + /* We stopped because of an exception. */ + /* Convert exception code to a signal number and send it. */ + i = gdbstub_regs.exc_frame_gdb.reason & 0x7f; if (i < sizeof(exceptionSignal)) gdbPacketHex(exceptionSignal[i], 8); else - gdbPacketHex(11, 8); + gdbPacketHex(SIGSEGV, 8); } else { - // We stopped because of a debugging exception. - gdbPacketHex(5, 8); //sigtrap - // Current Xtensa GDB versions don't seem to request this, so let's - // leave it off. + /* We stopped because of a debugging exception. */ + gdbPacketHex(5, 8); /* sigtrap */ + + /* Current Xtensa GDB versions don't seem to request this, so let's leave it off. */ #if 0 - if (gdbstub_savedRegs.reason&(1 << 0)) reason="break"; - if (gdbstub_savedRegs.reason&(1 << 1)) reason="hwbreak"; - if (gdbstub_savedRegs.reason&(1 << 2)) reason="watch"; - if (gdbstub_savedRegs.reason&(1 << 3)) reason="swbreak"; - if (gdbstub_savedRegs.reason&(1 << 4)) reason="swbreak"; + if (gdbstub_regs.exc_frame_gdb.reason&(1 << 0)) reason="break"; + if (gdbstub_regs.exc_frame_gdb.reason&(1 << 1)) reason="hwbreak"; + if (gdbstub_regs.exc_frame_gdb.reason&(1 << 2)) reason="watch"; + if (gdbstub_regs.exc_frame_gdb.reason&(1 << 3)) reason="swbreak"; + if (gdbstub_regs.exc_frame_gdb.reason&(1 << 4)) reason="swbreak"; gdbPacketStr(reason); gdbPacketChar(':'); - //ToDo: watch: send address + /* TODO: watch: send address */ #endif } gdbPacketEnd(); } -// Handle a command as received from GDB. +/* + * Handle a command as received from GDB. + */ static int ATTR_GDBFN gdbHandleCommand(unsigned char *cmd, int len) { - // Handle a command int i, j, k; - unsigned char *data=cmd+1; - if (cmd[0] == 'g') - { // send all registers to gdb + unsigned char *data = cmd + 1; + + if (cmd[0] == 'g') { + /* + * send all registers to gdb + * format corresponds to struct regfile + */ + unsigned *ar = (unsigned*)&gdbstub_regs.exc_frame.a0; /* a register array */ gdbPacketStart(); - gdbPacketHex(iswap(gdbstub_savedRegs.a0), 32); - gdbPacketHex(iswap(gdbstub_savedRegs.a1), 32); - for (i = 2; i < 16; i++) - gdbPacketHex(iswap(gdbstub_savedRegs.a[i-2]), 32); - gdbPacketHex(iswap(gdbstub_savedRegs.pc), 32); - gdbPacketHex(iswap(gdbstub_savedRegs.sar), 32); - gdbPacketHex(iswap(gdbstub_savedRegs.litbase), 32); - gdbPacketHex(iswap(gdbstub_savedRegs.sr176), 32); - gdbPacketHex(0, 32); - gdbPacketHex(iswap(gdbstub_savedRegs.ps), 32); + for (int i = 0; i < 16; i++) { + gdbPacketHex(iswap(ar[i]), 32); + } + gdbPacketHex(iswap(gdbstub_regs.exc_frame.pc), 32); + gdbPacketHex(iswap(gdbstub_regs.exc_frame.sar), 32); + gdbPacketHex(iswap(gdbstub_regs.exc_frame_gdb.litbase), 32); + gdbPacketHex(iswap(gdbstub_regs.exc_frame_gdb.sr176), 32); + gdbPacketHex(0, 32); /* sr208 is not sent */ + gdbPacketHex(iswap(gdbstub_regs.exc_frame.ps), 32); gdbPacketEnd(); } - else if (cmd[0]=='G') - { //receive content for all registers from gdb - gdbstub_savedRegs.a0 = iswap(gdbGetHexVal(&data, 32)); - gdbstub_savedRegs.a1 = iswap(gdbGetHexVal(&data, 32)); - for (i = 2; i < 16; i++) - gdbstub_savedRegs.a[i-2]=iswap(gdbGetHexVal(&data, 32)); - gdbstub_savedRegs.pc = iswap(gdbGetHexVal(&data, 32)); - gdbstub_savedRegs.sar = iswap(gdbGetHexVal(&data, 32)); - gdbstub_savedRegs.litbase = iswap(gdbGetHexVal(&data, 32)); - gdbstub_savedRegs.sr176 = iswap(gdbGetHexVal(&data, 32)); + + else if (cmd[0]=='G') { + /* + * receive content for all registers from gdb + * format corresponds to struct regfile + */ + unsigned *ar = (unsigned*)&gdbstub_regs.exc_frame.a0; /* a register array */ + gdbPacketStart(); + for (int i = 0; i < 16; i++) { + ar[i] = iswap(gdbGetHexVal(&data, 32)); + } + gdbstub_regs.exc_frame.pc = iswap(gdbGetHexVal(&data, 32)); + gdbstub_regs.exc_frame.sar = iswap(gdbGetHexVal(&data, 32)); + gdbstub_regs.exc_frame_gdb.litbase = iswap(gdbGetHexVal(&data, 32)); + gdbstub_regs.exc_frame_gdb.sr176 = iswap(gdbGetHexVal(&data, 32)); gdbGetHexVal(&data, 32); - gdbstub_savedRegs.ps = iswap(gdbGetHexVal(&data, 32)); + gdbstub_regs.exc_frame.ps = iswap(gdbGetHexVal(&data, 32)); gdbPacketStart(); gdbPacketStr("OK"); gdbPacketEnd(); } - else if (cmd[0]=='m') { //read memory to gdb - i=gdbGetHexVal(&data, -1); + + else if (cmd[0]=='m') { + /* read memory to gdb */ + i = gdbGetHexVal(&data, -1); data++; - j=gdbGetHexVal(&data, -1); + j = gdbGetHexVal(&data, -1); + gdbPacketStart(); - for (k=0; k= PBUFLEN) { + return ST_ERR; } - cmd[p++]=c; - if (p>=PBUFLEN) return ST_ERR; - } - //A # has been received. Get and check the received chsum. - sentchs[0]=gdbRecvChar(); - sentchs[1]=gdbRecvChar(); - ptr=&sentchs[0]; - rchsum=gdbGetHexVal(&ptr, 8); -// ets_printf("c %x r %x\n", chsum, rchsum); - if (rchsum!=chsum) { + } + /* # has been received. Get the received chsum. */ + sentchs[0] = gdbRecvChar(); + sentchs[1] = gdbRecvChar(); + + /* check the received checksum */ + ptr = sentchs; + rchsum = gdbGetHexVal(&ptr, 8); + if (rchsum != chsum) { + /* wrong checksum, request retransmission */ gdbSendChar('-'); +_gdbstub_in_rcv_packet = false; return ST_ERR; - } else { - gdbSendChar('+'); - return gdbHandleCommand(cmd, p); } + + /* ack the package and handle the command */ + gdbSendChar('+'); +_gdbstub_in_rcv_packet = false; + return gdbHandleCommand(cmd, p); } -//Get the value of one of the A registers -static unsigned int ATTR_GDBFN getaregval(int reg) { - if (reg==0) return gdbstub_savedRegs.a0; - if (reg==1) return gdbstub_savedRegs.a1; - return gdbstub_savedRegs.a[reg-2]; +/* get the value of one of an A registers */ +static unsigned int ATTR_GDBFN getaregval(int reg) +{ + assert(reg >= 0 && reg < 16); + unsigned *ar = (unsigned*)&gdbstub_regs.exc_frame.a0; + return ar[reg]; } -//Set the value of one of the A registers -static void ATTR_GDBFN setaregval(int reg, unsigned int val) { +/* set the value of one of an A registers */ +static void ATTR_GDBFN setaregval(int reg, unsigned int val) +{ ets_printf("%x -> %x\n", val, reg); - if (reg==0) gdbstub_savedRegs.a0=val; - if (reg==1) gdbstub_savedRegs.a1=val; - gdbstub_savedRegs.a[reg-2]=val; + assert(reg >= 0 && reg < 16); + unsigned *ar = (unsigned*)&gdbstub_regs.exc_frame.a0; + ar[reg] = val; } -//Emulate the l32i/s32i instruction we're stopped at. -static void ATTR_GDBFN emulLdSt(void) { - unsigned char i0=readbyte(gdbstub_savedRegs.pc); - unsigned char i1=readbyte(gdbstub_savedRegs.pc+1); - unsigned char i2=readbyte(gdbstub_savedRegs.pc+2); +/* Emulate the l32i/s32i instruction we're stopped at. */ +static void ATTR_GDBFN emulLdSt(void) +{ + unsigned char i0 = readbyte(gdbstub_regs.exc_frame.pc); + unsigned char i1 = readbyte(gdbstub_regs.exc_frame.pc+1); + unsigned char i2 = readbyte(gdbstub_regs.exc_frame.pc+2); int *p; - if ((i0 & 0xf)==2 && (i1 & 0xf0)==0x20) { - //l32i - p=(int*)getaregval(i1 & 0xf)+(i2*4); + + if ((i0 & 0xf) == 2 && (i1 & 0xf0) == 0x20) { + /* l32i */ + p = (int*)getaregval(i1 & 0xf) + (i2 * 4); setaregval(i0 >> 4, *p); - gdbstub_savedRegs.pc+=3; - } else if ((i0 & 0xf)==0x8) { - //l32i.n - p=(int*)getaregval(i1 & 0xf)+((i1 >> 4)*4); + gdbstub_regs.exc_frame.pc += 3; + } + else if ((i0 & 0xf) == 0x8) { + /* l32i.n */ + p = (int*)getaregval(i1 & 0xf) + ((i1 >> 4) * 4); setaregval(i0 >> 4, *p); - gdbstub_savedRegs.pc+=2; - } else if ((i0 & 0xf)==2 && (i1 & 0xf0)==0x60) { - //s32i - p=(int*)getaregval(i1 & 0xf)+(i2*4); - *p=getaregval(i0 >> 4); - gdbstub_savedRegs.pc+=3; - } else if ((i0 & 0xf)==0x9) { - //s32i.n - p=(int*)getaregval(i1 & 0xf)+((i1 >> 4)*4); - *p=getaregval(i0 >> 4); - gdbstub_savedRegs.pc+=2; - } else { + gdbstub_regs.exc_frame.pc += 2; + } + else if ((i0 & 0xf) == 2 && (i1 & 0xf0) == 0x60) { + /* s32i */ + p = (int*)getaregval(i1 & 0xf) + (i2*4); + *p = getaregval(i0 >> 4); + gdbstub_regs.exc_frame.pc += 3; + } + else if ((i0 & 0xf) == 0x9) { + /* s32i.n */ + p = (int*)getaregval(i1 & 0xf) + ((i1 >> 4) * 4); + *p = getaregval(i0 >> 4); + gdbstub_regs.exc_frame.pc += 2; + } + else { ets_printf("GDBSTUB: No l32i/s32i instruction: %x %x %x. Huh?", i2, i1, i0); } } -// We just caught a debug exception and need to handle it. This is called -// from an assembly routine in gdbstub-entry.S +void gdbstub_print_regs(void) +{ + ets_printf("pc : %08x\t", gdbstub_regs.exc_frame.pc); + ets_printf("ps : %08x\t", gdbstub_regs.exc_frame.ps); + ets_printf("exccause: %08x\t", gdbstub_regs.exc_frame.exccause); + ets_printf("excvaddr: %08x\n", gdbstub_regs.exc_frame.excvaddr); + ets_printf("a0 : %08x\t", gdbstub_regs.exc_frame.a0); + ets_printf("a1 : %08x\t", gdbstub_regs.exc_frame.a1); + ets_printf("a2 : %08x\t", gdbstub_regs.exc_frame.a2); + ets_printf("a3 : %08x\n", gdbstub_regs.exc_frame.a3); + ets_printf("a4 : %08x\t", gdbstub_regs.exc_frame.a4); + ets_printf("a5 : %08x\t", gdbstub_regs.exc_frame.a5); + ets_printf("a6 : %08x\t", gdbstub_regs.exc_frame.a6); + ets_printf("a7 : %08x\n", gdbstub_regs.exc_frame.a7); + ets_printf("a8 : %08x\t", gdbstub_regs.exc_frame.a8); + ets_printf("a9 : %08x\t", gdbstub_regs.exc_frame.a9); + ets_printf("a10 : %08x\t", gdbstub_regs.exc_frame.a10); + ets_printf("a11 : %08x\n", gdbstub_regs.exc_frame.a11); + ets_printf("a12 : %08x\t", gdbstub_regs.exc_frame.a12); + ets_printf("a13 : %08x\t", gdbstub_regs.exc_frame.a13); + ets_printf("a14 : %08x\t", gdbstub_regs.exc_frame.a14); + ets_printf("a15 : %08x\n", gdbstub_regs.exc_frame.a15); +#if XCHAL_HAVE_LOOPS + ets_printf("lbeg : %08x\t", gdbstub_regs.exc_frame.lbeg); + ets_printf("lend : %08x\t", gdbstub_regs.exc_frame.lend); + ets_printf("lcount : %08x\n", gdbstub_regs.exc_frame.lcount); +#endif /* XCHAL_HAVE_LOOPS */ +#ifdef XT_USE_SWPRI + ets_printf("vpri : %08x\n", gdbstub_regs.exc_frame.vpri); +#endif +#ifdef XT_USE_OVLY +#ifdef XT_USE_SWPRI + ets_printf("ovly : %08x\n", gdbstub_regs.exc_frame.ovly); +#endif +#endif + ets_printf("litbase : %08x\t", gdbstub_regs.exc_frame_gdb.litbase); + ets_printf("sr176 : %08x\t", gdbstub_regs.exc_frame_gdb.sr176); + ets_printf("sr208 : %08x\t", gdbstub_regs.exc_frame_gdb.sr208); + ets_printf("reason : %08x\n", gdbstub_regs.exc_frame_gdb.reason); +} + +/* + * We just caught a debug exception and need to handle it. This is called + * from an assembly routine in gdbstub-entry.S + */ void ATTR_GDBFN gdbstub_handle_debug_exception(void) { ets_wdt_disable(); if (singleStepPs != -1) { - // We come here after single-stepping an instruction. Interrupts are - // disabled for the single step. Re-enable them here. - gdbstub_savedRegs.ps = (gdbstub_savedRegs.ps & ~0xf) | (singleStepPs & 0xf); + /* + * We come here after single-stepping an instruction. Interrupts are + * disabled for the single step. Re-enable them here. + */ + gdbstub_regs.exc_frame.ps = (gdbstub_regs.exc_frame.ps & ~0xf) | (singleStepPs & 0xf); singleStepPs = -1; } sendReason(); - while (gdbReadCommand()!=ST_CONT) - ; + while (gdbReadCommand() != ST_CONT) { } - if ((gdbstub_savedRegs.reason & 0x84) == 0x4) + if ((gdbstub_regs.exc_frame_gdb.reason & 0x84) == 0x4) { - //We stopped due to a watchpoint. We can't re-execute the current instruction - //because it will happily re-trigger the same watchpoint, so we emulate it - //while we're still in debugger space. + /* + * We stopped due to a watchpoint. We can't re-execute the current + * instruction because it will happily re-trigger the same watchpoint, + * so we emulate it while we're still in debugger space. + */ emulLdSt(); - } else if ((gdbstub_savedRegs.reason & 0x88)==0x8) { - //We stopped due to a BREAK instruction. Skip over it. - //Check the instruction first; gdb may have replaced it with the original instruction - //if it's one of the breakpoints it set. - if (readbyte(gdbstub_savedRegs.pc+2)==0 && - (readbyte(gdbstub_savedRegs.pc+1) & 0xf0)==0x40 && - (readbyte(gdbstub_savedRegs.pc) & 0x0f)==0x00) { - gdbstub_savedRegs.pc+=3; + } + else if ((gdbstub_regs.exc_frame_gdb.reason & 0x88) == 0x8) { + /* + * We stopped due to a BREAK instruction. Skip over it. Check the + * instruction first; gdb may have replaced it with the + * original instruction if it's one of the breakpoints it set. + */ + if ((readbyte(gdbstub_regs.exc_frame.pc + 2) & 0xff) == 0 && + (readbyte(gdbstub_regs.exc_frame.pc + 1) & 0xf0) == 0x40 && + (readbyte(gdbstub_regs.exc_frame.pc) & 0x0f) == 0x00) { + gdbstub_regs.exc_frame.pc += 3; } - } else if ((gdbstub_savedRegs.reason & 0x90)==0x10) { - //We stopped due to a BREAK.N instruction. Skip over it, after making sure the instruction - //actually is a BREAK.N - if ((readbyte(gdbstub_savedRegs.pc+1) & 0xf0)==0xf0 && - readbyte(gdbstub_savedRegs.pc)==0x2d) { - gdbstub_savedRegs.pc+=3; + } + else if ((gdbstub_regs.exc_frame_gdb.reason & 0x90) == 0x10) { + /* + * We stopped due to a BREAK.N instruction. Skip over it, after + * making sure the instruction actually is a BREAK.N + */ + if ((readbyte(gdbstub_regs.exc_frame.pc+1) & 0xf0) == 0xf0 && + (readbyte(gdbstub_regs.exc_frame.pc) & 0xff) == 0x2d) { + gdbstub_regs.exc_frame.pc+=3; } } ets_wdt_enable(); } - -#ifdef MODULE_ESP_SDK_INT_HANDLING - -// Non-OS exception handler. Gets called by the Xtensa HAL. -static void ATTR_GDBFN gdb_exception_handler (void* arg) +static void ATTR_GDBFN gdb_exception_handler(XtExcFrame *frame) { - struct XTensa_exception_frame_s* frame = (struct XTensa_exception_frame_s*)arg; + assert(frame != NULL); - // Save the extra registers the Xtensa HAL doesn't save - gdbstub_save_extra_sfrs_for_exception(); + ets_printf("GDB entry after exception @%08x\n", frame->pc); - // Copy registers the Xtensa HAL did save to gdbstub_savedRegs - ets_memcpy(&gdbstub_savedRegs, frame, 19*4); + /* + * On entry, registers ps, pc, a0...a15, sar, lbeg, lend, lcount, vpri, + * ovly have been already saved by _xt_user_exc including _xt_context_save + */ - // Credits go to Cesanta for this trick. A1 seems to be destroyed, but because it - // has a fixed offset from the address of the passed frame, we can recover it. - gdbstub_savedRegs.a1 = (uint32_t)frame + EXCEPTION_GDB_SP_OFFSET; + /* copy the registers the Xtensa exception handler did save to gdbstub_regs */ + ets_memcpy(&gdbstub_regs.exc_frame, frame, sizeof(XtExcFrame)); + + /* save the extra registers the exception vectors doesn't save */ + gdbstub_save_extra_sfrs_for_exception(); - gdbstub_savedRegs.reason |= 0x80; //mark as an exception reason + gdbstub_regs.exc_frame_gdb.reason |= 0x80; /* mark as an exception reason */ ets_wdt_disable(); + sendReason(); - while (gdbReadCommand() != ST_CONT) - ; + while (gdbReadCommand() != ST_CONT) { } + ets_wdt_enable(); - // Copy any changed registers back to the frame the Xtensa HAL uses. - ets_memcpy(frame, &gdbstub_savedRegs, 19*4); + /* Copy changed registers back to the standard exception frame. */ + ets_memcpy(frame, &gdbstub_regs.exc_frame, sizeof(XtExcFrame)); } -#else -/* TODO -static void ATTR_GDBFN gdb_exception_handler (XtExcFrame *frame) +#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT +/* + * The following functions realize the communication with the gdb for console + * output. Each *printf function finally calls ets_printf which in turn calls + * ets_putc. Instead of spitting out the characters directly, the characters + * are be buffered up to OBUFLEN characters or up to a \n and sent out as a hex + * coded gdb packet. + */ + +int gdbstub_obuf_flush(void) { - ets_printf("GDB EXCEPTION\n"); - while (1) ; + int i; + gdbPacketStart(); + gdbPacketChar('O'); + for (i = 0; i < obufpos; i++) { + gdbPacketHex(obuf[i], 8); + } + gdbPacketEnd(); + obufpos = 0; + return i; } -*/ -#endif // MODULE_ESP_SDK_INT_HANDLING +/* function used by any printf function */ +int ets_putc(int c) +{ + /* before gdbstub is initialized we simply send the char */ + if (!gdbstub_initialized) { + gdbSendChar(c); + return c; + } -#if GDBSTUB_REDIRECT_CONSOLE_OUTPUT -// Replacement putchar1 routine. Instead of spitting out the character -// directly, it will buffer up to OBUFLEN characters (or up to a \n, -// whichever comes earlier) and send it out as a gdb stdout packet. -static void ATTR_GDBFN gdb_semihost_putchar1(char c) + /* put the character into the output buffer */ + obuf[obufpos++] = c; + + /* flush the buffer if newline is given or buffer is full */ + if (c == '\n' || obufpos == OBUFLEN) { + gdbstub_obuf_flush(); + } + + return c; +} + +/* function used with single characters, e.g. echoed input in shell */ +int putchar(int c) { - obuf[obufpos++]=c; - if (c=='\n' || obufpos==OBUFLEN) - { - int i; - gdbPacketStart(); - gdbPacketChar('O'); - for (i=0; isp != NULL); + + XtExcFrame* frame = (XtExcFrame *)sched_active_thread->sp; + int doDebug=0; int fifolen=0; - //Save the extra registers the Xtensa HAL doesn't save + + /* Save the extra registers the standard exception handlers don't save */ gdbstub_save_extra_sfrs_for_exception(); - fifolen=(READ_PERI_REG(UART_STATUS(0)) >> UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT; - while (fifolen!=0) + fifolen = (READ_PERI_REG(UART_STATUS(0)) >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT; + while (fifolen != 0) { - //Check if any of the chars is control-C. Throw away rest. - if ((READ_PERI_REG(UART_FIFO(0)) & 0xFF)==0x3) + uint8_t data = READ_PERI_REG(UART_FIFO(0)) & 0xff; + if (data == 0x03) { + /* if char is control-C, break execution and do in debug mode */ doDebug=1; + } + else if (data != '+' && data != '-' && !_gdbstub_in_rcv_packet) { + /* if char is not '+' (gdb ack/nak), forward it to stdio */ + extern isrpipe_t stdio_uart_isrpipe; + isrpipe_write_one(&stdio_uart_isrpipe, data); + } fifolen--; } - WRITE_PERI_REG(UART_INT_CLR(0), UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR); + WRITE_PERI_REG(UART_INT_CLR(0), UART_RXFIFO_FULL_INT_CLR | UART_RXFIFO_TOUT_INT_CLR); if (doDebug) { - // Copy registers the Xtensa HAL did save to gdbstub_savedRegs - ets_memcpy(&gdbstub_savedRegs, frame, 19*4); - gdbstub_savedRegs.a1=(uint32_t)frame+EXCEPTION_GDB_SP_OFFSET; + /* copy the registers the Xtensa exception handler did save to gdbstub_regs */ + ets_memcpy(&gdbstub_regs.exc_frame, frame, sizeof(XtExcFrame)); - //mark as user break reason - gdbstub_savedRegs.reason=0xff; + /* mark as user break reason */ + gdbstub_regs.exc_frame_gdb.reason = 0xff; ets_wdt_disable(); + sendReason(); - while(gdbReadCommand()!=ST_CONT); + while (gdbReadCommand() != ST_CONT) { } + ets_wdt_enable(); - // Copy any changed registers back to the frame the Xtensa HAL uses. - ets_memcpy(frame, &gdbstub_savedRegs, 19*4); + + /* Copy changed registers back to the standard exception frame. */ + ets_memcpy(frame, &gdbstub_regs.exc_frame, sizeof(XtExcFrame)); } } static void ATTR_GDBINIT install_uart_hdlr(void) { + /* set UART interrupt handler to the handler of gdbstub */ ets_isr_attach(ETS_UART_INUM, (ets_isr_t)uart_hdlr, NULL); + /* clear all interrupts */ SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA); - // enable uart interrupt + /* enable uart interrupt */ ets_isr_unmask((1 << ETS_UART_INUM)); } -#endif // GDBSTUB_CTRLC_BREAK +#endif /* GDBSTUB_CTRLC_BREAK */ + +extern bool _esp_output_active; -// gdbstub initialization routine. +/* gdbstub initialization routine. */ void ATTR_GDBINIT gdbstub_init(void) { - #if GDBSTUB_REDIRECT_CONSOLE_OUTPUT - ets_install_putc1(gdb_semihost_putchar1); - #endif - #if GDBSTUB_CTRLC_BREAK install_uart_hdlr(); #endif install_exceptions(); gdbstub_init_debug_entry(); + gdbstub_initialized = true; #if GDBSTUB_BREAK_ON_INIT + /* before break, PS.INTLEVEL has to be set correctly to allow debug exceptions */ + uint32_t _old_intlevel; + __asm__ volatile ("rsil %0, " XTSTR(XCHAL_DEBUGLEVEL - 1) : "=a" (_old_intlevel)); + (void)_old_intlevel; + /* now lets break on init */ gdbstub_do_break(); #endif } diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub.h b/cpu/esp8266/vendor/esp-gdbstub/gdbstub.h index d9e8b4a094ff..f47b2b1e0d71 100644 --- a/cpu/esp8266/vendor/esp-gdbstub/gdbstub.h +++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub.h @@ -6,6 +6,7 @@ extern "C" { #endif void gdbstub_init(void); +void gdbstub_do_break(void); #ifdef __cplusplus } diff --git a/cpu/esp8266/vendor/esp-idf/Makefile b/cpu/esp8266/vendor/esp-idf/Makefile new file mode 100644 index 000000000000..396aa95de908 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/Makefile @@ -0,0 +1,13 @@ +MODULE=esp_idf + +DIRS += esp8266/source +DIRS += nvs_flash/src +DIRS += spi_flash +DIRS += util/src +DIRS += wpa_supplicant + +ifneq (, $(filter esp_idf_heap, $(USEMODULE))) + DIRS += heap/src +endif + +include $(RIOTBASE)/Makefile.base diff --git a/cpu/esp8266/vendor/esp-idf/README.md b/cpu/esp8266/vendor/esp-idf/README.md new file mode 100644 index 000000000000..7a7050b924b8 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/README.md @@ -0,0 +1 @@ +The files in this directory and all subdirectories are from the [ESP8266 RTOS SDK](https://github.com/espressif/ESP8266_RTOS_SDK), the official development framework for ESP8266. All of these files are copyright of Espressif Systems (Shanghai) PTE LTD or their respective owners and licensed under the Apache License, Version 2.0. Please refer the copyright notice in these files for details. diff --git a/cpu/esp8266/vendor/esp-idf/bootloader_support/include/esp_image_format.h b/cpu/esp8266/vendor/esp-idf/bootloader_support/include/esp_image_format.h new file mode 100644 index 000000000000..6652349ddd37 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/bootloader_support/include/esp_image_format.h @@ -0,0 +1,181 @@ +// 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. +#pragma once + +#include +#include +#include "esp_flash_partitions.h" +#include "sdkconfig.h" + +#define ESP_ERR_IMAGE_BASE 0x2000 +#define ESP_ERR_IMAGE_FLASH_FAIL (ESP_ERR_IMAGE_BASE + 1) +#define ESP_ERR_IMAGE_INVALID (ESP_ERR_IMAGE_BASE + 2) + +/* Support for app/bootloader image parsing + Can be compiled as part of app or bootloader code. +*/ + +/* SPI flash mode, used in esp_image_header_t */ +typedef enum { + ESP_IMAGE_SPI_MODE_QIO, + ESP_IMAGE_SPI_MODE_QOUT, + ESP_IMAGE_SPI_MODE_DIO, + ESP_IMAGE_SPI_MODE_DOUT, + ESP_IMAGE_SPI_MODE_FAST_READ, + ESP_IMAGE_SPI_MODE_SLOW_READ +} esp_image_spi_mode_t; + +/* SPI flash clock frequency */ +typedef enum { + ESP_IMAGE_SPI_SPEED_40M, + ESP_IMAGE_SPI_SPEED_26M, + ESP_IMAGE_SPI_SPEED_20M, + ESP_IMAGE_SPI_SPEED_80M = 0xF +} esp_image_spi_freq_t; + +#ifdef CONFIG_TARGET_PLATFORM_ESP32 +/* Supported SPI flash sizes */ +typedef enum { + ESP_IMAGE_FLASH_SIZE_1MB = 0, + ESP_IMAGE_FLASH_SIZE_2MB, + ESP_IMAGE_FLASH_SIZE_4MB, + ESP_IMAGE_FLASH_SIZE_8MB, + ESP_IMAGE_FLASH_SIZE_16MB, + ESP_IMAGE_FLASH_SIZE_MAX +} esp_image_flash_size_t; +#endif + +#ifdef CONFIG_TARGET_PLATFORM_ESP8266 +/* Supported SPI flash sizes */ +typedef enum { + ESP_IMAGE_FLASH_SIZE_512KB = 0, + ESP_IMAGE_FLASH_SIZE_256KB, + ESP_IMAGE_FLASH_SIZE_1MB, + ESP_IMAGE_FLASH_SIZE_2MB, + ESP_IMAGE_FLASH_SIZE_4MB, + ESP_IMAGE_FLASH_SIZE_2MB_C1, + ESP_IMAGE_FLASH_SIZE_4MB_C1, + ESP_IMAGE_FLASH_SIZE_8MB = 8, + ESP_IMAGE_FLASH_SIZE_16MB, + ESP_IMAGE_FLASH_SIZE_MAX +} esp_image_flash_size_t; + +#endif + +#define ESP_IMAGE_HEADER_MAGIC 0xE9 + +/* Main header of binary image */ +typedef struct { + uint8_t magic; + uint8_t segment_count; + /* flash read mode (esp_image_spi_mode_t as uint8_t) */ + uint8_t spi_mode; + /* flash frequency (esp_image_spi_freq_t as uint8_t) */ + uint8_t spi_speed: 4; + /* flash chip size (esp_image_flash_size_t as uint8_t) */ + uint8_t spi_size: 4; + uint32_t entry_addr; + +#ifdef CONFIG_TARGET_PLATFORM_ESP32 + /* WP pin when SPI pins set via efuse (read by ROM bootloader, the IDF bootloader uses software to configure the WP + * pin and sets this field to 0xEE=disabled) */ + uint8_t wp_pin; + /* Drive settings for the SPI flash pins (read by ROM bootloader) */ + uint8_t spi_pin_drv[3]; + /* Reserved bytes in ESP32 additional header space, currently unused */ + uint8_t reserved[11]; + /* If 1, a SHA256 digest "simple hash" (of the entire image) is appended after the checksum. Included in image length. This digest + * is separate to secure boot and only used for detecting corruption. For secure boot signed images, the signature + * is appended after this (and the simple hash is included in the signed data). */ + uint8_t hash_appended; +#endif +} __attribute__((packed)) esp_image_header_t; + +#ifdef CONFIG_TARGET_PLATFORM_ESP32 +_Static_assert(sizeof(esp_image_header_t) == 24, "binary image header should be 24 bytes"); +#endif + +#ifdef CONFIG_TARGET_PLATFORM_ESP8266 +_Static_assert(sizeof(esp_image_header_t) == 8, "binary image header should be 8 bytes"); +#endif + +/* Header of binary image segment */ +typedef struct { + uint32_t load_addr; + uint32_t data_len; +} esp_image_segment_header_t; + +#define ESP_IMAGE_MAX_SEGMENTS 16 + +/* Structure to hold on-flash image metadata */ +typedef struct { + uint32_t start_addr; /* Start address of image */ + esp_image_header_t image; /* Header for entire image */ + esp_image_segment_header_t segments[ESP_IMAGE_MAX_SEGMENTS]; /* Per-segment header data */ + uint32_t segment_data[ESP_IMAGE_MAX_SEGMENTS]; /* Data offsets for each segment */ + uint32_t image_len; /* Length of image on flash, in bytes */ +} esp_image_metadata_t; + +/* Mode selection for esp_image_load() */ +typedef enum { + ESP_IMAGE_VERIFY, /* Verify image contents, load metadata. Print errorsors. */ + ESP_IMAGE_VERIFY_SILENT, /* Verify image contents, load metadata. Don't print errors. */ +#ifdef BOOTLOADER_BUILD + ESP_IMAGE_LOAD, /* Verify image contents, load to memory. Print errors. */ +#endif +} esp_image_load_mode_t; + +/** + * @brief Verify and (optionally, in bootloader mode) load an app image. + * + * If encryption is enabled, data will be transparently decrypted. + * + * @param mode Mode of operation (verify, silent verify, or load). + * @param part Partition to load the app from. + * @param[inout] data Pointer to the image metadata structure which is be filled in by this function. 'start_addr' member should be set (to the start address of the image.) Other fields will all be initialised by this function. + * + * Image validation checks: + * - Magic byte. + * - Partition smaller than 16MB. + * - All segments & image fit in partition. + * - 8 bit image checksum is valid. + * - SHA-256 of image is valid (if image has this appended). + * - (Signature) if signature verification is enabled. + * + * @return + * - ESP_OK if verify or load was successful + * - ESP_ERR_IMAGE_FLASH_FAIL if a SPI flash error occurs + * - ESP_ERR_IMAGE_INVALID if the image appears invalid. + * - ESP_ERR_INVALID_ARG if the partition or data pointers are invalid. + */ +esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data); + +/** + * @brief Verify the bootloader image. + * + * @param[out] If result is ESP_OK and this pointer is non-NULL, it + * will be set to the length of the bootloader image. + * + * @return As per esp_image_load_metadata(). + */ +esp_err_t esp_image_verify_bootloader(uint32_t *length); + +typedef struct { + uint32_t drom_addr; + uint32_t drom_load_addr; + uint32_t drom_size; + uint32_t irom_addr; + uint32_t irom_load_addr; + uint32_t irom_size; +} esp_image_flash_mapping_t; diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/include/esp8266/rom_functions.h b/cpu/esp8266/vendor/esp-idf/esp8266/include/esp8266/rom_functions.h new file mode 100644 index 000000000000..41d731402552 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/include/esp8266/rom_functions.h @@ -0,0 +1,45 @@ +#ifndef _ROM_FUNCTIONS_H +#define _ROM_FUNCTIONS_H + +#include +#include + +#define ROM_FLASH_BUF_DECLARE(__name, __size) uint8_t __name[__size] __attribute__((aligned(4))) + +typedef struct esp_spi_flash_chip { + uint32_t deviceId; + uint32_t chip_size; // chip size in byte + uint32_t block_size; + uint32_t sector_size; + uint32_t page_size; + uint32_t status_mask; +} esp_spi_flash_chip_t; + +extern esp_spi_flash_chip_t flashchip; + +uint32_t Wait_SPI_Idle(esp_spi_flash_chip_t *chip); + +void uart_div_modify(uint32_t uart_no, uint32_t baud_div); + +int ets_io_vprintf(int (*putc)(int), const char* fmt, va_list ap); + +void system_soft_wdt_feed(void); + +void Cache_Read_Enable_New(void); + +int SPI_page_program(esp_spi_flash_chip_t *chip, uint32_t dst_addr, void *pbuf, uint32_t len); +int SPI_read_data(esp_spi_flash_chip_t *chip, uint32_t dst_addr, void *pbuf, uint32_t len); +int SPI_write_enable(esp_spi_flash_chip_t *chip); +int SPI_sector_erase(esp_spi_flash_chip_t *chip, uint32_t sect_addr); +int SPI_write_status(esp_spi_flash_chip_t *chip, uint32_t status); +int SPI_read_status(esp_spi_flash_chip_t *chip, uint32_t *status); +int Enable_QMode(esp_spi_flash_chip_t *chip); + +int SPIWrite(uint32_t addr, const uint8_t *src, uint32_t size); +int SPIRead(uint32_t addr, void *dst, uint32_t size); +int SPIEraseSector(uint32_t sector_num); + +void Cache_Read_Disable(void); +void Cache_Read_Enable(uint8_t map, uint8_t p, uint8_t v); + +#endif diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/include/esp_event.h b/cpu/esp8266/vendor/esp-idf/esp8266/include/esp_event.h new file mode 100644 index 000000000000..ecb07a06a10d --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/include/esp_event.h @@ -0,0 +1,195 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __ESP_EVENT_H__ +#define __ESP_EVENT_H__ + +#include +#include + +#include "esp_err.h" +#include "esp_wifi_types.h" +#ifndef RIOT_VERSION +#include "lwip/ip_addr.h" +#include "tcpip_adapter.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_EVENT_IPV6 LWIP_IPV6 + +typedef enum { + SYSTEM_EVENT_WIFI_READY = 0, /**< ESP8266 WiFi ready */ + SYSTEM_EVENT_SCAN_DONE, /**< ESP8266 finish scanning AP */ + SYSTEM_EVENT_STA_START, /**< ESP8266 station start */ + SYSTEM_EVENT_STA_STOP, /**< ESP8266 station stop */ + SYSTEM_EVENT_STA_CONNECTED, /**< ESP8266 station connected to AP */ + SYSTEM_EVENT_STA_DISCONNECTED, /**< ESP8266 station disconnected from AP */ + SYSTEM_EVENT_STA_AUTHMODE_CHANGE, /**< the auth mode of AP connected by ESP8266 station changed */ + SYSTEM_EVENT_STA_GOT_IP, /**< ESP8266 station got IP from connected AP */ + SYSTEM_EVENT_STA_LOST_IP, /**< ESP8266 station lost IP and the IP is reset to 0 */ + SYSTEM_EVENT_STA_WPS_ER_SUCCESS, /**< ESP8266 station wps succeeds in enrollee mode */ + SYSTEM_EVENT_STA_WPS_ER_FAILED, /**< ESP8266 station wps fails in enrollee mode */ + SYSTEM_EVENT_STA_WPS_ER_TIMEOUT, /**< ESP8266 station wps timeout in enrollee mode */ + SYSTEM_EVENT_STA_WPS_ER_PIN, /**< ESP8266 station wps pin code in enrollee mode */ + SYSTEM_EVENT_AP_START, /**< ESP8266 soft-AP start */ + SYSTEM_EVENT_AP_STOP, /**< ESP8266 soft-AP stop */ + SYSTEM_EVENT_AP_STACONNECTED, /**< a station connected to ESP8266 soft-AP */ + SYSTEM_EVENT_AP_STADISCONNECTED, /**< a station disconnected from ESP8266 soft-AP */ + SYSTEM_EVENT_AP_STAIPASSIGNED, /**< ESP8266 soft-AP assign an IP to a connected station */ + SYSTEM_EVENT_AP_PROBEREQRECVED, /**< Receive probe request packet in soft-AP interface */ + SYSTEM_EVENT_GOT_IP6, /**< ESP8266 station or ap or ethernet interface v6IP addr is preferred */ + SYSTEM_EVENT_ETH_START, /**< ESP8266 ethernet start */ + SYSTEM_EVENT_ETH_STOP, /**< ESP8266 ethernet stop */ + SYSTEM_EVENT_ETH_CONNECTED, /**< ESP8266 ethernet phy link up */ + SYSTEM_EVENT_ETH_DISCONNECTED, /**< ESP8266 ethernet phy link down */ + SYSTEM_EVENT_ETH_GOT_IP, /**< ESP8266 ethernet got IP from connected AP */ + SYSTEM_EVENT_MAX +} system_event_id_t; + +/* add this macro define for compatible with old IDF version */ +#ifndef SYSTEM_EVENT_AP_STA_GOT_IP6 +#define SYSTEM_EVENT_AP_STA_GOT_IP6 SYSTEM_EVENT_GOT_IP6 +#endif + +typedef enum { + WPS_FAIL_REASON_NORMAL = 0, /**< ESP8266 WPS normal fail reason */ + WPS_FAIL_REASON_RECV_M2D, /**< ESP8266 WPS receive M2D frame */ + WPS_FAIL_REASON_MAX +}system_event_sta_wps_fail_reason_t; + +typedef struct { + uint32_t status; /**< status of scanning APs */ + uint8_t number; + uint8_t scan_id; +} system_event_sta_scan_done_t; + +typedef struct { + uint8_t ssid[32]; /**< SSID of connected AP */ + uint8_t ssid_len; /**< SSID length of connected AP */ + uint8_t bssid[6]; /**< BSSID of connected AP*/ + uint8_t channel; /**< channel of connected AP*/ + wifi_auth_mode_t authmode; +} system_event_sta_connected_t; + +typedef struct { + uint8_t ssid[32]; /**< SSID of disconnected AP */ + uint8_t ssid_len; /**< SSID length of disconnected AP */ + uint8_t bssid[6]; /**< BSSID of disconnected AP */ + uint8_t reason; /**< reason of disconnection */ +} system_event_sta_disconnected_t; + +typedef struct { + wifi_auth_mode_t old_mode; /**< the old auth mode of AP */ + wifi_auth_mode_t new_mode; /**< the new auth mode of AP */ +} system_event_sta_authmode_change_t; + +#ifndef RIOT_VERSION +typedef struct { + tcpip_adapter_ip_info_t ip_info; + bool ip_changed; +} system_event_sta_got_ip_t; +#endif + +typedef struct { + uint8_t pin_code[8]; /**< PIN code of station in enrollee mode */ +} system_event_sta_wps_er_pin_t; + +#ifndef RIOT_VERSION +typedef struct { + tcpip_adapter_if_t if_index; + tcpip_adapter_ip6_info_t ip6_info; +} system_event_got_ip6_t; +#endif + +typedef struct { + uint8_t mac[6]; /**< MAC address of the station connected to ESP8266 soft-AP */ + uint8_t aid; /**< the aid that ESP8266 soft-AP gives to the station connected to */ +} system_event_ap_staconnected_t; + +typedef struct { + uint8_t mac[6]; /**< MAC address of the station disconnects to ESP8266 soft-AP */ + uint8_t aid; /**< the aid that ESP8266 soft-AP gave to the station disconnects to */ +} system_event_ap_stadisconnected_t; + +typedef struct { + int rssi; /**< Received probe request signal strength */ + uint8_t mac[6]; /**< MAC address of the station which send probe request */ +} system_event_ap_probe_req_rx_t; + +typedef union { + system_event_sta_connected_t connected; /**< ESP8266 station connected to AP */ + system_event_sta_disconnected_t disconnected; /**< ESP8266 station disconnected to AP */ + system_event_sta_scan_done_t scan_done; /**< ESP8266 station scan (APs) done */ + system_event_sta_authmode_change_t auth_change; /**< the auth mode of AP ESP8266 station connected to changed */ +#ifndef RIOT_VERSION + system_event_sta_got_ip_t got_ip; /**< ESP8266 station got IP, first time got IP or when IP is changed */ +#endif + system_event_sta_wps_er_pin_t sta_er_pin; /**< ESP8266 station WPS enrollee mode PIN code received */ + system_event_sta_wps_fail_reason_t sta_er_fail_reason;/**< ESP8266 station WPS enrollee mode failed reason code received */ + system_event_ap_staconnected_t sta_connected; /**< a station connected to ESP8266 soft-AP */ + system_event_ap_stadisconnected_t sta_disconnected; /**< a station disconnected to ESP8266 soft-AP */ + system_event_ap_probe_req_rx_t ap_probereqrecved; /**< ESP8266 soft-AP receive probe request packet */ +#ifndef RIOT_VERSION + system_event_got_ip6_t got_ip6; /**< ESP8266 station or ap or ethernet ipv6 addr state change to preferred */ +#endif +} system_event_info_t; + +typedef struct { + system_event_id_t event_id; /**< event ID */ + system_event_info_t event_info; /**< event information */ +} system_event_t; + +typedef esp_err_t (*system_event_handler_t)(system_event_t *event); + +/** + * @brief Send a event to event task + * + * @attention 1. Other task/modules, such as the TCPIP module, can call this API to send an event to event task + * + * @param system_event_t * event : event + * + * @return ESP_OK : succeed + * @return others : fail + */ +esp_err_t esp_event_send(system_event_t *event); + +/** + * @brief Default event handler for system events + * + * This function performs default handling of system events. + * When using esp_event_loop APIs, it is called automatically before invoking the user-provided + * callback function. + * + * Applications which implement a custom event loop must call this function + * as part of event processing. + * + * @param event pointer to event to be handled + * @return ESP_OK if an event was handled successfully + */ +esp_err_t esp_event_process_default(system_event_t *event); + +/** + * @brief Install default event handlers for Wi-Fi interfaces (station and AP) + * + */ +void esp_event_set_default_wifi_handlers(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_EVENT_H__ */ diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/include/esp_event_loop.h b/cpu/esp8266/vendor/esp-idf/esp8266/include/esp_event_loop.h new file mode 100644 index 000000000000..0e582b90ad21 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/include/esp_event_loop.h @@ -0,0 +1,83 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __ESP_EVENT_LOOP_H__ +#define __ESP_EVENT_LOOP_H__ + +#include +#include + +#include "esp_err.h" +#include "esp_event.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" + +#define EVENT_LOOP_STACKSIZE CONFIG_EVENT_LOOP_STACK_SIZE + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Application specified event callback function + * + * @param void *ctx : reserved for user + * @param system_event_t *event : event type defined in this file + * + * @return ESP_OK : succeed + * @return others : fail + */ +typedef esp_err_t (*system_event_cb_t)(void *ctx, system_event_t *event); + +/** + * @brief Initialize event loop + * Create the event handler and task + * + * @param system_event_cb_t cb : application specified event callback, it can be modified by call esp_event_set_cb + * @param void *ctx : reserved for user + * + * @return ESP_OK : succeed + * @return others : fail + */ +esp_err_t esp_event_loop_init(system_event_cb_t cb, void *ctx); + +/** + * @brief Set application specified event callback function + * + * @attention 1. If cb is NULL, means application don't need to handle + * If cb is not NULL, it will be call when an event is received, after the default event callback is completed + * + * @param system_event_cb_t cb : callback + * @param void *ctx : reserved for user + * + * @return system_event_cb_t : old callback + */ +system_event_cb_t esp_event_loop_set_cb(system_event_cb_t cb, void *ctx); + +/** + * @brief Get the queue used by event loop + * + * @attention : currently this API is used to initialize "q" parameter + * of wifi_init structure. + * + * @return QueueHandle_t : event queue handle + */ +QueueHandle_t esp_event_loop_get_queue(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_EVENT_LOOP_H__ */ diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/include/esp_phy_init.h b/cpu/esp8266/vendor/esp-idf/esp8266/include/esp_phy_init.h new file mode 100644 index 000000000000..9d94af88c909 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/include/esp_phy_init.h @@ -0,0 +1,171 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include + +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file PHY init parameters and API + */ + + +/** + * @brief Structure holding PHY init parameters + */ +typedef struct { + uint8_t params[128]; /*!< opaque PHY initialization parameters */ +} esp_phy_init_data_t; + +/** + * @brief Opaque PHY calibration data + */ +typedef struct { + uint8_t rf_cal_data[128]; /*!< calibration data */ + uint32_t rx_gain_dc_table[125]; +} esp_phy_calibration_data_t; + +typedef enum { + PHY_RF_CAL_PARTIAL = 0x00000000, /*!< Do part of RF calibration. This should be used after power-on reset. */ + PHY_RF_CAL_NONE = 0x00000001, /*!< Don't do any RF calibration. This mode is only suggested to be used after deep sleep reset. */ + PHY_RF_CAL_FULL = 0x00000002 /*!< Do full RF calibration. Produces best results, but also consumes a lot of time and current. Suggested to be used once. */ +} esp_phy_calibration_mode_t; + + +/** + * @brief Modules for modem sleep + */ +typedef enum { + MODEM_WIFI_STATION_MODULE, //!< Wi-Fi Station used + MODEM_WIFI_SOFTAP_MODULE, //!< Wi-Fi SoftAP used + MODEM_WIFI_SNIFFER_MODULE, //!< Wi-Fi Sniffer used + MODEM_USER_MODULE, //!< User used + MODEM_MODULE_COUNT //!< Number of items +} modem_sleep_module_t; + +/** + * @brief Module WIFI mask for medem sleep + */ +#define MODEM_WIFI_MASK ((1< | event | ----------> | application | + * | stack | | task | event | task | + * |-----------| |-------------| |-------------| + * /|\ | + * | | + * event | | + * | | + * | | + * --------------- | + * | | | + * | WiFi Driver |/__________________| + * | |\ API call + * | | + * |-------------| + * + * The WiFi driver can be consider as black box, it knows nothing about the high layer code, such as + * TCPIP stack, application task, event task etc, all it can do is to receive API call from high layer + * or post event queue to a specified Queue, which is initialized by API esp_wifi_init(). + * + * The event task is a daemon task, which receives events from WiFi driver or from other subsystem, such + * as TCPIP stack, event task will call the default callback function on receiving the event. For example, + * on receiving event SYSTEM_EVENT_STA_CONNECTED, it will call tcpip_adapter_start() to start the DHCP + * client in it's default handler. + * + * Application can register it's own event callback function by API esp_event_init, then the application callback + * function will be called after the default callback. Also, if application doesn't want to execute the callback + * in the event task, what it needs to do is to post the related event to application task in the application callback function. + * + * The application task (code) generally mixes all these thing together, it calls APIs to init the system/WiFi and + * handle the events when necessary. + * + */ + +#ifndef __ESP_WIFI_H__ +#define __ESP_WIFI_H__ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "sdkconfig.h" +#include "esp_err.h" +#include "esp_wifi_types.h" +#include "esp_event.h" +#include "esp_wifi_os_adapter.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_ERR_WIFI_NOT_INIT (ESP_ERR_WIFI_BASE + 1) /*!< WiFi driver was not installed by esp_wifi_init */ +#define ESP_ERR_WIFI_NOT_STARTED (ESP_ERR_WIFI_BASE + 2) /*!< WiFi driver was not started by esp_wifi_start */ +#define ESP_ERR_WIFI_NOT_STOPPED (ESP_ERR_WIFI_BASE + 3) /*!< WiFi driver was not stopped by esp_wifi_stop */ +#define ESP_ERR_WIFI_IF (ESP_ERR_WIFI_BASE + 4) /*!< WiFi interface error */ +#define ESP_ERR_WIFI_MODE (ESP_ERR_WIFI_BASE + 5) /*!< WiFi mode error */ +#define ESP_ERR_WIFI_STATE (ESP_ERR_WIFI_BASE + 6) /*!< WiFi internal state error */ +#define ESP_ERR_WIFI_CONN (ESP_ERR_WIFI_BASE + 7) /*!< WiFi internal control block of station or soft-AP error */ +#define ESP_ERR_WIFI_NVS (ESP_ERR_WIFI_BASE + 8) /*!< WiFi internal NVS module error */ +#define ESP_ERR_WIFI_MAC (ESP_ERR_WIFI_BASE + 9) /*!< MAC address is invalid */ +#define ESP_ERR_WIFI_SSID (ESP_ERR_WIFI_BASE + 10) /*!< SSID is invalid */ +#define ESP_ERR_WIFI_PASSWORD (ESP_ERR_WIFI_BASE + 11) /*!< Password is invalid */ +#define ESP_ERR_WIFI_TIMEOUT (ESP_ERR_WIFI_BASE + 12) /*!< Timeout error */ +#define ESP_ERR_WIFI_WAKE_FAIL (ESP_ERR_WIFI_BASE + 13) /*!< WiFi is in sleep state(RF closed) and wakeup fail */ +#define ESP_ERR_WIFI_WOULD_BLOCK (ESP_ERR_WIFI_BASE + 14) /*!< The caller would block */ +#define ESP_ERR_WIFI_NOT_CONNECT (ESP_ERR_WIFI_BASE + 15) /*!< Station still in disconnect status */ + +#define ESP_WIFI_PARAM_USE_NVS 0 + +/** + * @brief WiFi stack configuration parameters passed to esp_wifi_init call. + */ +typedef struct { + system_event_handler_t event_handler; /**< WiFi event handler */ + wifi_osi_funcs_t* osi_funcs; /**< WiFi OS functions */ + int static_rx_buf_num; /**< WiFi static RX buffer number */ + int dynamic_rx_buf_num; /**< WiFi dynamic RX buffer number */ + int tx_buf_type; /**< WiFi TX buffer type */ + int static_tx_buf_num; /**< WiFi static TX buffer number */ + int dynamic_tx_buf_num; /**< WiFi dynamic TX buffer number */ + int csi_enable; /**< WiFi channel state information enable flag */ + int ampdu_rx_enable; /**< WiFi AMPDU RX feature enable flag */ + int ampdu_tx_enable; /**< WiFi AMPDU TX feature enable flag */ + int nvs_enable; /**< WiFi NVS flash enable flag */ + int nano_enable; /**< Nano option for printf/scan family enable flag */ + int tx_ba_win; /**< WiFi Block Ack TX window size */ + int rx_ba_win; /**< WiFi Block Ack RX window size */ + int magic; /**< WiFi init magic number, it should be the last field */ +} wifi_init_config_t; + +#define WIFI_INIT_CONFIG_MAGIC 0x1F2F3F4F + +extern wifi_osi_funcs_t s_wifi_osi_funcs; +#define WIFI_INIT_CONFIG_DEFAULT() { \ + .event_handler = &esp_event_send, \ + .osi_funcs = &s_wifi_osi_funcs, \ + .static_rx_buf_num = 5,\ + .dynamic_rx_buf_num = 0,\ + .tx_buf_type = 0,\ + .static_tx_buf_num = 6,\ + .dynamic_tx_buf_num = 0,\ + .csi_enable = 0,\ + .ampdu_rx_enable = 0,\ + .ampdu_tx_enable = 0,\ + .nvs_enable = 1,\ + .nano_enable = 0,\ + .tx_ba_win = 0,\ + .rx_ba_win = 0,\ + .magic = WIFI_INIT_CONFIG_MAGIC\ +}; + +/** + * @brief Init WiFi + * Alloc resource for WiFi driver, such as WiFi control structure, RX/TX buffer, + * WiFi NVS structure etc, this WiFi also start WiFi task + * + * @attention 1. This API must be called before all other WiFi API can be called + * @attention 2. Always use WIFI_INIT_CONFIG_DEFAULT macro to init the config to default values, this can + * guarantee all the fields got correct value when more fields are added into wifi_init_config_t + * in future release. If you want to set your owner initial values, overwrite the default values + * which are set by WIFI_INIT_CONFIG_DEFAULT, please be notified that the field 'magic' of + * wifi_init_config_t should always be WIFI_INIT_CONFIG_MAGIC! + * + * @param config pointer to WiFi init configuration structure; can point to a temporary variable. + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_NO_MEM: out of memory + * - others: refer to error code esp_err.h + */ +esp_err_t esp_wifi_init(const wifi_init_config_t *config); + +/** + * @brief Deinit WiFi + * Free all resource allocated in esp_wifi_init and stop WiFi task + * + * @attention 1. This API should be called if you want to remove WiFi driver from the system + * + * @return ESP_OK: succeed + */ +esp_err_t esp_wifi_deinit(void); + +/** + * @brief Set the WiFi operating mode + * + * Set the WiFi operating mode as station, soft-AP or station+soft-AP, + * The default mode is soft-AP mode. + * + * @param mode WiFi operating mode + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_INVALID_ARG: invalid argument + * - others: refer to error code in esp_err.h + */ +esp_err_t esp_wifi_set_mode(wifi_mode_t mode); + +/** + * @brief Get current operating mode of WiFi + * + * @param[out] mode store current WiFi mode + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_INVALID_ARG: invalid argument + */ +esp_err_t esp_wifi_get_mode(wifi_mode_t *mode); + +/** + * @brief Start WiFi according to current configuration + * If mode is WIFI_MODE_STA, it create station control block and start station + * If mode is WIFI_MODE_AP, it create soft-AP control block and start soft-AP + * If mode is WIFI_MODE_APSTA, it create soft-AP and station control block and start soft-AP and station + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_INVALID_ARG: invalid argument + * - ESP_ERR_NO_MEM: out of memory + * - ESP_ERR_WIFI_CONN: WiFi internal error, station or soft-AP control block wrong + * - ESP_FAIL: other WiFi internal errors + */ +esp_err_t esp_wifi_start(void); + +/** + * @brief Stop WiFi + * If mode is WIFI_MODE_STA, it stop station and free station control block + * If mode is WIFI_MODE_AP, it stop soft-AP and free soft-AP control block + * If mode is WIFI_MODE_APSTA, it stop station/soft-AP and free station/soft-AP control block + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + */ +esp_err_t esp_wifi_stop(void); + +/** + * @brief Restore WiFi stack persistent settings to default values + * + * This function will reset settings made using the following APIs: + * - esp_wifi_get_auto_connect, + * - esp_wifi_set_protocol, + * - esp_wifi_set_config related + * - esp_wifi_set_mode + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + */ +esp_err_t esp_wifi_restore(void); + +/** + * @brief Connect the ESP8266 WiFi station to the AP. + * + * @attention 1. This API only impact WIFI_MODE_STA or WIFI_MODE_APSTA mode + * @attention 2. If the ESP8266 is connected to an AP, call esp_wifi_disconnect to disconnect. + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start + * - ESP_ERR_WIFI_CONN: WiFi internal error, station or soft-AP control block wrong + * - ESP_ERR_WIFI_SSID: SSID of AP which station connects is invalid + */ +esp_err_t esp_wifi_connect(void); + +/** + * @brief Disconnect the ESP8266 WiFi station from the AP. + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi was not initialized by esp_wifi_init + * - ESP_ERR_WIFI_NOT_STARTED: WiFi was not started by esp_wifi_start + * - ESP_FAIL: other WiFi internal errors + */ +esp_err_t esp_wifi_disconnect(void); + +/** + * @brief Currently this API is just an stub API + * + + * @return + * - ESP_OK: succeed + * - others: fail + */ +esp_err_t esp_wifi_clear_fast_connect(void); + +/** + * @brief deauthenticate all stations or associated id equals to aid + * + * @param aid when aid is 0, deauthenticate all stations, otherwise deauthenticate station whose associated id is aid + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_NOT_STARTED: WiFi was not started by esp_wifi_start + * - ESP_ERR_INVALID_ARG: invalid argument + * - ESP_ERR_WIFI_MODE: WiFi mode is wrong + */ +esp_err_t esp_wifi_deauth_sta(uint16_t aid); + +/** + * @brief Scan all available APs. + * + * @attention If this API is called, the found APs are stored in WiFi driver dynamic allocated memory and the + * will be freed in esp_wifi_scan_get_ap_records, so generally, call esp_wifi_scan_get_ap_records to cause + * the memory to be freed once the scan is done + * @attention The values of maximum active scan time and passive scan time per channel are limited to 1500 milliseconds. + * Values above 1500ms may cause station to disconnect from AP and are not recommended. + * + * @param config configuration of scanning + * @param block if block is true, this API will block the caller until the scan is done, otherwise + * it will return immediately + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_NOT_STARTED: WiFi was not started by esp_wifi_start + * - ESP_ERR_WIFI_TIMEOUT: blocking scan is timeout + * - others: refer to error code in esp_err.h + */ +esp_err_t esp_wifi_scan_start(const wifi_scan_config_t *config, bool block); + +/** + * @brief Stop the scan in process + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_NOT_STARTED: WiFi is not started by esp_wifi_start + */ +esp_err_t esp_wifi_scan_stop(void); + +/** + * @brief Get number of APs found in last scan + * + * @param[out] number store number of APIs found in last scan + * + * @attention This API can only be called when the scan is completed, otherwise it may get wrong value. + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_NOT_STARTED: WiFi is not started by esp_wifi_start + * - ESP_ERR_INVALID_ARG: invalid argument + */ +esp_err_t esp_wifi_scan_get_ap_num(uint16_t *number); + +/** + * @brief Get AP list found in last scan + * + * @param[inout] number As input param, it stores max AP number ap_records can hold. + * As output param, it receives the actual AP number this API returns. + * @param ap_records wifi_ap_record_t array to hold the found APs + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_NOT_STARTED: WiFi is not started by esp_wifi_start + * - ESP_ERR_INVALID_ARG: invalid argument + * - ESP_ERR_NO_MEM: out of memory + */ +esp_err_t esp_wifi_scan_get_ap_records(uint16_t *number, wifi_ap_record_t *ap_records); + + +/** + * @brief Get information of AP which the ESP8266 station is associated with + * + * @param ap_info the wifi_ap_record_t to hold AP information + * sta can get the connected ap's phy mode info through the struct member + * phy_11b,phy_11g,phy_11n,phy_lr in the wifi_ap_record_t struct. + * For example, phy_11b = 1 imply that ap support 802.11b mode + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_CONN: The station interface don't initialized + * - ESP_ERR_WIFI_NOT_CONNECT: The station is in disconnect status + */ +esp_err_t esp_wifi_sta_get_ap_info(wifi_ap_record_t *ap_info); + +/** + * @brief Set current power save type + * + * @attention Default power save type is WIFI_PS_NONE. + * + * @param type power save type + * + * @return ESP_ERR_NOT_SUPPORTED: not supported yet + */ +esp_err_t esp_wifi_set_ps(wifi_ps_type_t type); + +/** + * @brief Get current power save type + * + * @attention Default power save type is WIFI_PS_NONE. + * + * @param[out] type: store current power save type + * + * @return ESP_ERR_NOT_SUPPORTED: not supported yet + */ +esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type); + +/** + * @brief Set protocol type of specified interface + * The default protocol is (WIFI_PROTOCOL_11B|WIFI_PROTOCOL_11G|WIFI_PROTOCOL_11N) + * + * @attention Currently we only support 802.11b or 802.11bg or 802.11bgn mode + * + * @param ifx interfaces + * @param protocol_bitmap WiFi protocol bitmap + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_IF: invalid interface + * - others: refer to error codes in esp_err.h + */ +esp_err_t esp_wifi_set_protocol(wifi_interface_t ifx, uint8_t protocol_bitmap); + +/** + * @brief Get the current protocol bitmap of the specified interface + * + * @param ifx interface + * @param[out] protocol_bitmap store current WiFi protocol bitmap of interface ifx + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_IF: invalid interface + * - ESP_ERR_INVALID_ARG: invalid argument + * - others: refer to error codes in esp_err.h + */ +esp_err_t esp_wifi_get_protocol(wifi_interface_t ifx, uint8_t *protocol_bitmap); + +/** + * @brief Set the bandwidth of ESP8266 specified interface + * + * @attention 1. API return false if try to configure an interface that is not enabled + * @attention 2. WIFI_BW_HT40 is supported only when the interface support 11N + * + * @param ifx interface to be configured + * @param bw bandwidth + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_IF: invalid interface + * - ESP_ERR_INVALID_ARG: invalid argument + * - others: refer to error codes in esp_err.h + */ +esp_err_t esp_wifi_set_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t bw); + +/** + * @brief Get the bandwidth of ESP8266 specified interface + * + * @attention 1. API return false if try to get a interface that is not enable + * + * @param ifx interface to be configured + * @param[out] bw store bandwidth of interface ifx + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_IF: invalid interface + * - ESP_ERR_INVALID_ARG: invalid argument + */ +esp_err_t esp_wifi_get_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t *bw); + +/** + * @brief Set primary/secondary channel of ESP8266 + * + * @attention 1. This is a special API for sniffer + * @attention 2. This API should be called after esp_wifi_start() or esp_wifi_set_promiscuous() + * + * @param primary for HT20, primary is the channel number, for HT40, primary is the primary channel + * @param second for HT20, second is ignored, for HT40, second is the second channel + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_IF: invalid interface + * - ESP_ERR_INVALID_ARG: invalid argument + */ +esp_err_t esp_wifi_set_channel(uint8_t primary, wifi_second_chan_t second); + +/** + * @brief Get the primary/secondary channel of ESP8266 + * + * @attention 1. API return false if try to get a interface that is not enable + * + * @param primary store current primary channel + * @param[out] second store current second channel + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_INVALID_ARG: invalid argument + */ +esp_err_t esp_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second); + +/** + * @brief configure country info + * + * @attention 1. The default country is {.cc="CN", .schan=1, .nchan=13, policy=WIFI_COUNTRY_POLICY_AUTO} + * @attention 2. When the country policy is WIFI_COUNTRY_POLICY_AUTO, the country info of the AP to which + * the station is connected is used. E.g. if the configured country info is {.cc="USA", .schan=1, .nchan=11} + * and the country info of the AP to which the station is connected is {.cc="JP", .schan=1, .nchan=14} + * then the country info that will be used is {.cc="JP", .schan=1, .nchan=14}. If the station disconnected + * from the AP the country info is set back back to the country info of the station automatically, + * {.cc="USA", .schan=1, .nchan=11} in the example. + * @attention 3. When the country policy is WIFI_COUNTRY_POLICY_MANUAL, always use the configured country info. + * @attention 4. When the country info is changed because of configuration or because the station connects to a different + * external AP, the country IE in probe response/beacon of the soft-AP is changed also. + * @attention 5. The country configuration is not stored into flash + * @attention 6. This API doesn't validate the per-country rules, it's up to the user to fill in all fields according to + * local regulations. + * + * @param country the configured country info + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_INVALID_ARG: invalid argument + */ +esp_err_t esp_wifi_set_country(const wifi_country_t *country); + +/** + * @brief get the current country info + * + * @param country country info + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_INVALID_ARG: invalid argument + */ +esp_err_t esp_wifi_get_country(wifi_country_t *country); + + +/** + * @brief Set MAC address of the ESP8266 WiFi station or the soft-AP interface. + * + * @attention 1. This API can only be called when the interface is disabled + * @attention 2. ESP8266 soft-AP and station have different MAC addresses, do not set them to be the same. + * @attention 3. The bit 0 of the first byte of ESP8266 MAC address can not be 1. For example, the MAC address + * can set to be "1a:XX:XX:XX:XX:XX", but can not be "15:XX:XX:XX:XX:XX". + * + * @param ifx interface + * @param mac the MAC address + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_INVALID_ARG: invalid argument + * - ESP_ERR_WIFI_IF: invalid interface + * - ESP_ERR_WIFI_MAC: invalid mac address + * - ESP_ERR_WIFI_MODE: WiFi mode is wrong + * - others: refer to error codes in esp_err.h + */ +esp_err_t esp_wifi_set_mac(wifi_interface_t ifx, const uint8_t mac[6]); + +/** + * @brief Get mac of specified interface + * + * @param ifx interface + * @param[out] mac store mac of the interface ifx + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_INVALID_ARG: invalid argument + * - ESP_ERR_WIFI_IF: invalid interface + */ +esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6]); + +/** + * @brief The RX callback function in the promiscuous mode. + * Each time a packet is received, the callback function will be called. + * + * @param buf Data received. Type of data in buffer (wifi_promiscuous_pkt_t or wifi_pkt_rx_ctrl_t) indicated by 'type' parameter. + * @param type promiscuous packet type. + * + */ +typedef void (* wifi_promiscuous_cb_t)(void *buf, wifi_promiscuous_pkt_type_t type); +/** + * @brief Register the RX callback function in the promiscuous mode. + * + * Each time a packet is received, the registered callback function will be called. + * + * @param cb callback + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + */ +esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb); + +/** + * @brief Enable the promiscuous mode. + * + * @param en false - disable, true - enable + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + */ +esp_err_t esp_wifi_set_promiscuous(bool en); + +/** + * @brief Get the promiscuous mode. + * + * @param[out] en store the current status of promiscuous mode + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_INVALID_ARG: invalid argument + */ +esp_err_t esp_wifi_get_promiscuous(bool *en); + +/** + * @brief Enable the promiscuous mode packet type filter. + * + * @note The default filter is to filter all packets except WIFI_PKT_MISC + * + * @param filter the packet type filtered in promiscuous mode. + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + */ +esp_err_t esp_wifi_set_promiscuous_filter(const wifi_promiscuous_filter_t *filter); + +/** + * @brief Get the promiscuous filter. + * + * @param[out] filter store the current status of promiscuous filter + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_INVALID_ARG: invalid argument + */ +esp_err_t esp_wifi_get_promiscuous_filter(wifi_promiscuous_filter_t *filter); + +/** + * @brief Set the configuration of the ESP8266 STA or AP + * + * @attention 1. This API can be called only when specified interface is enabled, otherwise, API fail + * @attention 2. For station configuration, bssid_set needs to be 0; and it needs to be 1 only when users need to check the MAC address of the AP. + * @attention 3. ESP8266 is limited to only one channel, so when in the soft-AP+station mode, the soft-AP will adjust its channel automatically to be the same as + * the channel of the ESP8266 station. + * + * @param interface interface + * @param conf station or soft-AP configuration + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_INVALID_ARG: invalid argument + * - ESP_ERR_WIFI_IF: invalid interface + * - ESP_ERR_WIFI_MODE: invalid mode + * - ESP_ERR_WIFI_PASSWORD: invalid password + * - ESP_ERR_WIFI_NVS: WiFi internal NVS error + * - others: refer to the erro code in esp_err.h + */ +esp_err_t esp_wifi_set_config(wifi_interface_t interface, wifi_config_t *conf); + +/** + * @brief Get configuration of specified interface + * + * @param interface interface + * @param[out] conf station or soft-AP configuration + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_INVALID_ARG: invalid argument + * - ESP_ERR_WIFI_IF: invalid interface + */ +esp_err_t esp_wifi_get_config(wifi_interface_t interface, wifi_config_t *conf); + +/** + * @brief Get STAs associated with soft-AP + * + * @attention SSC only API + * + * @param[out] sta station list + * ap can get the connected sta's phy mode info through the struct member + * phy_11b,phy_11g,phy_11n,phy_lr in the wifi_sta_info_t struct. + * For example, phy_11b = 1 imply that sta support 802.11b mode + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_INVALID_ARG: invalid argument + * - ESP_ERR_WIFI_MODE: WiFi mode is wrong + * - ESP_ERR_WIFI_CONN: WiFi internal error, the station/soft-AP control block is invalid + */ +esp_err_t esp_wifi_ap_get_sta_list(wifi_sta_list_t *sta); + + +/** + * @brief Set the WiFi API configuration storage type + * + * @attention 1. The default value is WIFI_STORAGE_FLASH + * + * @param storage : storage type + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_INVALID_ARG: invalid argument + */ +esp_err_t esp_wifi_set_storage(wifi_storage_t storage); + +/** + * @brief Set auto connect + * The default value is true + * + * @param en : true - enable auto connect / false - disable auto connect + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_MODE: WiFi internal error, the station/soft-AP control block is invalid + * - others: refer to error code in esp_err.h + */ +esp_err_t esp_wifi_set_auto_connect(bool en) __attribute__ ((deprecated)); + +/** + * @brief Get the auto connect flag + * + * @param[out] en store current auto connect configuration + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_INVALID_ARG: invalid argument + */ +esp_err_t esp_wifi_get_auto_connect(bool *en) __attribute__ ((deprecated)); + +/** + * @brief Set 802.11 Vendor-Specific Information Element + * + * @param enable If true, specified IE is enabled. If false, specified IE is removed. + * @param type Information Element type. Determines the frame type to associate with the IE. + * @param idx Index to set or clear. Each IE type can be associated with up to two elements (indices 0 & 1). + * @param vnd_ie Pointer to vendor specific element data. First 6 bytes should be a header with fields matching vendor_ie_data_t. + * If enable is false, this argument is ignored and can be NULL. Data does not need to remain valid after the function returns. + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init() + * - ESP_ERR_INVALID_ARG: Invalid argument, including if first byte of vnd_ie is not WIFI_VENDOR_IE_ELEMENT_ID (0xDD) + * or second byte is an invalid length. + * - ESP_ERR_NO_MEM: Out of memory + */ +esp_err_t esp_wifi_set_vendor_ie(bool enable, wifi_vendor_ie_type_t type, wifi_vendor_ie_id_t idx, const void *vnd_ie); + +/** + * @brief Function signature for received Vendor-Specific Information Element callback. + * @param ctx Context argument, as passed to esp_wifi_set_vendor_ie_cb() when registering callback. + * @param type Information element type, based on frame type received. + * @param sa Source 802.11 address. + * @param vnd_ie Pointer to the vendor specific element data received. + * @param rssi Received signal strength indication. + */ +typedef void (*esp_vendor_ie_cb_t) (void *ctx, wifi_vendor_ie_type_t type, const uint8_t sa[6], const vendor_ie_data_t *vnd_ie, int rssi); + +/** + * @brief Register Vendor-Specific Information Element monitoring callback. + * + * @param cb Callback function + * @param ctx Context argument, passed to callback function. + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + */ +esp_err_t esp_wifi_set_vendor_ie_cb(esp_vendor_ie_cb_t cb, void *ctx); + +/** + * @brief Set maximum WiFi transmiting power + * + * @attention WiFi transmiting power is divided to six levels in phy init data. + * Level0 represents highest transmiting power and level5 represents lowest + * transmiting power. Packets of different rates are transmitted in + * different powers according to the configuration in phy init data. + * This API only sets maximum WiFi transmiting power. If this API is called, + * the transmiting power of every packet will be less than or equal to the + * value set by this API. If this API is not called, the value of maximum + * transmitting power set in phy_init_data.bin or menuconfig (depend on + * whether to use phy init data in partition or not) will be used. Default + * value is level0. Values passed in power are mapped to transmit power + * levels as follows: + * - [78, 127]: level0 + * - [76, 77]: level1 + * - [74, 75]: level2 + * - [68, 73]: level3 + * - [60, 67]: level4 + * - [52, 59]: level5 + * - [44, 51]: level5 - 2dBm + * - [34, 43]: level5 - 4.5dBm + * - [28, 33]: level5 - 6dBm + * - [20, 27]: level5 - 8dBm + * - [8, 19]: level5 - 11dBm + * - [-128, 7]: level5 - 14dBm + * + * @param power Maximum WiFi transmiting power. + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start + */ +esp_err_t esp_wifi_set_max_tx_power(int8_t power); + +/** + * @brief Get maximum WiFi transmiting power + * + * @attention This API gets maximum WiFi transmiting power. Values got + * from power are mapped to transmit power levels as follows: + * - 78: 19.5dBm + * - 76: 19dBm + * - 74: 18.5dBm + * - 68: 17dBm + * - 60: 15dBm + * - 52: 13dBm + * - 44: 11dBm + * - 34: 8.5dBm + * - 28: 7dBm + * - 20: 5dBm + * - 8: 2dBm + * - -4: -1dBm + * + * @param power Maximum WiFi transmiting power. + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start + * - ESP_ERR_INVALID_ARG: invalid argument + */ +esp_err_t esp_wifi_get_max_tx_power(int8_t *power); + +/** + * @brief Set mask to enable or disable some WiFi events + * + * @attention 1. Mask can be created by logical OR of various WIFI_EVENT_MASK_ constants. + * Events which have corresponding bit set in the mask will not be delivered to the system event handler. + * @attention 2. Default WiFi event mask is WIFI_EVENT_MASK_AP_PROBEREQRECVED. + * @attention 3. There may be lots of stations sending probe request data around. + * Don't unmask this event unless you need to receive probe request data. + * + * @param mask WiFi event mask. + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + */ +esp_err_t esp_wifi_set_event_mask(uint32_t mask); + +/** + * @brief Get mask of WiFi events + * + * @param mask WiFi event mask. + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_ARG: invalid argument + */ +esp_err_t esp_wifi_get_event_mask(uint32_t *mask); + +/** + * @brief Send user-define 802.11 packets. + * + * @attention 1. Packet has to be the whole 802.11 packet, does not include the FCS. + * The length of the packet has to be longer than the minimum length + * of the header of 802.11 packet which is 24 bytes, and less than 1400 bytes. + * @attention 2. Duration area is invalid for user, it will be filled in SDK. + * @attention 3. The rate of sending packet is same as the management packet which + * is the same as the system rate of sending packets. + * @attention 4. Only after the previous packet was sent, entered the sent callback, + * the next packet is allowed to send. Otherwise, wifi_send_pkt_freedom + * will return fail. + * + * @param uint8 *buf : pointer of packet + * @param uint16 len : packet length + * @param bool sys_seq : follow the system's 802.11 packets sequence number or not, + * if it is true, the sequence number will be increased 1 every + * time a packet sent. + * + * @return ESP_OK, succeed; + * @return ESP_FAIL, fail. + */ +esp_err_t esp_wifi_send_pkt_freedom(uint8_t *buf, int32_t len, bool sys_seq); + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_WIFI_H__ */ diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/source/Makefile b/cpu/esp8266/vendor/esp-idf/esp8266/source/Makefile new file mode 100644 index 000000000000..474ca6e6d134 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/source/Makefile @@ -0,0 +1,6 @@ +MODULE=esp_idf_esp8266 + +include $(RIOTBASE)/Makefile.base + +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/esp8266/source +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/util/include diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/source/chip_boot.c b/cpu/esp8266/vendor/esp-idf/esp8266/source/chip_boot.c new file mode 100644 index 000000000000..9ced762007d0 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/source/chip_boot.c @@ -0,0 +1,29 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "sdkconfig.h" + +#ifndef CONFIG_BOOTLOADER_INIT_SPI_FLASH +#include "spi_flash.h" + +/* + * @brief initialize the chip + */ +void chip_boot(void) +{ + extern void esp_spi_flash_init(uint32_t spi_speed, uint32_t spi_mode); + + esp_spi_flash_init(CONFIG_SPI_FLASH_FREQ, CONFIG_SPI_FLASH_MODE); +} +#endif /* CONFIG_BOOTLOADER_INIT_SPI_FLASH */ diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/source/esp_socket.c b/cpu/esp8266/vendor/esp-idf/esp8266/source/esp_socket.c new file mode 100644 index 000000000000..74d2def569d5 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/source/esp_socket.c @@ -0,0 +1,333 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include "esp_socket.h" +#include "net/sockio.h" + +#define CRITICAL_DECLARE(t) +#define CRITICAL_ENTER(t) +#define CRITICAL_EXIT(t) + +#ifndef ESP_SOCKET_MAX +#define ESP_SOCKET_MAX 2 +#endif + +#define SET_ERR(err) errno = err + +#define CHECK_FD(s) \ + if (s >= ESP_SOCKET_MAX \ + || !s_socket[s].info) { \ + SET_ERR(EINVAL); \ + return -1; \ + } + +#define CHECK_METHOD(s, io) \ + CHECK_FD(s) \ + if (!s_socket[s].method \ + || !s_socket[s].method->io) { \ + SET_ERR(ESRCH); \ + return -1; \ + } + +#define SOCKET_IO_METHOD(s, io, ...) \ + s_socket[s].method->io(s_socket[s].index, ##__VA_ARGS__) + +/* + * socket event object + */ +typedef struct esp_socket_event { + esp_aio_cb_t cb; + void *arg; +} esp_socket_event_t; + +/* + * socket object + */ +typedef struct esp_socket { + esp_socket_info_t *info; + + /* + * lowlevel socket module index + */ + void *index; + + /* + * lowlevel socket module method + */ + const esp_socket_method_t *method; + + esp_socket_event_t event[ESP_SOCKET_MAX_EVENT]; +} esp_socket_t; + +static esp_socket_t s_socket[ESP_SOCKET_MAX]; + +static inline int event_is_used(int s, int e) +{ + return s_socket[s].event[e].cb != NULL; +} + +static inline int alloc_event(int s, int e) +{ + CRITICAL_DECLARE(t); + + if (e >= ESP_SOCKET_MAX_EVENT) + return -1; + + CRITICAL_ENTER(t); + if (event_is_used(s, e)) { + e = ESP_SOCKET_MAX_EVENT; + } + CRITICAL_EXIT(t); + + return e < ESP_SOCKET_MAX_EVENT ? e : -1; +} + +static inline void free_event(int s, int e) +{ + s_socket[s].event[e].cb = NULL; +} + +static inline int alloc_socket(void) +{ + int s; + CRITICAL_DECLARE(t); + + CRITICAL_ENTER(t); + for (s = 0; s < ESP_SOCKET_MAX; s++) { + if (s_socket[s].info == NULL) { + s_socket[s].info = (void *)1; + break; + } + } + CRITICAL_EXIT(t); + + return s < ESP_SOCKET_MAX ? s : -1; +} + +static inline void free_socket(int s) +{ + int e; + + s_socket[s].info = NULL; + for (e = 0; e < ESP_SOCKET_MAX_EVENT; e++) { + free_event(s, e); + } +} + +/* + * @brief create a socket file description + */ +int esp_socket(int domain, int type, int protocol) +{ + int s; + + s = alloc_socket(); + if (s < 0) { + SET_ERR(ENOMEM); + return -1; + } + + s_socket[s].info = malloc(sizeof(esp_socket_info_t)); + if (!s_socket[s].info) { + free_socket(s); + SET_ERR(ENOMEM); + return -1; + } + + s_socket[s].info->domain = domain; + s_socket[s].info->type = type; + s_socket[s].info->protocol = protocol; + + s_socket[s].index = NULL; + s_socket[s].method = NULL; + + return s; +} + +/* + * @brief send a block of data asynchronously and receive result by callback function + */ +int esp_aio_sendto(esp_aio_t *aio, const struct sockaddr_ll *to, socklen_t len) +{ + int s = aio->fd; + + CHECK_METHOD(s, aio_sendto); + + return SOCKET_IO_METHOD(s, aio_sendto, aio, to, len); +} + +/* + * @brief register a event and its callback function to target of file description + */ +int esp_aio_event(int fd, unsigned int event, esp_aio_cb_t cb, void *arg) +{ + int e; + int ret; + int s = fd; + + CHECK_METHOD(s, aio_event); + + e = alloc_event(s, event); + if (e < 0) { + SET_ERR(ENOMEM); + return -1; + } + + ret = SOCKET_IO_METHOD(s, aio_event, event, cb, arg); + if (ret) { + free_event(s, e); + return -1; + } + + s_socket[s].event[e].cb = cb; + s_socket[s].event[e].arg = arg; + + return 0; +} + +/* + * @brief lowlevel socket module upload event and its data + */ +int esp_upload_event(void *index, esp_socket_info_t *info, unsigned int event, esp_aio_data_t *aio_data) +{ + int ret; + int s; + + if (event >= ESP_SOCKET_MAX_EVENT) + return -EINVAL; + + for (s = 0; s < ESP_SOCKET_MAX; s++) { + if (s_socket[s].index == index && event_is_used(s, event)) { + esp_aio_t aio; + + aio.fd = s; + aio.cb = s_socket[s].event[event].cb; + aio.arg = s_socket[s].event[event].arg; + + aio.pbuf = aio_data->pbuf; + aio.len = aio_data->len; + aio.ret = aio_data->status; + + ret = s_socket[s].event[event].cb(&aio); + if (ret) + return ret; + } + } + + return 0; +} + +/* + * @brief free buffer taken from event callback + */ +int esp_free_pbuf(int fd, void *pbuf) +{ + int ret; + int s = fd; + + CHECK_METHOD(s, free_pbuf); + + ret = SOCKET_IO_METHOD(s, free_pbuf, pbuf); + if (ret) + return -1; + + return 0; +} + +/* + * @brief map real lowlevel socket object to virtual socket + */ +static int map_socket_ll(int fd, const char *name) +{ + int s = fd; + const esp_socket_method_t *p; + extern const esp_socket_method_t __start_ksymatabesp_socket, __stop_ksymatabesp_socket; + + for (p = &__start_ksymatabesp_socket; p != &__stop_ksymatabesp_socket; p++) { + if (!strcmp(name, p->name)) + break; + } + if (p >= &__stop_ksymatabesp_socket) { + SET_ERR(ENXIO); + return -1; + } + + s_socket[s].index = p->open(s_socket[s].info); + if (!s_socket[s].index) + return -1; + s_socket[s].method = p; + + return 0; +} + +/* + * @brief send requset command to target by file description and get the result synchronously + */ +int esp_ioctl(int fd, unsigned int cmd, ...) +{ + int ret; + va_list va; + int s = fd; + + va_start(va, cmd); + + switch(cmd) { +#if SIOCGIFINDEX != SIOGIFINDEX + case SIOGIFINDEX: +#endif + case SIOCGIFINDEX: { + const char *name; + + name = va_arg(va, const char *); + ret = map_socket_ll(fd, name); + break; + } + default: { + int *arg = ((int *)&cmd) + 1; + + CHECK_METHOD(s, ioctl); + ret = SOCKET_IO_METHOD(s, ioctl, cmd, arg); + break; + } + } + + va_end(va); + + return ret; +} + +/* + * @brief close target of file description + */ +int esp_close(int fd) +{ + int ret; + int s = fd; + + CHECK_METHOD(s, close); + + ret = SOCKET_IO_METHOD(s, close); + if (ret) + return -1; + + free(s_socket[s].info); + free_socket(s); + + return 0; +} diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/source/esp_wifi.c b/cpu/esp8266/vendor/esp-idf/esp8266/source/esp_wifi.c new file mode 100644 index 000000000000..8a38b71c16ab --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/source/esp_wifi.c @@ -0,0 +1,75 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "sdkconfig.h" +#include "esp_attr.h" +#include "esp_libc.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "internal/esp_wifi_internal.h" +#include "esp_socket.h" +#include "net/sockio.h" +#include "phy.h" + +const size_t _g_esp_wifi_ppt_task_stk_size = CONFIG_WIFI_PPT_TASKSTACK_SIZE; + +esp_err_t esp_wifi_init_internal(const wifi_init_config_t *config); + +/** + * @brief Init WiFi + * Alloc resource for WiFi driver, such as WiFi control structure, RX/TX buffer, + * WiFi NVS structure etc, this WiFi also start WiFi task + * + * @attention 1. This API must be called before all other WiFi API can be called + * @attention 2. Always use WIFI_INIT_CONFIG_DEFAULT macro to init the config to default values, this can + * guarantee all the fields got correct value when more fields are added into wifi_init_config_t + * in future release. If you want to set your owner initial values, overwrite the default values + * which are set by WIFI_INIT_CONFIG_DEFAULT, please be notified that the field 'magic' of + * wifi_init_config_t should always be WIFI_INIT_CONFIG_MAGIC! + * + * @param config pointer to WiFi init configuration structure; can point to a temporary variable. + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_NO_MEM: out of memory + * - others: refer to error code esp_err.h + */ +esp_err_t esp_wifi_init(const wifi_init_config_t *config) +{ + esp_event_set_default_wifi_handlers(); + return esp_wifi_init_internal(config); +} + +void esp_deep_sleep_set_rf_option(uint8_t option) +{ + phy_afterwake_set_rfoption(option); +} + +size_t __attribute__((weak)) esp_wifi_scan_get_ap_num_max(void) +{ + return CONFIG_SCAN_AP_MAX; +} + +bool IRAM_ATTR esp_wifi_try_rate_from_high(void) { +#if CONFIG_WIFI_TX_RATE_SEQUENCE_FROM_HIGH + int8_t rssi; + rssi = esp_wifi_get_ap_rssi(); + wifi_mode_t mode; + esp_wifi_get_mode( &mode ); + if (rssi < -26 && mode == WIFI_MODE_STA) { + return true; + } +#endif + return false; +} diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/source/esp_wifi_os_adapter.c b/cpu/esp8266/vendor/esp-idf/esp8266/source/esp_wifi_os_adapter.c new file mode 100644 index 000000000000..2d26313b2284 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/source/esp_wifi_os_adapter.c @@ -0,0 +1,473 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "esp_libc.h" +#include "esp_system.h" +#include "esp_attr.h" +#include "esp_wifi_os_adapter.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "freertos/timers.h" + +#ifdef RIOT_VERSION +#include "esp_log.h" +#include "freertos/portmacro.h" +#include "xtensa/xtensa_api.h" + +#endif + +#include "nvs.h" + +#if defined(CONFIG_NEWLIB_LIBRARY_LEVEL_NORMAL) || defined(CONFIG_NEWLIB_LIBRARY_LEVEL_NANO) +#include "esp_newlib.h" +#endif + +#ifdef RIOT_VERSION + +extern void vPortYield(void); +extern void vPortYieldFromInt(void); +#define portYIELD vPortYield +void thread_yield_higher(void); + +#endif /* RIOT_VERSION */ + +static void *task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio) +{ + portBASE_TYPE ret; + xTaskHandle handle; + ret = xTaskCreate(task_func, name, stack_depth, param, prio, &handle); + + return ret == pdPASS ? handle : NULL; +} + +static void task_delete_wrapper(void *task_handle) +{ + vTaskDelete(task_handle); +} + +static void task_yield_wrapper(void) +{ +#ifdef RIOT_VERSION + thread_yield_higher(); +#else + portYIELD(); +#endif +} + +static void task_yield_from_isr_wrapper(void) +{ +#ifdef RIOT_VERSION + thread_yield_higher(); +#else + portYIELD(); +#endif +} + +static void task_delay_wrapper(uint32_t tick) +{ + vTaskDelay(tick); +} + +static void* task_get_current_task_wrapper(void) +{ + return (void *)xTaskGetCurrentTaskHandle(); +} + +static uint32_t task_get_max_priority_wrapper(void) +{ + return (uint32_t)(configMAX_PRIORITIES-1); +} + +static uint32_t task_ms_to_tick_wrapper(uint32_t ms) +{ + return (uint32_t)(ms / portTICK_RATE_MS); +} + +static void task_suspend_all_wrapper(void) +{ +#ifndef RIOT_VERSION + /* there is no equivalent in RIOT */ + vTaskSuspendAll(); +#endif +} + +static void task_resume_all_wrapper(void) +{ +#ifndef RIOT_VERSION + /* there is no equivalent in RIOT */ + xTaskResumeAll(); +#endif +} + +static void os_init_wrapper(void) +{ +#ifdef RIOT_VERSION + extern void esp_riot_init(void); + esp_riot_init(); +#else +#if defined(CONFIG_NEWLIB_LIBRARY_LEVEL_NORMAL) || defined(CONFIG_NEWLIB_LIBRARY_LEVEL_NANO) + esp_newlib_init(); +#endif +#endif +} + +static void os_start_wrapper(void) +{ +#ifdef RIOT_VERSION + extern void esp_riot_start(void); + esp_riot_start(); +#else + vTaskStartScheduler(); +#endif +} + +static void *semphr_create_wrapper(uint32_t max, uint32_t init) +{ + return (void *)xSemaphoreCreateCounting(max, init); +} + +static void semphr_delete_wrapper(void *semphr) +{ + vSemaphoreDelete(semphr); +} + +static bool semphr_take_from_isr_wrapper(void *semphr, int *hptw) +{ + signed portBASE_TYPE ret; + + ret = xSemaphoreTakeFromISR(semphr, (signed portBASE_TYPE *)hptw); + + return ret == pdPASS ? true : false; +} + +static bool semphr_give_from_isr_wrapper(void *semphr, int *hptw) +{ + signed portBASE_TYPE ret; + + ret = xSemaphoreGiveFromISR(semphr, (signed portBASE_TYPE *)hptw); + + return ret == pdPASS ? true : false; +} + +static bool semphr_take_wrapper(void *semphr, uint32_t block_time_tick) +{ + signed portBASE_TYPE ret; + + if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) { + ret = xSemaphoreTake(semphr, portMAX_DELAY); + } else { + ret = xSemaphoreTake(semphr, block_time_tick); + } + + return ret == pdPASS ? true : false; +} + +static bool semphr_give_wrapper(void *semphr) +{ + signed portBASE_TYPE ret; + + ret = xSemaphoreGive(semphr); + + return ret == pdPASS ? true : false; +} + +static void *mutex_create_wrapper(void) +{ + return (void *)xSemaphoreCreateRecursiveMutex(); +} + +static void mutex_delete_wrapper(void *mutex) +{ + vSemaphoreDelete(mutex); +} + +static bool mutex_lock_wrapper(void *mutex) +{ + signed portBASE_TYPE ret; + + ret = xSemaphoreTakeRecursive(mutex, portMAX_DELAY); + + return ret == pdPASS ? true : false; +} + +static bool mutex_unlock_wrapper(void *mutex) +{ + signed portBASE_TYPE ret; + + ret = xSemaphoreGiveRecursive(mutex); + + return ret == pdPASS ? true : false; +} + +static void *queue_create_wrapper(uint32_t queue_len, uint32_t item_size) +{ + return (void *)xQueueCreate(queue_len, item_size); +} + +static void queue_delete_wrapper(void *queue) +{ + vQueueDelete(queue); +} + +static bool queue_send_wrapper(void *queue, void *item, uint32_t block_time_tick, uint32_t pos) +{ + signed portBASE_TYPE ret; + BaseType_t os_pos; + + if (pos == OSI_QUEUE_SEND_BACK) + os_pos = queueSEND_TO_BACK; + else if (pos == OSI_QUEUE_SEND_FRONT) + os_pos = queueSEND_TO_FRONT; + else + os_pos = queueOVERWRITE; + + if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) { + ret = xQueueGenericSend(queue, item, portMAX_DELAY, os_pos); + } else { + ret = xQueueGenericSend(queue, item, block_time_tick, os_pos); + } + + return ret == pdPASS ? true : false; +} + +static bool queue_send_from_isr_wrapper(void *queue, void *item, int *hptw) +{ + signed portBASE_TYPE ret; + + ret = xQueueSendFromISR(queue, item, (signed portBASE_TYPE *)hptw); + + return ret == pdPASS ? true : false; +} + +static bool queue_recv_wrapper(void *queue, void *item, uint32_t block_time_tick) +{ + signed portBASE_TYPE ret; + + if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) { + ret = xQueueReceive(queue, item, portMAX_DELAY); + } else { + ret = xQueueReceive(queue, item, block_time_tick); + } + + return ret == pdPASS ? true : false; +} + +static bool queue_recv_from_isr_wrapper(void *queue, void *item, int *hptw) +{ + signed portBASE_TYPE ret; + + ret = xQueueReceiveFromISR(queue, item, (signed portBASE_TYPE *)hptw); + + return ret == pdPASS ? true : false; +} + +static uint32_t queue_msg_waiting_wrapper(void *queue) +{ + return (uint32_t)uxQueueMessagesWaiting(queue); +} + +static uint32_t get_free_heap_size_wrapper(void) +{ + return (uint32_t)esp_get_free_heap_size(); +} + +static void *timer_create_wrapper(const char *name, uint32_t period_ticks, bool auto_load, void *arg, void (*cb)(void *timer)) +{ +#ifdef MODULE_ESP_WIFI_ANY + return xTimerCreate(name, period_ticks, auto_load, arg, (tmrTIMER_CALLBACK)cb); +#else + return NULL; +#endif +} + +static void *timer_get_arg_wrapper(void *timer) +{ +#ifdef MODULE_ESP_WIFI_ANY + return pvTimerGetTimerID(timer); +#else + return false; +#endif +} + +static bool timer_reset_wrapper(void *timer, uint32_t ticks) +{ +#ifdef MODULE_ESP_WIFI_ANY + return xTimerReset(timer, ticks); +#else + return false; +#endif +} + +static bool timer_stop_wrapper(void *timer, uint32_t ticks) +{ +#ifdef MODULE_ESP_WIFI_ANY + return xTimerStop(timer, ticks); +#else + return false; +#endif +} + +static bool timer_delete_wrapper(void *timer, uint32_t ticks) +{ +#ifdef MODULE_ESP_WIFI_ANY + return xTimerDelete(timer, ticks); +#else + return false; +#endif +} + +static void *malloc_wrapper(uint32_t s, uint32_t cap, const char *file, size_t line) +{ + uint32_t os_caps; + + if (cap & (OSI_MALLOC_CAP_8BIT | OSI_MALLOC_CAP_DMA)) + os_caps = MALLOC_CAP_8BIT | MALLOC_CAP_DMA; + else + os_caps = MALLOC_CAP_32BIT; + + return _heap_caps_malloc(s, os_caps, file, line); +} + +static void *zalloc_wrapper(uint32_t s, uint32_t cap, const char *file, size_t line) +{ + uint32_t os_caps; + + if (cap & (OSI_MALLOC_CAP_8BIT | OSI_MALLOC_CAP_DMA)) + os_caps = MALLOC_CAP_8BIT | MALLOC_CAP_DMA; + else + os_caps = MALLOC_CAP_32BIT; + + return _heap_caps_zalloc(s, os_caps, file, line); +} + +static void *realloc_wrapper(void *ptr, uint32_t s, uint32_t cap, const char *file, size_t line) +{ + uint32_t os_caps; + + if (cap & (OSI_MALLOC_CAP_8BIT | OSI_MALLOC_CAP_DMA)) + os_caps = MALLOC_CAP_8BIT | MALLOC_CAP_DMA; + else + os_caps = MALLOC_CAP_32BIT; + + return _heap_caps_realloc(ptr, s, os_caps, file, line); +} + +static void *calloc_wrapper(uint32_t cnt, uint32_t s, uint32_t cap, const char *file, size_t line) +{ + uint32_t os_caps; + + if (cap & (OSI_MALLOC_CAP_8BIT | OSI_MALLOC_CAP_DMA)) + os_caps = MALLOC_CAP_8BIT | MALLOC_CAP_DMA; + else + os_caps = MALLOC_CAP_32BIT; + + return _heap_caps_calloc(cnt , s, os_caps, file, line); +} + +static void free_wrapper(void *ptr, const char *file, size_t line) +{ + _heap_caps_free(ptr, file, line); +} + +static void srand_wrapper(uint32_t seed) +{ + /* empty function */ +} + +static int32_t rand_wrapper(void) +{ + return (int32_t)esp_random(); +} + +void *osi_task_top_sp(void) +{ + extern volatile thread_t *sched_active_thread; + return sched_active_thread ? sched_active_thread->sp : 0; +} + +const wifi_osi_funcs_t s_wifi_osi_funcs = { + .version = ESP_WIFI_OS_ADAPTER_VERSION, + + .task_create = task_create_wrapper, + .task_delete = task_delete_wrapper, + .task_yield = task_yield_wrapper, + .task_yield_from_isr = task_yield_from_isr_wrapper, + .task_delay = task_delay_wrapper, + .task_get_current_task = task_get_current_task_wrapper, + .task_get_max_priority = task_get_max_priority_wrapper, + + .task_ms_to_tick = task_ms_to_tick_wrapper, + + .task_suspend_all = task_suspend_all_wrapper, + .task_resume_all = task_resume_all_wrapper, + + .os_init = os_init_wrapper, + .os_start = os_start_wrapper, + + .semphr_create = semphr_create_wrapper, + .semphr_delete = semphr_delete_wrapper, + .semphr_take_from_isr = semphr_take_from_isr_wrapper, + .semphr_give_from_isr = semphr_give_from_isr_wrapper, + .semphr_take = semphr_take_wrapper, + .semphr_give = semphr_give_wrapper, + + .mutex_create = mutex_create_wrapper, + .mutex_delete = mutex_delete_wrapper, + .mutex_lock = mutex_lock_wrapper, + .mutex_unlock = mutex_unlock_wrapper, + + .queue_create = queue_create_wrapper, + .queue_delete = queue_delete_wrapper, + .queue_send = queue_send_wrapper, + .queue_send_from_isr = queue_send_from_isr_wrapper, + .queue_recv = queue_recv_wrapper, + .queue_recv_from_isr = queue_recv_from_isr_wrapper, + .queue_msg_waiting = queue_msg_waiting_wrapper, + + .timer_create = timer_create_wrapper, + .timer_get_arg = timer_get_arg_wrapper, + .timer_reset = timer_reset_wrapper, + .timer_stop = timer_stop_wrapper, + .timer_delete = timer_delete_wrapper, + + .malloc = malloc_wrapper, + .zalloc = zalloc_wrapper, + .realloc = realloc_wrapper, + .calloc = calloc_wrapper, + .free = free_wrapper, + .get_free_heap_size = get_free_heap_size_wrapper, + + .srand = srand_wrapper, + .rand = rand_wrapper, + + .nvs_set_i8 = nvs_set_i8, + .nvs_get_i8 = nvs_get_i8, + .nvs_set_u8 = nvs_set_u8, + .nvs_get_u8 = nvs_get_u8, + .nvs_set_u16 = nvs_set_u16, + .nvs_get_u16 = nvs_get_u16, + .nvs_open = nvs_open, + .nvs_close = nvs_close, + .nvs_commit = nvs_commit, + .nvs_set_blob = nvs_set_blob, + .nvs_get_blob = nvs_get_blob, + .nvs_erase_key = nvs_erase_key, + + .magic = ESP_WIFI_OS_ADAPTER_MAGIC, +}; diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/source/ets_printf.c b/cpu/esp8266/vendor/esp-idf/esp8266/source/ets_printf.c new file mode 100644 index 000000000000..1406d7a5048d --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/source/ets_printf.c @@ -0,0 +1,310 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "sdkconfig.h" + +#include "esp_attr.h" + +#include "esp8266/eagle_soc.h" +#include "esp8266/uart_register.h" +#include "esp8266/rom_functions.h" + +#ifdef RIOT_VERSION + +/* RIOT has its own putchar function which writes to UART */ +extern int putchar(int c); +#define uart_putc putchar + +#else /* RIOT_VERSION */ + +#ifndef CONFIG_CONSOLE_UART_NONE +static void uart_putc(int c) +{ + while (1) { + uint32_t fifo_cnt = READ_PERI_REG(UART_STATUS(CONFIG_CONSOLE_UART_NUM)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S); + + if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) + break; + } + + WRITE_PERI_REG(UART_FIFO(CONFIG_CONSOLE_UART_NUM) , c); +} +#else +#define uart_putc(_c) { } +#endif + +#endif /* RIOT_VERSION */ + +int __attribute__ ((weak)) ets_putc(int c) +{ +#ifdef CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF + if (c == '\n') + uart_putc('\r'); +#elif defined(CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR) + if (c == '\n') + c = '\r'; +#endif + + uart_putc(c); + + return c; +} + +#if defined(CONFIG_USING_NEW_ETS_VPRINTF) && !defined(BOOTLOADER_BUILD) + +#define FILL_0 0x01 +#define FILL_LEFT 0x02 +#define POINTOR 0x04 +#define ALTERNATE 0x08 +#define OUPUT_INT 0x10 +#define START 0x20 + +#define VINT_STR_MAX 10 + +typedef union _val_cache { + uint8_t val8; + int32_t val32; + uint32_t val32u; + const char *valcp; +} val_cache_t; + +typedef struct _val_attr { + int8_t type; + uint8_t state; + uint8_t fillbytes; + uint8_t precision; + + val_cache_t value; +} val_attr_t; + +#define isdigit(_c) ((_c <= '9') && (_c >= '0')) +#define fill_num(_attr) ((attr)->fillbytes) +#define isfill_0(_attr) (fill_num(_attr) && ((_attr)->state & FILL_0)) +#define isfill_left(_attr) (fill_num(_attr) && ((_attr)->state & FILL_LEFT)) +#define isstart(_attr) ((_attr)->state & START) + +static inline void ets_printf_ch_mutlti(uint32_t c, uint32_t len) +{ + while (len--) + ets_putc(c); +} + +static inline void ets_printf_buf(const char *s, uint32_t len) +{ + while (len--) + ets_putc(*s++); +} + +static int ets_printf_str(const val_attr_t * const attr) +{ + const char *s = attr->value.valcp; + s = s == NULL ? "" : s; + + if (fill_num(attr)) { + unsigned char left; + unsigned char len; + + while (*s != '\0') + s++; + len = s - attr->value.valcp; + left = fill_num(attr) > len ? fill_num(attr) - len : 0; + + if (!isfill_left(attr)) { + ets_printf_ch_mutlti(' ', left); + } + + ets_printf_buf(attr->value.valcp, len); + + if (isfill_left(attr)) { + ets_printf_ch_mutlti(' ', left); + } + } else { + while (*s != '\0') + ets_putc(*s++); + } + + return 0; +} + +static int ets_printf_int(val_attr_t * const attr, uint8_t hex) +{ + char buf[VINT_STR_MAX]; + unsigned char offset = VINT_STR_MAX; + + if (attr->value.val32u != 0) { + for (; attr->value.val32u > 0; attr->value.val32u /= hex) { + unsigned char c = attr->value.val32u % hex; + if (c < 10) + buf[--offset] = c + '0'; + else + buf[--offset] = c + 'a' - 10; + } + } else + buf[--offset] = '0'; + + if (fill_num(attr)) { + char fill_data = isfill_0(attr) ? '0' : ' '; + unsigned char len = fill_num(attr) - (VINT_STR_MAX - offset); + unsigned char left = fill_num(attr) > (VINT_STR_MAX - offset) ? len : 0; + + if (!isfill_left(attr)) { + ets_printf_ch_mutlti(fill_data, left); + } + + ets_printf_buf(&buf[offset], VINT_STR_MAX - offset); + + if (isfill_left(attr)) { + ets_printf_ch_mutlti(fill_data, left); + } + } else { + ets_printf_buf(&buf[offset], VINT_STR_MAX - offset); + } + + return 0; +} + +int ets_vprintf(const char *fmt, va_list va) +{ + for (; ;) { + const char *ps = fmt; + val_attr_t attr; + + while (*ps != '\0' && *ps != '%') + ets_putc(*ps++); + + if (*ps == '\0') + break; + + fmt = ps; + + attr.state = 0; + attr.type = -1; + attr.fillbytes = 0; + attr.precision = 0; + + for (; ;) { + switch (*++ps) { + case 'd': + case 'i': + case 'u': + case 'x': + case 'c': + case 's': + case 'p': + case '\0': + attr.type = *ps++; + break; + case '#': + attr.state |= ALTERNATE; + ps++; + break; + case '0'...'9': + if (!isstart(&attr) && *ps == '0') { + attr.state |= FILL_0; + } else { + if (attr.state & POINTOR) + attr.precision = attr.precision * 10 + *ps - '0'; + else + attr.fillbytes = attr.fillbytes * 10 + *ps - '0'; + } + break; + case '.': + attr.state |= POINTOR; + break; + case '-': + attr.state |= FILL_LEFT; + break; + default: + attr.type = -2; + break; + } + + attr.state |= START; + + if (attr.type != -1) + break; + } + + switch (attr.type) { + case 'c': + attr.value.val8 = (char)va_arg(va, int); + ets_putc(attr.value.val8); + break; + case 's': + attr.value.valcp = va_arg(va, const char *); + ets_printf_str(&attr); + break; + case 'i': + case 'd': + attr.value.val32 = va_arg(va, int); + if (attr.value.val32 < 0) { + ets_putc('-'); + attr.value.val32 = -attr.value.val32; + } + ets_printf_int(&attr, 10); + break; + case 'u': + attr.value.val32u = va_arg(va, unsigned int); + ets_printf_int(&attr, 10); + break; + case 'x': + attr.value.val32u = va_arg(va, unsigned int); + ets_printf_int(&attr, 16); + break; + case 'p': + attr.value.valcp = va_arg(va, const char *); + ets_printf_int(&attr, 16); + default: + break; + } + + fmt = ps; + } + + return 0; +} + +#else /* defined(CONFIG_USING_NEW_ETS_VPRINTF) && !defined(BOOTLOADER_BUILD) */ + +int ets_vprintf(const char *fmt, va_list ap) +{ + return ets_io_vprintf(ets_putc, fmt, ap); +} + +#endif /* defined(CONFIG_USING_NEW_ETS_VPRINTF) && !defined(BOOTLOADER_BUILD) */ + +/** + * Re-write ets_printf in SDK side, since ets_printf in ROM will use a global + * variable which address is in heap region of SDK side. If use ets_printf in ROM, + * this variable maybe re-write when heap alloc and modification. + * + * Using new "ets_vprintf" costs stack without alignment and accuracy: + * just "fmt": 136 Bytes + * "%s": 172 Bytes + * "%p", "%d, "%i, "%u", "%x": 215 Bytes + */ +int ets_printf(const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = ets_vprintf(fmt, ap); + va_end(ap); + + return ret; +} diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/source/event_default_handlers.c b/cpu/esp8266/vendor/esp-idf/esp8266/source/event_default_handlers.c new file mode 100644 index 000000000000..18f877ac6109 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/source/event_default_handlers.c @@ -0,0 +1,376 @@ +// Copyright 2018 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. + +#ifdef RIOT_VERSION +#define ENABLE_DEBUG 0 +#include "debug.h" +#include "esp_common.h" +#endif + +#include +#include +#include + +#include "rom/ets_sys.h" + +#include "esp_err.h" +#include "esp_wifi.h" +#include "esp_event.h" +#include "esp_event_loop.h" +#include "esp_system.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" + +#ifndef RIOT_VERSION +#include "tcpip_adapter.h" +#endif +#include "esp_log.h" + +static const char* TAG = "event"; + +#define WIFI_API_CALL_CHECK(info, api_call, ret) \ +do{\ + esp_err_t __err = (api_call);\ + if ((ret) != __err) {\ + ESP_LOGE(TAG, "%s %d %s ret=0x%X", __FUNCTION__, __LINE__, (info), __err);\ + return __err;\ + }\ +} while(0) + +typedef esp_err_t (*system_event_handler_t)(system_event_t *e); + +static esp_err_t system_event_ap_start_handle_default(system_event_t *event); +static esp_err_t system_event_ap_stop_handle_default(system_event_t *event); +static esp_err_t system_event_sta_start_handle_default(system_event_t *event); +static esp_err_t system_event_sta_stop_handle_default(system_event_t *event); +static esp_err_t system_event_sta_connected_handle_default(system_event_t *event); +static esp_err_t system_event_sta_disconnected_handle_default(system_event_t *event); +static esp_err_t system_event_sta_got_ip_default(system_event_t *event); +static esp_err_t system_event_sta_lost_ip_default(system_event_t *event); + +/* Default event handler functions + + Any entry in this table which is disabled by config will have a NULL handler. +*/ +static system_event_handler_t default_event_handlers[SYSTEM_EVENT_MAX] = { 0 }; + +static esp_err_t system_event_sta_got_ip_default(system_event_t *event) +{ + #ifndef RIOT_VERSION /* TODO implement */ + ESP_LOGI(TAG, "sta ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR, + IP2STR(&event->event_info.got_ip.ip_info.ip), + IP2STR(&event->event_info.got_ip.ip_info.netmask), + IP2STR(&event->event_info.got_ip.ip_info.gw)); + #else + ESP_LOGI(TAG, "%s", __func__); + #endif + + return ESP_OK; +} + +static esp_err_t system_event_sta_lost_ip_default(system_event_t *event) +{ + ESP_LOGI(TAG, "station ip lost"); + return ESP_OK; +} + +esp_err_t system_event_ap_start_handle_default(system_event_t *event) +{ + #ifndef RIOT_VERSION /* TODO implement */ + tcpip_adapter_ip_info_t ap_ip; + uint8_t ap_mac[6]; + + WIFI_API_CALL_CHECK("esp_wifi_mac_get", esp_wifi_get_mac(ESP_IF_WIFI_AP, ap_mac), ESP_OK); + + tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ap_ip); + tcpip_adapter_start(TCPIP_ADAPTER_IF_AP, ap_mac, &ap_ip); + #else + ESP_LOGI(TAG, "%s", __func__); + #endif + + return ESP_OK; +} + +esp_err_t system_event_ap_stop_handle_default(system_event_t *event) +{ + #ifndef RIOT_VERSION /* TODO implement */ + tcpip_adapter_stop(TCPIP_ADAPTER_IF_AP); + #else + ESP_LOGI(TAG, "%s", __func__); + #endif + + return ESP_OK; +} + +esp_err_t system_event_sta_start_handle_default(system_event_t *event) +{ + #ifndef RIOT_VERSION /* TODO implement */ + tcpip_adapter_ip_info_t sta_ip; + uint8_t sta_mac[6]; + + WIFI_API_CALL_CHECK("esp_wifi_mac_get", esp_wifi_get_mac(ESP_IF_WIFI_STA, sta_mac), ESP_OK); + tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &sta_ip); + tcpip_adapter_start(TCPIP_ADAPTER_IF_STA, sta_mac, &sta_ip); + #else + ESP_LOGI(TAG, "%s", __func__); + #endif + + return ESP_OK; +} + +esp_err_t system_event_sta_stop_handle_default(system_event_t *event) +{ + #ifndef RIOT_VERSION /* TODO implement */ + tcpip_adapter_stop(TCPIP_ADAPTER_IF_STA); + #else + ESP_LOGI(TAG, "%s", __func__); + #endif + + return ESP_OK; +} + +esp_err_t system_event_sta_connected_handle_default(system_event_t *event) +{ + #ifndef RIOT_VERSION /* TODO implement */ + tcpip_adapter_dhcp_status_t status; + + tcpip_adapter_up(TCPIP_ADAPTER_IF_STA); + tcpip_adapter_dhcpc_get_status(TCPIP_ADAPTER_IF_STA, &status); + + if (status == TCPIP_ADAPTER_DHCP_INIT) { + tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_STA); + } else if (status == TCPIP_ADAPTER_DHCP_STOPPED) { + tcpip_adapter_ip_info_t sta_ip; + tcpip_adapter_ip_info_t sta_old_ip; + + tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &sta_ip); + tcpip_adapter_get_old_ip_info(TCPIP_ADAPTER_IF_STA, &sta_old_ip); + + if (!(ip4_addr_isany_val(sta_ip.ip) || ip4_addr_isany_val(sta_ip.netmask) || ip4_addr_isany_val(sta_ip.gw))) { + system_event_t evt; + + evt.event_id = SYSTEM_EVENT_STA_GOT_IP; + evt.event_info.got_ip.ip_changed = false; + + if (memcmp(&sta_ip, &sta_old_ip, sizeof(sta_ip))) { + evt.event_info.got_ip.ip_changed = true; + } + + memcpy(&evt.event_info.got_ip.ip_info, &sta_ip, sizeof(tcpip_adapter_ip_info_t)); + tcpip_adapter_set_old_ip_info(TCPIP_ADAPTER_IF_STA, &sta_ip); + + esp_event_send(&evt); + ESP_LOGD(TAG, "static ip: ip changed=%d", evt.event_info.got_ip.ip_changed); + } else { + ESP_LOGE(TAG, "invalid static ip"); + } + } + #else + ESP_LOGI(TAG, "%s", __func__); + #endif + + return ESP_OK; +} + +esp_err_t system_event_sta_disconnected_handle_default(system_event_t *event) +{ + #ifndef RIOT_VERSION /* TODO implement */ + tcpip_adapter_down(TCPIP_ADAPTER_IF_STA); + #else + ESP_LOGI(TAG, "%s", __func__); + #endif + return ESP_OK; +} + +static esp_err_t esp_system_event_debug(system_event_t *event) +{ + if (event == NULL) { + ESP_LOGE(TAG, "event is null!"); + printf("event is null!"); + return ESP_FAIL; + } + + switch (event->event_id) { + case SYSTEM_EVENT_WIFI_READY: { + ESP_LOGD(TAG, "SYSTEM_EVENT_WIFI_READY"); + break; + } + case SYSTEM_EVENT_SCAN_DONE: { + system_event_sta_scan_done_t *scan_done = &event->event_info.scan_done; + (void)scan_done; /* to avoid compile error: unused variable */ + ESP_LOGD(TAG, "SYSTEM_EVENT_SCAN_DONE, status:%d, number:%d", scan_done->status, scan_done->number); + break; + } + case SYSTEM_EVENT_STA_START: { + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_START"); + break; + } + case SYSTEM_EVENT_STA_STOP: { + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_STOP"); + break; + } + case SYSTEM_EVENT_STA_CONNECTED: { + system_event_sta_connected_t *connected = &event->event_info.connected; + (void)connected; /* to avoid compile error: unused variable */ + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_CONNECTED, ssid:%s, ssid_len:%d, bssid:" MACSTR ", channel:%d, authmode:%d", \ + connected->ssid, connected->ssid_len, MAC2STR(connected->bssid), connected->channel, connected->authmode); + break; + } + case SYSTEM_EVENT_STA_DISCONNECTED: { + system_event_sta_disconnected_t *disconnected = &event->event_info.disconnected; + (void)disconnected; /* to avoid compile error: unused variable */ + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_DISCONNECTED, ssid:%s, ssid_len:%d, bssid:" MACSTR ", reason:%d", \ + disconnected->ssid, disconnected->ssid_len, MAC2STR(disconnected->bssid), disconnected->reason); + break; + } + case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: { + system_event_sta_authmode_change_t *auth_change = &event->event_info.auth_change; + (void)auth_change; /* to avoid compile error: unused variable */ + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_AUTHMODE_CHNAGE, old_mode:%d, new_mode:%d", auth_change->old_mode, auth_change->new_mode); + break; + } + case SYSTEM_EVENT_STA_GOT_IP: { + #ifndef RIOT_VERSION /* TODO implement */ + system_event_sta_got_ip_t *got_ip = &event->event_info.got_ip; + (void)got_ip; /* to avoid compile error: unused variable */ + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_GOT_IP, ip:" IPSTR ", mask:" IPSTR ", gw:" IPSTR, + IP2STR(&got_ip->ip_info.ip), + IP2STR(&got_ip->ip_info.netmask), + IP2STR(&got_ip->ip_info.gw)); + #else + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_GOT_IP"); + #endif + break; + } + case SYSTEM_EVENT_STA_LOST_IP: { + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_LOST_IP"); + break; + } + case SYSTEM_EVENT_STA_WPS_ER_SUCCESS: { + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_SUCCESS"); + break; + } + case SYSTEM_EVENT_STA_WPS_ER_FAILED: { + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_FAILED"); + break; + } + case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT: { + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_TIMEOUT"); + break; + } + case SYSTEM_EVENT_STA_WPS_ER_PIN: { + ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_PIN"); + break; + } + case SYSTEM_EVENT_AP_START: { + ESP_LOGD(TAG, "SYSTEM_EVENT_AP_START"); + break; + } + case SYSTEM_EVENT_AP_STOP: { + ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STOP"); + break; + } + case SYSTEM_EVENT_AP_STACONNECTED: { + system_event_ap_staconnected_t *staconnected = &event->event_info.sta_connected; + (void)staconnected; /* to avoid compile error: unused variable */ + ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STACONNECTED, mac:" MACSTR ", aid:%d", \ + MAC2STR(staconnected->mac), staconnected->aid); + break; + } + case SYSTEM_EVENT_AP_STADISCONNECTED: { + system_event_ap_stadisconnected_t *stadisconnected = &event->event_info.sta_disconnected; + (void)stadisconnected; /* to avoid compile error: unused variable */ + ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STADISCONNECTED, mac:" MACSTR ", aid:%d", \ + MAC2STR(stadisconnected->mac), stadisconnected->aid); + break; + } + case SYSTEM_EVENT_AP_STAIPASSIGNED: { + ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STAIPASSIGNED"); + break; + } + case SYSTEM_EVENT_AP_PROBEREQRECVED: { + system_event_ap_probe_req_rx_t *ap_probereqrecved = &event->event_info.ap_probereqrecved; + (void)ap_probereqrecved; /* to avoid compile error: unused variable */ + ESP_LOGD(TAG, "SYSTEM_EVENT_AP_PROBEREQRECVED, rssi:%d, mac:" MACSTR, \ + ap_probereqrecved->rssi, \ + MAC2STR(ap_probereqrecved->mac)); + break; + } +#if ESP_EVENT_IPV6 + case SYSTEM_EVENT_GOT_IP6: { + #ifndef RIOT_VERSION /* TODO implement */ + ip6_addr_t *addr = &event->event_info.got_ip6.ip6_info.ip; + ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STA_GOT_IP6 address %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", + IP6_ADDR_BLOCK1(addr), + IP6_ADDR_BLOCK2(addr), + IP6_ADDR_BLOCK3(addr), + IP6_ADDR_BLOCK4(addr), + IP6_ADDR_BLOCK5(addr), + IP6_ADDR_BLOCK6(addr), + IP6_ADDR_BLOCK7(addr), + IP6_ADDR_BLOCK8(addr)); + #else + ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STA_GOT_IP6 address "); + #endif + break; + } +#endif + + + default: { + ESP_LOGW(TAG, "unexpected system event %d!", event->event_id); + break; + } + } + + return ESP_OK; +} + +esp_err_t esp_event_process_default(system_event_t *event) +{ + if (event == NULL) { + ESP_LOGE(TAG, "Error: event is null!"); + return ESP_FAIL; + } + + esp_system_event_debug(event); + if ((event->event_id < SYSTEM_EVENT_MAX)) { + if (default_event_handlers[event->event_id] != NULL) { + ESP_LOGV(TAG, "enter default callback"); + default_event_handlers[event->event_id](event); + ESP_LOGV(TAG, "exit default callback"); + } + } else { + ESP_LOGE(TAG, "mismatch or invalid event, id=%d", event->event_id); + return ESP_FAIL; + } + return ESP_OK; +} + +void esp_event_set_default_wifi_handlers(void) +{ + default_event_handlers[SYSTEM_EVENT_STA_START] = system_event_sta_start_handle_default; + default_event_handlers[SYSTEM_EVENT_STA_STOP] = system_event_sta_stop_handle_default; + default_event_handlers[SYSTEM_EVENT_STA_CONNECTED] = system_event_sta_connected_handle_default; + default_event_handlers[SYSTEM_EVENT_STA_DISCONNECTED] = system_event_sta_disconnected_handle_default; + default_event_handlers[SYSTEM_EVENT_STA_GOT_IP] = system_event_sta_got_ip_default; + default_event_handlers[SYSTEM_EVENT_STA_LOST_IP] = system_event_sta_lost_ip_default; + default_event_handlers[SYSTEM_EVENT_AP_START] = system_event_ap_start_handle_default; + default_event_handlers[SYSTEM_EVENT_AP_STOP] = system_event_ap_stop_handle_default; + + //esp_register_shutdown_handler((shutdown_handler_t)esp_wifi_stop); +} diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/source/event_loop.c b/cpu/esp8266/vendor/esp-idf/esp8266/source/event_loop.c new file mode 100644 index 000000000000..05a7d29ca498 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/source/event_loop.c @@ -0,0 +1,112 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include "esp_err.h" +#include "esp_wifi.h" +#include "esp_event.h" +#include "esp_event_loop.h" +#include "esp_wifi_osi.h" + +#include "esp_log.h" +#include "sdkconfig.h" + +static const char* TAG = "event"; +static bool s_event_init_flag = false; +static void *s_event_queue = NULL; +static system_event_cb_t s_event_handler_cb = NULL; +static void *s_event_ctx = NULL; + +static esp_err_t esp_event_post_to_user(system_event_t *event) +{ + if (s_event_handler_cb) { + return (*s_event_handler_cb)(s_event_ctx, event); + } + return ESP_OK; +} + +static void esp_event_loop_task(void *pvParameters) +{ + while (1) { + system_event_t evt; + if (wifi_queue_recv(s_event_queue, &evt, OSI_FUNCS_TIME_BLOCKING) == pdPASS) { + esp_err_t ret = esp_event_process_default(&evt); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "default event handler failed!"); + } + ret = esp_event_post_to_user(&evt); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "post event to user fail!"); + } + } + } +} + +system_event_cb_t esp_event_loop_set_cb(system_event_cb_t cb, void *ctx) +{ + system_event_cb_t old_cb = s_event_handler_cb; + s_event_handler_cb = cb; + s_event_ctx = ctx; + return old_cb; +} + +esp_err_t esp_event_send(system_event_t *event) +{ + if (s_event_queue == NULL) { + ESP_LOGE(TAG, "Event loop not initialized via esp_event_loop_init, but esp_event_send called"); + return ESP_ERR_INVALID_STATE; + } + + int ret = wifi_queue_send(s_event_queue, event, 0, OSI_QUEUE_SEND_BACK); + if (ret != true) { + if (event) { + ESP_LOGE(TAG, "e=%d f", event->event_id); + } else { + ESP_LOGE(TAG, "e null"); + } + return ESP_FAIL; + } + return ESP_OK; +} + +QueueHandle_t esp_event_loop_get_queue(void) +{ + return s_event_queue; +} + +esp_err_t esp_event_loop_init(system_event_cb_t cb, void *ctx) +{ + if (s_event_init_flag) { + return ESP_FAIL; + } + s_event_handler_cb = cb; + s_event_ctx = ctx; + s_event_queue = wifi_queue_create(32, sizeof(system_event_t)); + if(s_event_queue == NULL) + return ESP_ERR_NO_MEM; +#ifdef RIOT_VERSION + if(wifi_task_create(esp_event_loop_task, "esp_events", EVENT_LOOP_STACKSIZE, NULL, wifi_task_get_max_priority() - 5) == NULL) { +#else + if(wifi_task_create(esp_event_loop_task, "esp_event_loop_task", EVENT_LOOP_STACKSIZE, NULL, wifi_task_get_max_priority() - 5) == NULL) { +#endif + return ESP_ERR_NO_MEM; + } + s_event_handler_cb = cb; + s_event_ctx = ctx; + s_event_init_flag = true; + return ESP_OK; +} diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/source/phy_init.c b/cpu/esp8266/vendor/esp-idf/esp8266/source/phy_init.c new file mode 100644 index 000000000000..5b137f86d09f --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/source/phy_init.c @@ -0,0 +1,336 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include "rom/ets_sys.h" + +#include "esp_err.h" +#include "esp_phy_init.h" +#include "esp_system.h" +#include "esp_log.h" + +#include "nvs.h" +#include "nvs_flash.h" +#include "sdkconfig.h" + +#include "phy_init_data.h" +#include "phy.h" + +static const char *TAG = "phy_init"; + +static uint8_t phy_check_calibration_data(uint8_t *rf_cal_data) +{ +#define CHECK_NUM 26 +#define CHIP_ID_L 24 +#define CHIP_ID_H 25 + + uint8_t i; + uint32_t *cal_data_word = (uint32_t *)rf_cal_data; + uint32_t check_sum = 0; + + /* L: flag_1[79:76], version[59:56], mac_map[55:48], mac_l[47:24] */ + uint32_t chip_id_l = ((REG_READ(0x3FF00058) & 0xF000) << 16) | + (REG_READ(0x3ff00054) & 0xFFFFFFF); + /* H: mac_l[31:24], mac_h[119:96] */ + uint32_t chip_id_h = (REG_READ(0x3FF00050) & 0xFF000000) | + (REG_READ(0x3ff0005C) & 0xFFFFFF); + + cal_data_word[CHIP_ID_L] = chip_id_l; + cal_data_word[CHIP_ID_H] = chip_id_h; + + for (i = 0; i < CHECK_NUM; i++) { + check_sum += cal_data_word[i]; + } + + return (cal_data_word[CHECK_NUM] != ~check_sum); +} + +/* temporary put rx_gain_dc_table in memory */ +/* ToDo: use rx_gain_dc_table in nvs, need to modify internal libraries */ +uint32_t rx_gain_dc_table[125]; + +esp_err_t esp_phy_rf_init(const esp_phy_init_data_t *init_data, esp_phy_calibration_mode_t mode, + esp_phy_calibration_data_t *calibration_data, phy_rf_module_t module) +{ + esp_err_t status = ESP_OK; + uint8_t sta_mac[6]; + uint8_t *local_init_data = calloc(1, 256); +#ifdef CONFIG_CONSOLE_UART_BAUDRATE + const uint32_t uart_baudrate = CONFIG_CONSOLE_UART_BAUDRATE; +#else + const uint32_t uart_baudrate = 74880; // ROM default baudrate +#endif + + memcpy(local_init_data, init_data->params, 128); + + extern uint32_t *phy_rx_gain_dc_table; + phy_rx_gain_dc_table = calibration_data->rx_gain_dc_table; + uint8_t cal_data_check = phy_check_calibration_data(calibration_data->rf_cal_data) || + phy_check_data_table(phy_rx_gain_dc_table, 125, 1); + + phy_afterwake_set_rfoption(1); + + if (!cal_data_check) { + write_data_to_rtc(calibration_data->rf_cal_data); + } + + esp_efuse_mac_get_default(sta_mac); + chip_init(local_init_data, sta_mac, uart_baudrate); + get_data_from_rtc((uint8_t *)calibration_data); + + memcpy(rx_gain_dc_table, calibration_data->rx_gain_dc_table, 4 * 125); + phy_rx_gain_dc_table = rx_gain_dc_table; + + free(local_init_data); + + if (cal_data_check == ESP_CAL_DATA_CHECK_FAIL) { +#ifdef CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE + ESP_LOGW(TAG, "saving new calibration data because of checksum failure, mode(%d)", mode); + if (mode != PHY_RF_CAL_FULL) { + esp_phy_store_cal_data_to_nvs(calibration_data); + } +#endif + } + + return status; +} + +esp_err_t esp_phy_rf_deinit(phy_rf_module_t module) +{ + esp_err_t status = ESP_OK; + + return status; +} + +// PHY init data handling functions +#if CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION +#include "esp_partition.h" + +const esp_phy_init_data_t *esp_phy_get_init_data(void) +{ + const esp_partition_t *partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_PHY, NULL); + + if (partition == NULL) { + ESP_LOGE(TAG, "PHY data partition not found"); + return NULL; + } + + ESP_LOGD(TAG, "loading PHY init data from partition at offset 0x%x", partition->address); + size_t init_data_store_length = sizeof(phy_init_magic_pre) + + sizeof(esp_phy_init_data_t) + sizeof(phy_init_magic_post); + uint8_t *init_data_store = (uint8_t *) malloc(init_data_store_length); + + if (init_data_store == NULL) { + ESP_LOGE(TAG, "failed to allocate memory for PHY init data"); + return NULL; + } + + esp_err_t err = esp_partition_read(partition, 0, init_data_store, init_data_store_length); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "failed to read PHY data partition (0x%x)", err); + return NULL; + } + + if (memcmp(init_data_store, PHY_INIT_MAGIC, sizeof(phy_init_magic_pre)) != 0 || + memcmp(init_data_store + init_data_store_length - sizeof(phy_init_magic_post), + PHY_INIT_MAGIC, sizeof(phy_init_magic_post)) != 0) { + ESP_LOGE(TAG, "failed to validate PHY data partition"); + return NULL; + } + + ESP_LOGD(TAG, "PHY data partition validated"); + return (const esp_phy_init_data_t *)(init_data_store + sizeof(phy_init_magic_pre)); +} + +void esp_phy_release_init_data(const esp_phy_init_data_t *init_data) +{ + free((uint8_t *) init_data - sizeof(phy_init_magic_pre)); +} + +#else // CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION + +// phy_init_data.h will declare static 'phy_init_data' variable initialized with default init data + +const esp_phy_init_data_t *esp_phy_get_init_data(void) +{ + ESP_LOGD(TAG, "loading PHY init data from application binary"); + return &phy_init_data; +} + +void esp_phy_release_init_data(const esp_phy_init_data_t *init_data) +{ + // no-op +} +#endif // CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION + + +// PHY calibration data handling functions +static const char *PHY_NAMESPACE = "phy"; +static const char *PHY_CAL_DATA_KEY = "cal_data"; +static const char *PHY_RX_GAIN_DC_TABLE_KEY = "dc_table"; + +static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle, + esp_phy_calibration_data_t *out_cal_data); + +static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle, + const esp_phy_calibration_data_t *cal_data); + +esp_err_t esp_phy_load_cal_data_from_nvs(esp_phy_calibration_data_t *out_cal_data) +{ + nvs_handle handle; + esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READONLY, &handle); + + if (err == ESP_ERR_NVS_NOT_INITIALIZED) { + ESP_LOGE(TAG, "%s: NVS has not been initialized. " + "Call nvs_flash_init before starting WiFi/BT.", __func__); + } else if (err != ESP_OK) { + ESP_LOGD(TAG, "%s: failed to open NVS namespace (0x%x)", __func__, err); + return err; + } + + err = load_cal_data_from_nvs_handle(handle, out_cal_data); + nvs_close(handle); + return err; +} + +esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t *cal_data) +{ + nvs_handle handle; + esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READWRITE, &handle); + + if (err != ESP_OK) { + ESP_LOGD(TAG, "%s: failed to open NVS namespace (0x%x)", __func__, err); + return err; + } else { + err = store_cal_data_to_nvs_handle(handle, cal_data); + nvs_close(handle); + return err; + } +} + +static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle, + esp_phy_calibration_data_t *out_cal_data) +{ + esp_err_t err; + + size_t length = sizeof(out_cal_data->rf_cal_data); + + err = nvs_get_blob(handle, PHY_CAL_DATA_KEY, out_cal_data->rf_cal_data, &length); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: failed to get cal_data(0x%x)", __func__, err); + return err; + } + + if (length != sizeof(out_cal_data->rf_cal_data)) { + ESP_LOGD(TAG, "%s: invalid length of cal_data (%d)", __func__, length); + return ESP_ERR_INVALID_SIZE; + } + + length = sizeof(out_cal_data->rx_gain_dc_table); + err = nvs_get_blob(handle, PHY_RX_GAIN_DC_TABLE_KEY, out_cal_data->rx_gain_dc_table, &length); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: failed to get rx_gain_dc_table(0x%x)", __func__, err); + return err; + } + + if (length != sizeof(out_cal_data->rx_gain_dc_table)) { + ESP_LOGD(TAG, "%s: invalid length of rx_gain_dc_table (%d)", __func__, length); + return ESP_ERR_INVALID_SIZE; + } + + return ESP_OK; +} + +static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle, + const esp_phy_calibration_data_t *cal_data) +{ + esp_err_t err; + + err = nvs_set_blob(handle, PHY_CAL_DATA_KEY, cal_data->rf_cal_data, sizeof(cal_data->rf_cal_data)); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: store calibration data failed(0x%x)\n", __func__, err); + return err; + } + + err = nvs_set_blob(handle, PHY_RX_GAIN_DC_TABLE_KEY, cal_data->rx_gain_dc_table, sizeof(cal_data->rx_gain_dc_table)); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: store rx gain dc table failed(0x%x)\n", __func__, err); + return err; + } + + err = nvs_commit(handle); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: store calibration nvs commit failed(0x%x)\n", __func__, err); + } + + return err; +} + +void esp_phy_load_cal_and_init(phy_rf_module_t module) +{ + esp_phy_calibration_data_t *cal_data = + (esp_phy_calibration_data_t *) calloc(sizeof(esp_phy_calibration_data_t), 1); + + if (cal_data == NULL) { + ESP_LOGE(TAG, "failed to allocate memory for RF calibration data"); + abort(); + } + + const esp_phy_init_data_t *init_data = esp_phy_get_init_data(); + + if (init_data == NULL) { + ESP_LOGE(TAG, "failed to obtain PHY init data"); + abort(); + } + +#ifdef CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE + esp_phy_calibration_mode_t calibration_mode = PHY_RF_CAL_PARTIAL; + +// if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) { +// calibration_mode = PHY_RF_CAL_NONE; +// } + + esp_err_t err = esp_phy_load_cal_data_from_nvs(cal_data); + + if (err != ESP_OK) { + ESP_LOGW(TAG, "failed to load RF calibration data (0x%x), falling back to full calibration", err); + calibration_mode = PHY_RF_CAL_FULL; + } + + esp_phy_rf_init(init_data, calibration_mode, cal_data, module); + + if (calibration_mode != PHY_RF_CAL_NONE && err != ESP_OK) { + err = esp_phy_store_cal_data_to_nvs(cal_data); + } else { + err = ESP_OK; + } + +#else + esp_phy_rf_init(init_data, PHY_RF_CAL_FULL, cal_data, module); +#endif + + esp_phy_release_init_data(init_data); + + free(cal_data); // PHY maintains a copy of calibration data, so we can free this +} diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/source/reset_reason.c b/cpu/esp8266/vendor/esp-idf/esp8266/source/reset_reason.c new file mode 100644 index 000000000000..ec3370696cc1 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/source/reset_reason.c @@ -0,0 +1,145 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "sdkconfig.h" +#include +#include "esp_system.h" +#include "internal/esp_system_internal.h" +#include "esp8266/rtc_register.h" +#include "esp8266/rom_functions.h" +#include "esp_log.h" +#include "esp_libc.h" + +#if CONFIG_RESET_REASON + +#define RTC_RESET_SW_CAUSE_REG RTC_STORE0 +#define RTC_RESET_HW_CAUSE_REG RTC_STATE1 +#define RTC_WAKEUP_HW_CAUSE_REG RTC_STATE2 + +#define RTC_RESET_HW_CAUSE_LSB 0 +#define RTC_RESET_HW_CAUSE_MSB 3 + +#define RTC_WAKEUP_HW_CAUSE_LSB 8 +#define RTC_WAKEUP_HW_CAUSE_MSB 13 + +static const char *TAG = "reset_reason"; +static uint32_t s_reset_reason; + +static inline void esp_reset_reason_clear_hint() +{ + rtc_sys_info.hint = 0; +} + +static inline uint32_t esp_reset_reason_get_hint(uint32_t hw_reset) +{ + if (hw_reset == POWERON_RESET && rtc_sys_info.hint != ESP_RST_SW) { + uint32_t *p = (uint32_t *)&rtc_sys_info; + + for (int i = 0; i < RTC_SYS_RAM_SIZE / sizeof(uint32_t); i++) + *p++ = 0; + } + + return rtc_sys_info.hint; +} + +static inline uint32_t esp_rtc_get_reset_reason(void) +{ + return GET_PERI_REG_BITS(RTC_RESET_HW_CAUSE_REG, RTC_RESET_HW_CAUSE_MSB, RTC_RESET_HW_CAUSE_LSB); +} + +#if CONFIG_RESET_REASON_CHECK_WAKEUP +static inline uint32_t esp_rtc_get_wakeup_reason(void) +{ + return GET_PERI_REG_BITS(RTC_WAKEUP_HW_CAUSE_REG, RTC_WAKEUP_HW_CAUSE_MSB, RTC_WAKEUP_HW_CAUSE_LSB); +} +#endif + +static inline uint32_t get_reset_reason(uint32_t rtc_reset_reason, uint32_t reset_reason_hint) +{ + switch (rtc_reset_reason) { + case POWERON_RESET: + if (reset_reason_hint == ESP_RST_SW) + return reset_reason_hint; + return ESP_RST_POWERON; + case EXT_RESET: + if (reset_reason_hint == ESP_RST_DEEPSLEEP) { + return reset_reason_hint; + } + return ESP_RST_EXT; + case SW_RESET: + if (reset_reason_hint == ESP_RST_PANIC || + reset_reason_hint == ESP_RST_BROWNOUT || + reset_reason_hint == ESP_RST_TASK_WDT) { + return reset_reason_hint; + } + return ESP_RST_SW; + case DEEPSLEEP_RESET: + return ESP_RST_DEEPSLEEP; + case OWDT_RESET: + return ESP_RST_WDT; + case SDIO_RESET: + return ESP_RST_SDIO; + default: + return ESP_RST_UNKNOWN; + } +} + +/** + * @brief Internal function to get SoC reset reason at system initialization + */ +void esp_reset_reason_init(void) +{ + const uint32_t hw_reset = esp_rtc_get_reset_reason(); +#if CONFIG_RESET_REASON_CHECK_WAKEUP + const uint32_t hw_wakeup = esp_rtc_get_wakeup_reason(); +#else + const uint32_t hw_wakeup = 0; +#endif + const uint32_t hint = esp_reset_reason_get_hint(hw_reset); + + s_reset_reason = get_reset_reason(hw_reset, hint); + if (hint != ESP_RST_UNKNOWN) { + esp_reset_reason_clear_hint(); + } + + ESP_LOGI(TAG, "RTC reset %u wakeup %u store %u, reason is %u", hw_reset, hw_wakeup, hint, s_reset_reason); +} + +/** + * @brief Internal function to set reset reason hint + */ +void esp_reset_reason_set_hint(esp_reset_reason_t hint) +{ + rtc_sys_info.hint = hint; +} + +/** + * @brief Get reason of last reset + */ +esp_reset_reason_t esp_reset_reason(void) +{ + return (esp_reset_reason_t)s_reset_reason; +} + +#else /* CONFIG_RESET_REASON */ + +/** + * null function for pass compiling + */ +void esp_reset_reason_set_hint(esp_reset_reason_t hint) +{ + +} + +#endif /* CONFIG_RESET_REASON */ diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/source/startup.c b/cpu/esp8266/vendor/esp-idf/esp8266/source/startup.c new file mode 100644 index 000000000000..cda46511462a --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/source/startup.c @@ -0,0 +1,171 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include "sdkconfig.h" + +#include "nvs_flash.h" +#ifndef RIOT_VERSION +#include "tcpip_adapter.h" +#endif + +#include "esp_log.h" +#include "esp_image_format.h" +#include "esp_phy_init.h" +#include "esp_wifi_osi.h" +#include "esp_heap_caps_init.h" +#include "esp_system.h" +#include "esp_task_wdt.h" +#include "internal/esp_wifi_internal.h" +#include "internal/esp_system_internal.h" + +#define FLASH_MAP_ADDR 0x40200000 +#define FLASH_MAP_SIZE 0x00100000 + +extern void chip_boot(void); +extern int esp_rtc_init(void); +extern int mac_init(void); +extern int base_gpio_init(void); +extern int watchdog_init(void); +extern int wifi_timer_init(void); +extern int wifi_nvs_init(void); +extern esp_err_t esp_pthread_init(void); +extern void phy_get_bb_evm(void); + +static void user_init_entry(void *param) +{ + extern void app_main(void); + + phy_get_bb_evm(); + +#ifdef MCU_ESP8266 + /* initialize newlib system calls */ + extern void syscalls_init (void); + syscalls_init (); +#endif + + if (nvs_flash_init() != 0) { + assert(0); + } + if (wifi_nvs_init() != 0) { + assert(0); + } + if (esp_rtc_init() != 0) { + assert(0); + } + if (mac_init() != 0) { + assert(0); + } + if (base_gpio_init() != 0) { + assert(0); + }; + + esp_phy_load_cal_and_init(0); + +#ifdef MODULE_ESP_WIFI_ANY + if (wifi_timer_init() != 0) { + assert(0); + } +#endif + + esp_wifi_set_rx_pbuf_mem_type(WIFI_RX_PBUF_DRAM); + +#if CONFIG_RESET_REASON + esp_reset_reason_init(); +#endif + +#ifdef CONFIG_TASK_WDT + esp_task_wdt_init(); +#endif + +#ifdef CONFIG_ENABLE_PTHREAD + if (esp_pthread_init() != 0) { + assert(0); + } +#endif + +#ifdef RIOT_VERSION + /* initialize RIOT for ESP8266 */ + wifi_os_init(); + /* start RIOT kernel */ + wifi_os_start(); +#else + app_main(); + + wifi_task_delete(NULL); +#endif +} + +void call_user_start(size_t start_addr) +{ + int i; + int *p; + + extern int _bss_start, _bss_end; + + esp_image_header_t *head = (esp_image_header_t *)(FLASH_MAP_ADDR + (start_addr & (FLASH_MAP_SIZE - 1))); + esp_image_segment_header_t *segment = (esp_image_segment_header_t *)((uintptr_t)head + sizeof(esp_image_header_t)); + + for (i = 0; i < 3; i++) { + segment = (esp_image_segment_header_t *)((uintptr_t)segment + sizeof(esp_image_segment_header_t) + segment->data_len); + + uint32_t *dest = (uint32_t *)segment->load_addr; + uint32_t *src = (uint32_t *)((uintptr_t)segment + sizeof(esp_image_segment_header_t)); + uint32_t size = segment->data_len / sizeof(uint32_t); + + while (size--) + *dest++ = *src++; + } + + /* + * When finish copying IRAM program, the exception vect must be initialized. + * And then user can load/store data which is not aligned by 4-byte. + */ + __asm__ __volatile__( + "movi a0, 0x40100000\n" + "wsr a0, vecbase\n" + : : :"memory"); + +#ifndef CONFIG_BOOTLOADER_INIT_SPI_FLASH + chip_boot(); +#endif + + /* clear bss data */ + for (p = &_bss_start; p < &_bss_end; p++) + *p = 0; + + __asm__ __volatile__( + "rsil a2, 2\n" + "movi a1, _chip_interrupt_tmp\n" + : : :"memory"); + + heap_caps_init(); + +#ifdef RIOT_VERSION + /* in case of RIOT, user_init_entry is called directly and not from a task */ + user_init_entry(NULL); +#else + wifi_os_init(); + + if (wifi_task_create(user_init_entry, "uiT", CONFIG_MAIN_TASK_STACK_SIZE, NULL, wifi_task_get_max_priority()) == NULL) { + assert(0); + } + + wifi_os_start(); +#endif +} diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/source/system_api.c b/cpu/esp8266/vendor/esp-idf/esp8266/source/system_api.c new file mode 100644 index 000000000000..d5d754d2a0a8 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/source/system_api.c @@ -0,0 +1,357 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "esp_system.h" + +#include "crc.h" + +#include "esp8266/eagle_soc.h" +#include "esp8266/efuse_register.h" + +#include "FreeRTOS.h" + +#include "nvs.h" +#include "nvs_flash.h" + +static const char* TAG = "system_api"; + +static uint8_t base_mac_addr[6] = { 0 }; + +esp_err_t esp_base_mac_addr_set(uint8_t *mac) +{ + if (mac == NULL) { + ESP_LOGE(TAG, "Base MAC address is NULL"); + return ESP_ERR_INVALID_ARG; + } + + memcpy(base_mac_addr, mac, 6); + + return ESP_OK; +} + +esp_err_t esp_base_mac_addr_get(uint8_t *mac) +{ + uint8_t null_mac[6] = {0}; + + if (memcmp(base_mac_addr, null_mac, 6) == 0) { + ESP_LOGI(TAG, "Base MAC address is not set, read default base MAC address from BLK0 of EFUSE"); + return ESP_ERR_INVALID_MAC; + } + + memcpy(mac, base_mac_addr, 6); + + return ESP_OK; +} + +esp_err_t esp_efuse_mac_get_default(uint8_t* mac) +{ + uint32_t efuse[4]; + + uint8_t efuse_crc = 0; + uint8_t calc_crc = 0; + uint8_t version; + uint8_t use_default = 1; + + efuse[0] = REG_READ(EFUSE_DATA0_REG); + efuse[1] = REG_READ(EFUSE_DATA1_REG); + efuse[2] = REG_READ(EFUSE_DATA2_REG); + efuse[3] = REG_READ(EFUSE_DATA3_REG); + + mac[3] = efuse[1] >> 8; + mac[4] = efuse[1]; + mac[5] = efuse[0] >> 24; + + if (efuse[2] & EFUSE_IS_48BITS_MAC) { + uint8_t tmp_mac[4]; + + mac[0] = efuse[3] >> 16; + mac[1] = efuse[3] >> 8; + mac[2] = efuse[3]; + + use_default = 0; + + tmp_mac[0] = mac[2]; + tmp_mac[1] = mac[1]; + tmp_mac[2] = mac[0]; + + efuse_crc = efuse[2] >> 24; + calc_crc = esp_crc8(tmp_mac, 3); + + if (efuse_crc != calc_crc) + use_default = 1; + + if (!use_default) { + version = (efuse[1] >> EFUSE_VERSION_S) & EFUSE_VERSION_V; + + if (version == EFUSE_VERSION_1 || version == EFUSE_VERSION_2) { + tmp_mac[0] = mac[5]; + tmp_mac[1] = mac[4]; + tmp_mac[2] = mac[3]; + tmp_mac[3] = efuse[1] >> 16; + + efuse_crc = efuse[0] >> 16; + calc_crc = esp_crc8(tmp_mac, 4); + + if (efuse_crc != calc_crc) + use_default = 1; + } + } + } + + if (use_default) { + mac[0] = 0x18; + mac[1] = 0xFE; + mac[2] = 0x34; + } + + return ESP_OK; +} + +static const char *BACKUP_MAC_NAMESPACE = "backup_mac"; +static const char *BACKUP_MAC_DATA_KEY = "backup_mac_data"; +#define MAC_DATA_LEN_WITH_CRC (4*4) + +static esp_err_t load_backup_mac_data(uint8_t *mac) +{ + esp_err_t err; + nvs_handle handle; + uint32_t efuse[4]; + uint8_t efuse_crc = 0; + uint8_t calc_crc = 0; + uint8_t version; + + if (mac == NULL) { + ESP_LOGE(TAG, "mac address param is NULL"); + return ESP_ERR_INVALID_ARG; + } + + err = nvs_open(BACKUP_MAC_NAMESPACE, NVS_READONLY, &handle); + + if (err == ESP_ERR_NVS_NOT_INITIALIZED) { + ESP_LOGE(TAG, "%s: NVS has not been initialized. " + "Call nvs_flash_init before starting WiFi/BT.", __func__); + return ESP_ERR_INVALID_MAC; + } else if (err != ESP_OK) { + ESP_LOGD(TAG, "%s: failed to open NVS namespace (0x%x)", __func__, err); + return ESP_ERR_INVALID_MAC; + } + + size_t length = MAC_DATA_LEN_WITH_CRC; + err = nvs_get_blob(handle, BACKUP_MAC_DATA_KEY, efuse, &length); + if (err != ESP_OK) { + ESP_LOGD(TAG, "%s: failed to get backup mac (0x%x)", __func__, err); + return ESP_ERR_INVALID_MAC; + } + if (length != MAC_DATA_LEN_WITH_CRC) { + ESP_LOGD(TAG, "%s: invalid length of backup mac (%d)", __func__, length); + return ESP_ERR_INVALID_MAC; + } + nvs_close(handle); + + mac[3] = efuse[1] >> 8; + mac[4] = efuse[1]; + mac[5] = efuse[0] >> 24; + + if (efuse[2] & EFUSE_IS_48BITS_MAC) { + uint8_t tmp_mac[4]; + + mac[0] = efuse[3] >> 16; + mac[1] = efuse[3] >> 8; + mac[2] = efuse[3]; + + tmp_mac[0] = mac[2]; + tmp_mac[1] = mac[1]; + tmp_mac[2] = mac[0]; + + efuse_crc = efuse[2] >> 24; + calc_crc = esp_crc8(tmp_mac, 3); + + if (efuse_crc != calc_crc) { + ESP_LOGE(TAG, "High MAC CRC error, efuse_crc = 0x%02x; calc_crc = 0x%02x", efuse_crc, calc_crc); + return ESP_ERR_INVALID_MAC; + } + + version = (efuse[1] >> EFUSE_VERSION_S) & EFUSE_VERSION_V; + + if (version == EFUSE_VERSION_1 || version == EFUSE_VERSION_2) { + tmp_mac[0] = mac[5]; + tmp_mac[1] = mac[4]; + tmp_mac[2] = mac[3]; + tmp_mac[3] = efuse[1] >> 16; + + efuse_crc = efuse[0] >> 16; + calc_crc = esp_crc8(tmp_mac, 4); + + if (efuse_crc != calc_crc) { + ESP_LOGE(TAG, "CRC8 error, efuse_crc = 0x%02x; calc_crc = 0x%02x", efuse_crc, calc_crc); + return ESP_ERR_INVALID_MAC; + } + } + } else { + mac[0] = 0x18; + mac[1] = 0xFE; + mac[2] = 0x34; + } + + return ESP_OK; +} + +static esp_err_t store_backup_mac_data(void) +{ + esp_err_t err; + nvs_handle handle; + uint32_t efuse[4]; + efuse[0] = REG_READ(EFUSE_DATA0_REG); + efuse[1] = REG_READ(EFUSE_DATA1_REG); + efuse[2] = REG_READ(EFUSE_DATA2_REG); + efuse[3] = REG_READ(EFUSE_DATA3_REG); + + err = nvs_open(BACKUP_MAC_NAMESPACE, NVS_READWRITE, &handle); + + if (err != ESP_OK) { + ESP_LOGD(TAG, "%s: failed to open NVS namespace (0x%x)", __func__, err); + return err; + } + + err = nvs_set_blob(handle, BACKUP_MAC_DATA_KEY, efuse, MAC_DATA_LEN_WITH_CRC); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: store backup mac data failed(0x%x)\n", __func__, err); + return err; + } + + err = nvs_commit(handle); + + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: store backup mac data failed(0x%x)\n", __func__, err); + } + + return err; +} + +esp_err_t esp_derive_mac(uint8_t* local_mac, const uint8_t* universal_mac) +{ + uint8_t idx; + + if (local_mac == NULL || universal_mac == NULL) { + ESP_LOGE(TAG, "mac address param is NULL"); + return ESP_ERR_INVALID_ARG; + } + + memcpy(local_mac, universal_mac, 6); + for (idx = 0; idx < 64; idx++) { + local_mac[0] = universal_mac[0] | 0x02; + local_mac[0] ^= idx << 2; + + if (memcmp(local_mac, universal_mac, 6)) { + break; + } + } + + return ESP_OK; +} + +esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type) +{ + uint8_t efuse_mac[6]; + + if (mac == NULL) { + ESP_LOGE(TAG, "mac address param is NULL"); + return ESP_ERR_INVALID_ARG; + } + + if (type < ESP_MAC_WIFI_STA || type > ESP_MAC_WIFI_SOFTAP) { + ESP_LOGE(TAG, "mac type is incorrect"); + return ESP_ERR_INVALID_ARG; + } + + if (esp_base_mac_addr_get(efuse_mac) != ESP_OK) { + if (load_backup_mac_data(efuse_mac) != ESP_OK) { + if (esp_efuse_mac_get_default(efuse_mac) != ESP_OK) { + ESP_LOGE(TAG, "Get mac address error"); + abort(); + } else { + store_backup_mac_data(); + } + } + } + + switch (type) { + case ESP_MAC_WIFI_STA: + memcpy(mac, efuse_mac, 6); + break; + case ESP_MAC_WIFI_SOFTAP: + esp_derive_mac(mac, efuse_mac); + break; + default: + ESP_LOGW(TAG, "incorrect mac type"); + break; + } + + return ESP_OK; +} + +/** + * Get IDF version + */ +const char* esp_get_idf_version(void) +{ + return IDF_VER; +} + +/** + * @brief Fill an esp_chip_info_t structure with information about the ESP8266 chip + */ +static void get_chip_info_esp8266(esp_chip_info_t* out_info) +{ + memset(out_info, 0, sizeof(*out_info)); + + out_info->model = CHIP_ESP8266; + out_info->revision = 1; + out_info->cores = 1; + out_info->features = CHIP_FEATURE_WIFI_BGN; +} + +/** + * @brief Fill an esp_chip_info_t structure with information about the chip + */ +void esp_chip_info(esp_chip_info_t* out_info) +{ + // Only ESP8266 is supported now, in the future call one of the + // chip-specific functions based on sdkconfig choice + return get_chip_info_esp8266(out_info); +} + +#ifdef MODULE_ESP_IDF_HEAP +/** + * @brief Get the size of available heap. + */ +uint32_t esp_get_free_heap_size(void) +{ + return heap_caps_get_free_size(MALLOC_CAP_32BIT); +} + +/** + * @brief Get the minimum heap that has ever been available + */ +uint32_t esp_get_minimum_free_heap_size(void) +{ + return heap_caps_get_minimum_free_size(MALLOC_CAP_32BIT); +} +#endif /* MODULE_ESP_IDF_HEAP */ diff --git a/cpu/esp8266/vendor/esp-idf/esp8266/source/task_wdt.c b/cpu/esp8266/vendor/esp-idf/esp8266/source/task_wdt.c new file mode 100644 index 000000000000..77c68df155e7 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp8266/source/task_wdt.c @@ -0,0 +1,115 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "esp_log.h" +#include "esp_libc.h" +#include "esp_wifi_osi.h" +#include "esp_task_wdt.h" +#include "portmacro.h" +#include "esp8266/eagle_soc.h" + +static const char *TAG = "wdt"; + +#ifdef CONFIG_TASK_WDT_PANIC +/** + * @brief Task watch dog interrupt function and it should do panic + */ +static void esp_task_wdt_isr(void *param) +{ + /* + * In RIOT-OS, the interrupt from WDT (stage 1) is only used to wakeup + * the system and to execute `sched_run` on the exit from the interrupt + * to schedule the next task which also resets the WDT. + * The system is hard-reset (stage 2), if the system is locked completely. + */ +#ifdef RIOT_VERSION + esp_task_wdt_reset(); +#else + extern void panicHandler(void *frame, int wdt); + + panicHandler(osi_task_top_sp(), 1); +#endif +} +#endif + +/** + * @brief Just for pass compiling and mark wdt calling line + */ +typedef void (* _xt_isr)(void *arg); +extern void _xt_isr_unmask(uint32_t unmask); +extern void _xt_clear_ints(uint32_t mask); +extern void _xt_isr_attach(uint8_t i, _xt_isr func, void *arg); + +esp_err_t esp_task_wdt_init(void) +{ + CLEAR_WDT_REG_MASK(WDT_CTL_ADDRESS, BIT0); + +#ifdef CONFIG_TASK_WDT_PANIC + const uint32_t panic_time_param = 11; + + // Just for soft restart + _xt_clear_ints(1 << ETS_WDT_INUM); + + _xt_isr_attach(ETS_WDT_INUM, esp_task_wdt_isr, NULL); + _xt_isr_unmask(1 << ETS_WDT_INUM); + + WDT_EDGE_INT_ENABLE(); + + ESP_LOGD(TAG, "Enable task watch dog panic, panic time parameter is %u", panic_time_param); +#else + const uint32_t panic_time_param = 1; +#endif + + ESP_LOGD(TAG, "task watch dog trigger time parameter is %u", CONFIG_TASK_WDT_TIMEOUT_S); + + WDT_REG_WRITE(WDT_OP_ADDRESS, CONFIG_TASK_WDT_TIMEOUT_S); // 2^n * 0.8ms, mask 0xf, n = 13 -> (2^13 = 8192) * 0.8 * 0.001 = 6.5536 + WDT_REG_WRITE(WDT_OP_ND_ADDRESS, panic_time_param); // 2^n * 0.8ms, mask 0xf, n = 11 -> (2^11 = 2048) * 0.8 * 0.001 = 1.6384 + + SET_PERI_REG_BITS(PERIPHS_WDT_BASEADDR + WDT_CTL_ADDRESS, WDT_CTL_RSTLEN_MASK, 7 << WDT_CTL_RSTLEN_LSB, 0); + // interrupt then reset + SET_PERI_REG_BITS(PERIPHS_WDT_BASEADDR + WDT_CTL_ADDRESS, WDT_CTL_RSPMOD_MASK, 0 << WDT_CTL_RSPMOD_LSB, 0); + // start task watch dog1 + SET_PERI_REG_BITS(PERIPHS_WDT_BASEADDR + WDT_CTL_ADDRESS, WDT_CTL_EN_MASK, 1 << WDT_CTL_EN_LSB, 0); + + WDT_FEED(); + + return 0; +} + +/** + * @brief Reset(Feed) the Task Watchdog Timer (TWDT) on behalf of the currently + * running task + */ +void esp_task_wdt_reset(void) +{ + WDT_FEED(); +} + +/** + * @brief Just for pass compiling and mark wdt calling line + */ +void pp_soft_wdt_stop(void) +{ + +} + +/** + * @brief Just for pass compiling and mark wdt calling line + */ +void pp_soft_wdt_restart(void) +{ + +} diff --git a/cpu/esp8266/vendor/esp-idf/esp_funcs.c b/cpu/esp8266/vendor/esp-idf/esp_funcs.c new file mode 100644 index 000000000000..a75a7a209783 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/esp_funcs.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2019 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup cpu_esp8266 + * @{ + * + * @file + * @brief ESP function required by SDK + * + * This file is a collection of functions required by ESP8266 RTOS SDK. + * + * @author Gunar Schorcht + */ + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include +#include +#include + +#include "assert.h" +#include "esp/xtensa_ops.h" +#include "esp_attr.h" +#include "esp_err.h" +#include "esp_libc.h" +#include "irq_arch.h" +#include "rom/ets_sys.h" + +#include "xtensa/xtensa_api.h" + +/* Just to satisfy the linker, lwIP from SDK is not used */ +uint32_t LwipTimOutLim = 0; + +#ifndef MODULE_LWIP_ETHERNET +const uint8_t ethbroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +#endif + +void IRAM_ATTR HDL_MAC_SIG_IN_LV1_ISR(void) +{ + extern unsigned int ets_soft_int_type; + ets_soft_int_type = ETS_SOFT_INT_HDL_MAC; + WSR(BIT(ETS_SOFT_INUM), interrupt); +} + +void __attribute__((noreturn)) _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression) +{ + printf("ESP_ERROR_CHECK failed: esp_err_t 0x%x at %p\n", rc, __builtin_return_address(0)); + printf("file: \"%s\" line %d\nfunc: %s\nexpression: %s\n", file, line, function, expression); + abort(); +} + +void IRAM_ATTR _xt_isr_attach(uint8_t i, xt_handler func, void* arg) +{ + DEBUG("%s %d %p\n", __func__, i, func); + xt_set_interrupt_handler(i, func, arg); +} + + +unsigned int IRAM_ATTR _xt_isr_unmask(unsigned int mask) +{ + DEBUG("%s %08x\n", __func__, mask); + return xt_ints_on(mask); +} + +unsigned int IRAM_ATTR _xt_isr_mask(unsigned int mask) +{ + DEBUG("%s %08x\n", __func__, mask); + return xt_ints_off(mask); +} + +void IRAM_ATTR _xt_clear_ints(uint32_t mask) +{ + DEBUG("%s %08x\n", __func__, mask); + xt_set_intclear(mask); +} + +void IRAM_ATTR _xt_set_xt_ccompare_val(void) +{ + /* to figure out whether it is called at all, not yet implemented */ + assert(0); + DEBUG("%s\n", __func__); +} + diff --git a/cpu/esp8266/vendor/esp-idf/heap/include/esp_heap_caps_init.h b/cpu/esp8266/vendor/esp-idf/heap/include/esp_heap_caps_init.h new file mode 100644 index 000000000000..bd134b24b760 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/heap/include/esp_heap_caps_init.h @@ -0,0 +1,31 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize the capability-aware heap allocator. + * + * This is called once in the ESP8266 startup code. Do not call it + * at other times. + */ +void heap_caps_init(void); + +#ifdef __cplusplus +} +#endif diff --git a/cpu/esp8266/vendor/esp-idf/heap/src/Makefile b/cpu/esp8266/vendor/esp-idf/heap/src/Makefile new file mode 100644 index 000000000000..307a079feab6 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/heap/src/Makefile @@ -0,0 +1,3 @@ +MODULE=esp_idf_heap + +include $(RIOTBASE)/Makefile.base diff --git a/cpu/esp8266/vendor/esp-idf/heap/src/esp_heap_caps.c b/cpu/esp8266/vendor/esp-idf/heap/src/esp_heap_caps.c new file mode 100644 index 000000000000..f039baace332 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/heap/src/esp_heap_caps.c @@ -0,0 +1,332 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#define ENABLE_DEBUG (0) + +#include +#include +#include +#include + +#include "esp_heap_caps.h" +#include "esp_heap_port.h" +#include "esp_heap_trace.h" +#include "priv/esp_heap_caps_priv.h" + +#if ENABLE_DEBUG +#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE +#endif + +#include "esp_log.h" + +static const char *TAG = "heap_caps"; +extern heap_region_t g_heap_region[HEAP_REGIONS_MAX]; + +/** + * @brief Initialize regions of memory to the collection of heaps at runtime. + */ +void esp_heap_caps_init_region(heap_region_t *region, size_t max_num) +{ + uint8_t num; + mem_blk_t *mem_start, *mem_end; + + for (num = 0; num < max_num; num++) { + mem_start = (mem_blk_t *)HEAP_ALIGN(region[num].start_addr); + mem_end = (mem_blk_t *)(HEAP_ALIGN(region[num].start_addr + region[num].total_size)); + if ((uint8_t *)mem_end != region[num].start_addr + region[num].total_size) + mem_end = (mem_blk_t *)((uint8_t *)mem_end - sizeof(void *)); + mem_end = (mem_blk_t *)((uint8_t *)mem_end - MEM_HEAD_SIZE); + + ESP_EARLY_LOGV(TAG, "heap %d start from %p to %p total %d bytes, mem_blk from %p to %p total", + num, region[num].start_addr, region[num].start_addr + region[num].total_size, + region[num].total_size, mem_start, mem_end); + + mem_start->prev = NULL; + mem_start->next = mem_end; + + mem_end->prev = mem_start; + mem_end->next = NULL; + + g_heap_region[num].free_blk = mem_start; + g_heap_region[num].min_free_bytes = g_heap_region[num].free_bytes = blk_link_size(mem_start); + } +} + +/** + * @brief Get the total free size of all the regions that have the given capabilities + */ +size_t heap_caps_get_free_size(uint32_t caps) +{ + size_t bytes = 0; + + for (int i = 0; i < HEAP_REGIONS_MAX; i++) + if (caps == (caps & g_heap_region[i].caps)) + bytes += g_heap_region[i].free_bytes; + + return bytes; +} + +/** + * @brief Get the total minimum free memory of all regions with the given capabilities + */ +size_t heap_caps_get_minimum_free_size(uint32_t caps) +{ + size_t bytes = 0; + + for (int i = 0; i < HEAP_REGIONS_MAX; i++) + if (caps == (caps & g_heap_region[i].caps)) + bytes += g_heap_region[i].min_free_bytes; + + return bytes; +} + +/** + * @brief Allocate a chunk of memory which has the given capabilities + */ +void *_heap_caps_malloc(size_t size, uint32_t caps, const char *file, size_t line) +{ + mem_blk_t *mem_blk, *next_mem_blk; + void *ret_mem = NULL; + uint32_t num; + uint32_t mem_blk_size; + + if (line == 0) { + ESP_EARLY_LOGV(TAG, "caller func %p", file); + } else { + ESP_EARLY_LOGV(TAG, "caller file %s line %d", file, line); + } + + for (num = 0; num < HEAP_REGIONS_MAX; num++) { + bool trace; + size_t head_size; + + if ((g_heap_region[num].caps & caps) != caps) + continue; + + _heap_caps_lock(num); + + trace = heap_trace_is_on(); + + mem_blk_size = ptr2memblk_size(size, trace); + + ESP_EARLY_LOGV(TAG, "malloc size is %d(%x) blk size is %d(%x) region is %d", size, size, + mem_blk_size, mem_blk_size, num); + + if (mem_blk_size > g_heap_region[num].free_bytes) + goto next_region; + + mem_blk = (mem_blk_t *)g_heap_region[num].free_blk; + + ESP_EARLY_LOGV(TAG, "malloc start %p", mem_blk); + + while (mem_blk && !mem_blk_is_end(mem_blk) && (mem_blk_is_used(mem_blk) || blk_link_size(mem_blk) < mem_blk_size)) { + ESP_EARLY_LOGV(TAG, "malloc mem_blk %p next %p used %x traced %x, size %d", mem_blk, mem_blk_next(mem_blk), + mem_blk_is_used(mem_blk), mem_blk_is_traced(mem_blk), blk_link_size(mem_blk)); + mem_blk = mem_blk_next(mem_blk); + } + + ESP_EARLY_LOGV(TAG, "malloc end %p, end %d", mem_blk, mem_blk_is_end(mem_blk)); + + if (!mem_blk || mem_blk_is_end(mem_blk)) + goto next_region; + + ret_mem = blk2ptr(mem_blk, trace); + ESP_EARLY_LOGV(TAG, "ret_mem is %p", ret_mem); + + head_size = mem_blk_head_size(trace); + + if (blk_link_size(mem_blk) >= mem_blk_size + head_size + MEM_BLK_MIN) + next_mem_blk = (mem_blk_t *)((uint8_t *)mem_blk + mem_blk_size); + else + next_mem_blk = mem_blk_next(mem_blk); + + ESP_EARLY_LOGV(TAG, "next_mem_blk is %p", next_mem_blk); + + if (mem_blk_next(mem_blk) != next_mem_blk) { + next_mem_blk->prev = next_mem_blk->next = NULL; + + mem_blk_set_prev(next_mem_blk, mem_blk); + mem_blk_set_next(next_mem_blk, mem_blk_next(mem_blk)); + + ESP_EARLY_LOGV(TAG, "mem_blk1 %p, mem_blk->prev %p(%p), mem_blk->next %p(%p)", mem_blk, mem_blk_prev(mem_blk), + mem_blk->prev, mem_blk_next(mem_blk), mem_blk->next); + + mem_blk_set_prev(mem_blk_next(mem_blk), next_mem_blk); + mem_blk_set_next(mem_blk, next_mem_blk); + } + + mem_blk_set_used(mem_blk); + if (trace) { + mem_blk_set_traced((mem2_blk_t *)mem_blk, file, line); + ESP_EARLY_LOGV(TAG, "mem_blk1 %p set trace", mem_blk); + } + + if (g_heap_region[num].free_blk == mem_blk) { + mem_blk_t *free_blk = mem_blk; + + while (free_blk && !mem_blk_is_end(free_blk) && mem_blk_is_used(free_blk)) { + free_blk = mem_blk_next(free_blk); + } + + ESP_EARLY_LOGV(TAG, "reset free_blk from %p to %p", g_heap_region[num].free_blk, free_blk); + g_heap_region[num].free_blk = free_blk; + } else { + ESP_EARLY_LOGV(TAG, "free_blk is %p", g_heap_region[num].free_blk); + } + + mem_blk_size = blk_link_size(mem_blk); + g_heap_region[num].free_bytes -= mem_blk_size; + + if (g_heap_region[num].min_free_bytes > g_heap_region[num].free_bytes) + g_heap_region[num].min_free_bytes = g_heap_region[num].free_bytes; + + ESP_EARLY_LOGV(TAG, "mem_blk2 %p, mem_blk->prev %p(%p), mem_blk->next %p(%p)", mem_blk, mem_blk_prev(mem_blk), + mem_blk->prev, mem_blk_next(mem_blk), mem_blk->next); + ESP_EARLY_LOGV(TAG, "next_mem_blk %p, next_mem_blk->prev %p(%p), next_mem_blk->next %p(%p)", next_mem_blk, + mem_blk_prev(next_mem_blk), next_mem_blk->prev, mem_blk_next(next_mem_blk), next_mem_blk->next); + ESP_EARLY_LOGV(TAG, "last_mem_blk %p, last_mem_blk->prev %p(%p), last_mem_blk->next %p(%p)", mem_blk_next(next_mem_blk), + mem_blk_prev(mem_blk_next(next_mem_blk)), mem_blk_next(next_mem_blk)->prev, mem_blk_next(mem_blk_next(next_mem_blk)), mem_blk_next(next_mem_blk)->next); + +next_region: + _heap_caps_unlock(num); + + if (ret_mem) + break; + } + + ESP_EARLY_LOGV(TAG, "malloc return mem %p", ret_mem); + + return ret_mem; +} + +/** + * @brief Free memory previously allocated via heap_caps_(m/c/r/z)alloc(). + */ +void _heap_caps_free(void *ptr, const char *file, size_t line) +{ + int num; + mem_blk_t *mem_blk; + mem_blk_t *tmp, *next, *prev, *last; + + if ((int)line == 0) { + ESP_EARLY_LOGV(TAG, "caller func %p", file); + } else { + ESP_EARLY_LOGV(TAG, "caller file %s line %d", file, line); + } + + if (!ptr) { + ESP_EARLY_LOGE(TAG, "free(ptr=NULL)"); + if ((int)line == 0) { + ESP_EARLY_LOGE(TAG, "caller func %p", file); + } else { + ESP_EARLY_LOGE(TAG, "caller file %s line %d", file, line); + } + return; + } + + num = get_blk_region(ptr); + + if (num >= HEAP_REGIONS_MAX) { + ESP_EARLY_LOGE(TAG, "free(ptr_region=NULL)"); + return; + } + + mem_blk = ptr2blk(ptr, ptr_is_traced(ptr)); + if (!mem_blk_is_used(mem_blk)) { + ESP_EARLY_LOGE(TAG, "%p already freed\n", ptr); + return; + } + + ESP_EARLY_LOGV(TAG, "Free(ptr=%p, mem_blk=%p, region=%d)", ptr, mem_blk, num); + + _heap_caps_lock(num); + + g_heap_region[num].free_bytes += blk_link_size(mem_blk); + + ESP_EARLY_LOGV(TAG, "ptr prev=%p next=%p", mem_blk_prev(mem_blk), mem_blk_next(mem_blk)); + ESP_EARLY_LOGV(TAG, "ptr1 prev->next=%p next->prev=%p", mem_blk_prev(mem_blk) ? mem_blk_next(mem_blk_prev(mem_blk)) : NULL, + mem_blk_prev(mem_blk_next(mem_blk))); + + mem_blk_set_unused(mem_blk); + mem_blk_set_untraced((mem2_blk_t *)mem_blk); + + prev = mem_blk_prev(mem_blk); + next = mem_blk_next(mem_blk); + last = mem_blk_next(next); + + if (prev && !mem_blk_is_used(prev)) { + mem_blk_set_next(prev, next); + mem_blk_set_prev(next, prev); + tmp = prev; + } else + tmp = mem_blk; + + if (last && !mem_blk_is_used(next)) { + mem_blk_set_next(tmp, last); + mem_blk_set_prev(last, tmp); + } + + ESP_EARLY_LOGV(TAG, "ptr2 prev->next=%p next->prev=%p", mem_blk_prev(mem_blk) ? mem_blk_next(mem_blk_prev(mem_blk)) : NULL, + mem_blk_prev(mem_blk_next(mem_blk))); + + if ((uint8_t *)mem_blk < (uint8_t *)g_heap_region[num].free_blk) { + ESP_EARLY_LOGV(TAG, "Free update free block from %p to %p", g_heap_region[num].free_blk, mem_blk); + g_heap_region[num].free_blk = mem_blk; + } + + _heap_caps_unlock(num); +} + +/** + * @brief Allocate a chunk of memory which has the given capabilities. The initialized value in the memory is set to zero. + */ +void *_heap_caps_calloc(size_t count, size_t size, uint32_t caps, const char *file, size_t line) +{ + void *p = _heap_caps_malloc(count * size, caps, file, line); + if (p) + memset(p, 0, count * size); + + return p; +} + +/** + * @brief Reallocate memory previously allocated via heap_caps_(m/c/r/z)alloc(). + */ +void *_heap_caps_realloc(void *mem, size_t newsize, uint32_t caps, const char *file, size_t line) +{ + void *return_addr = (void *)__builtin_return_address(0); + + void *p = _heap_caps_malloc(newsize, caps, file, line); + if (p && mem) { + size_t mem_size = ptr_size(mem); + size_t min = MIN(newsize, mem_size); + + memcpy(p, mem, min); + _heap_caps_free(mem, (char *)return_addr, line); + } + + return p; +} + +/** + * @brief Allocate a chunk of memory which has the given capabilities. The initialized value in the memory is set to zero. + */ +void *_heap_caps_zalloc(size_t size, uint32_t caps, const char *file, size_t line) +{ + void *p = _heap_caps_malloc(size, caps, file, line); + if (p) + memset(p, 0, size); + + return p; +} diff --git a/cpu/esp8266/vendor/esp-idf/heap/src/esp_heap_init.c b/cpu/esp8266/vendor/esp-idf/heap/src/esp_heap_init.c new file mode 100644 index 000000000000..1afa0a9137a9 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/heap/src/esp_heap_init.c @@ -0,0 +1,39 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp_heap_caps.h" + +heap_region_t g_heap_region[HEAP_REGIONS_MAX]; + +/** + * @brief Initialize the capability-aware heap allocator. + */ +void heap_caps_init(void) +{ + extern char _heap_start; + +#ifndef CONFIG_SOC_FULL_ICACHE + extern char _lit4_end; + + g_heap_region[0].start_addr = (uint8_t *)&_lit4_end; + g_heap_region[0].total_size = ((size_t)(0x4010C000 - (uint32_t)&_lit4_end)); + g_heap_region[0].caps = MALLOC_CAP_32BIT; +#endif + + g_heap_region[HEAP_REGIONS_MAX - 1].start_addr = (uint8_t *)&_heap_start; + g_heap_region[HEAP_REGIONS_MAX - 1].total_size = ((size_t)(0x40000000 - (uint32_t)&_heap_start)); + g_heap_region[HEAP_REGIONS_MAX - 1].caps = MALLOC_CAP_8BIT | MALLOC_CAP_32BIT | MALLOC_CAP_DMA; + + esp_heap_caps_init_region(g_heap_region, HEAP_REGIONS_MAX); +} diff --git a/cpu/esp8266/vendor/esp-idf/heap/src/esp_heap_trace.c b/cpu/esp8266/vendor/esp-idf/heap/src/esp_heap_trace.c new file mode 100644 index 000000000000..3b666c5690dc --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/heap/src/esp_heap_trace.c @@ -0,0 +1,146 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "esp_heap_caps.h" +#include "esp_heap_port.h" +#include "esp_heap_trace.h" +#include "priv/esp_heap_caps_priv.h" + +//#define CONFIG_TRACE_ALL +//#define CONFIG_TRACE_MEM_LINK 1 +//#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE + +#include "esp_log.h" + +#ifdef CONFIG_TRACE_ALL +#define HEAP_INFO_STATE " is %s" +#define HEAP_INFO_STATE_PARAM(_p) ,mem_blk_is_used(_p)?"used":"freed" +#else +#define HEAP_INFO_STATE "" +#define HEAP_INFO_STATE_PARAM(_p) +#endif + +#ifdef CONFIG_TRACE_MEM_LINK +#define HEAP_INFO "p %p, prev %p(%p) next %p(%p) size %d"HEAP_INFO_STATE +#define HEAP_INFO_PARAM(_p) (_p),mem_blk_prev(_p),(_p)->prev,mem_blk_next(_p),(_p)->next,blk_link_size(_p)HEAP_INFO_STATE_PARAM(_p) +#else +#define HEAP_INFO "mem @%p size %d"HEAP_INFO_STATE +#define HEAP_INFO_PARAM(_p) (_p),blk_link_size(_p)HEAP_INFO_STATE_PARAM(_p) +#endif + +static const char *TAG = "heap_trace"; +static int s_heap_trace_mode = HEAP_TRACE_NONE; +extern heap_region_t g_heap_region[HEAP_REGIONS_MAX]; + +/** + * @brief Empty function just for passing compiling some place. + */ +esp_err_t heap_trace_init_standalone(heap_trace_record_t *record_buffer, size_t num_records) +{ + return ESP_OK; +} + +/** + * @brief Check if heap trace is on + */ +int heap_trace_is_on(void) +{ + return s_heap_trace_mode == HEAP_TRACE_LEAKS; +} + +/** + * @brief Start heap tracing. All heap allocations will be traced, until heap_trace_stop() is called. + */ +esp_err_t heap_trace_start(heap_trace_mode_t mode) +{ + s_heap_trace_mode = mode; + + return ESP_OK; +} + +/** + * @brief Stop heap tracing. + */ +esp_err_t heap_trace_stop(void) +{ + s_heap_trace_mode = HEAP_TRACE_NONE; + + return ESP_OK; +} + +/** + * @brief Resume heap tracing which was previously stopped. + */ +esp_err_t heap_trace_resume(void) +{ + s_heap_trace_mode = HEAP_TRACE_LEAKS; + + return ESP_OK; +} + +/** + * @brief Dump heap trace record data to stdout + */ +void heap_trace_dump(void) +{ + uint8_t num; + mem_blk_t *mem_start, *mem_end, *p; + + for (num = 0; num < HEAP_REGIONS_MAX; num++) { + mem_start = (mem_blk_t *)HEAP_ALIGN(g_heap_region[num].start_addr); + mem_end = (mem_blk_t *)(HEAP_ALIGN(g_heap_region[num].start_addr + g_heap_region[num].total_size)); + if ((uint8_t *)mem_end != g_heap_region[num].start_addr + g_heap_region[num].total_size) + mem_end = (mem_blk_t *)((uint8_t *)mem_end - sizeof(void *)); + mem_end = (mem_blk_t *)((uint8_t *)mem_end - MEM_HEAD_SIZE); + + _heap_caps_lock(num); + + ESP_EARLY_LOGI(TAG, "\r\n\r\n"); + ESP_EARLY_LOGD(TAG, "start %p end %p", mem_start, mem_end); + ESP_EARLY_LOGD(TAG, "free blk %p", g_heap_region[num].free_blk); + ESP_EARLY_LOGD(TAG, "size %d mini size %d", g_heap_region[num].free_bytes, g_heap_region[num].min_free_bytes); + + p = mem_start; + while (p != mem_end) { + if (mem_blk_is_used(p) && mem_blk_is_traced(p)) { + mem2_blk_t *mem2_blk = (mem2_blk_t *)p; + size_t line = mem2_blk_line(mem2_blk); + + if (!line) { + ESP_EARLY_LOGI(TAG, HEAP_INFO " caller func %p", HEAP_INFO_PARAM(p), mem2_blk->file); + } else { + const char *file = rindex(mem2_blk->file, '/'); + if (file) + file++; + else + file = mem2_blk->file; + + ESP_EARLY_LOGI(TAG, HEAP_INFO " caller file %s line %d", HEAP_INFO_PARAM(p), file, line); + } + } +#ifdef CONFIG_TRACE_ALL + else { + ESP_EARLY_LOGI(TAG, HEAP_INFO, HEAP_INFO_PARAM(p)); + } +#endif + p = mem_blk_next(p); + + _heap_caps_feed_wdt(g_heap_region[num].caps & caps); + } + + _heap_caps_unlock(num); + } +} diff --git a/cpu/esp8266/vendor/esp-idf/log/include/esp_log.h b/cpu/esp8266/vendor/esp-idf/log/include/esp_log.h new file mode 100644 index 000000000000..f7a5a2e1a7c7 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/log/include/esp_log.h @@ -0,0 +1,357 @@ +// 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 LOG_ESP_LOG_H +#define LOG_ESP_LOG_H + +#include +#include +#include "sdk_conf.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Log level + * + */ +typedef enum { + ESP_LOG_NONE, /*!< No log output */ + ESP_LOG_ERROR, /*!< Critical errors, software module can not recover on its own */ + ESP_LOG_WARN, /*!< Error conditions from which recovery measures have been taken */ + ESP_LOG_INFO, /*!< Information messages which describe normal flow of events */ + ESP_LOG_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */ + ESP_LOG_VERBOSE /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */ +} esp_log_level_t; + +typedef int (*vprintf_like_t)(const char *, va_list); + +/** + * @brief Set log level for given tag + * + * If logging for given component has already been enabled, changes previous setting. + * + * Note that this function can not raise log level above the level set using + * CONFIG_LOG_DEFAULT_LEVEL setting in menuconfig. + * + * To raise log level above the default one for a given file, define + * LOG_LOCAL_LEVEL to one of the ESP_LOG_* values, before including + * esp_log.h in this file. + * + * @param tag Tag of the log entries to enable. Must be a non-NULL zero terminated string. + * Value "*" resets log level for all tags to the given value. + * + * @param level Selects log level to enable. Only logs at this and lower verbosity + * levels will be shown. + */ +void esp_log_level_set(const char* tag, esp_log_level_t level); + +/** + * @brief Set function used to output log entries + * + * By default, log output goes to UART0. This function can be used to redirect log + * output to some other destination, such as file or network. Returns the original + * log handler, which may be necessary to return output to the previous destination. + * + * @param func new Function used for output. Must have same signature as vprintf. + * + * @return func old Function used for output. + */ +vprintf_like_t esp_log_set_vprintf(vprintf_like_t func); + +/** + * @brief Function which returns timestamp to be used in log output + * + * This function is used in expansion of ESP_LOGx macros. + * In the 2nd stage bootloader, and at early application startup stage + * this function uses CPU cycle counter as time source. Later when + * FreeRTOS scheduler start running, it switches to FreeRTOS tick count. + * + * For now, we ignore millisecond counter overflow. + * + * @return timestamp, in milliseconds + */ +uint32_t esp_log_timestamp(void); + +/** + * @brief Function which returns timestamp to be used in log output + * + * This function uses HW cycle counter and does not depend on OS, + * so it can be safely used after application crash. + * + * @return timestamp, in milliseconds + */ +uint32_t esp_log_early_timestamp(void); + +/** + * @brief Write message into the log + * + * This function is not intended to be used directly. Instead, use one of + * ESP_LOGE, ESP_LOGW, ESP_LOGI, ESP_LOGD, ESP_LOGV macros. + * + * This function or these macros should not be used from an interrupt. + */ +void esp_log_write(esp_log_level_t level, const char* tag, const char* format, ...) __attribute__ ((format (printf, 3, 4))); + +#ifndef RIOT_VERSION + +/** @cond */ + +#include "esp_log_internal.h" + +#ifndef LOG_LOCAL_LEVEL +#ifndef BOOTLOADER_BUILD +#define LOG_LOCAL_LEVEL CONFIG_LOG_DEFAULT_LEVEL +#else +#define LOG_LOCAL_LEVEL CONFIG_LOG_BOOTLOADER_LEVEL +#endif +#endif + +/** @endcond */ + +/** + * @brief Log a buffer of hex bytes at specified level, separated into 16 bytes each line. + * + * @param tag description tag + * @param buffer Pointer to the buffer array + * @param buff_len length of buffer in bytes + * @param level level of the log + * + */ +#define ESP_LOG_BUFFER_HEX_LEVEL( tag, buffer, buff_len, level ) \ + do {\ + if ( LOG_LOCAL_LEVEL >= (level) ) { \ + esp_log_buffer_hex_internal( tag, buffer, buff_len, level ); \ + } \ + } while(0) + +/** + * @brief Log a buffer of characters at specified level, separated into 16 bytes each line. Buffer should contain only printable characters. + * + * @param tag description tag + * @param buffer Pointer to the buffer array + * @param buff_len length of buffer in bytes + * @param level level of the log + * + */ +#define ESP_LOG_BUFFER_CHAR_LEVEL( tag, buffer, buff_len, level ) \ + do {\ + if ( LOG_LOCAL_LEVEL >= (level) ) { \ + esp_log_buffer_char_internal( tag, buffer, buff_len, level ); \ + } \ + } while(0) + +/** + * @brief Dump a buffer to the log at specified level. + * + * The dump log shows just like the one below: + * + * W (195) log_example: 0x3ffb4280 45 53 50 33 32 20 69 73 20 67 72 65 61 74 2c 20 |ESP32 is great, | + * W (195) log_example: 0x3ffb4290 77 6f 72 6b 69 6e 67 20 61 6c 6f 6e 67 20 77 69 |working along wi| + * W (205) log_example: 0x3ffb42a0 74 68 20 74 68 65 20 49 44 46 2e 00 |th the IDF..| + * + * It is highly recommend to use terminals with over 102 text width. + * + * @param tag description tag + * @param buffer Pointer to the buffer array + * @param buff_len length of buffer in bytes + * @param level level of the log + */ +#define ESP_LOG_BUFFER_HEXDUMP( tag, buffer, buff_len, level ) \ + do { \ + if ( LOG_LOCAL_LEVEL >= (level) ) { \ + esp_log_buffer_hexdump_internal( tag, buffer, buff_len, level); \ + } \ + } while(0) + +/** + * @brief Log a buffer of hex bytes at Info level + * + * @param tag description tag + * @param buffer Pointer to the buffer array + * @param buff_len length of buffer in bytes + * + * @see ``esp_log_buffer_hex_level`` + * + */ +#define ESP_LOG_BUFFER_HEX(tag, buffer, buff_len) \ + do { \ + if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { \ + ESP_LOG_BUFFER_HEX_LEVEL( tag, buffer, buff_len, ESP_LOG_INFO ); \ + }\ + } while(0) + +/** + * @brief Log a buffer of characters at Info level. Buffer should contain only printable characters. + * + * @param tag description tag + * @param buffer Pointer to the buffer array + * @param buff_len length of buffer in bytes + * + * @see ``esp_log_buffer_char_level`` + * + */ +#define ESP_LOG_BUFFER_CHAR(tag, buffer, buff_len) \ + do { \ + if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { \ + ESP_LOG_BUFFER_CHAR_LEVEL( tag, buffer, buff_len, ESP_LOG_INFO ); \ + }\ + } while(0) + +/** @cond */ + +//to be back compatible +#define esp_log_buffer_hex ESP_LOG_BUFFER_HEX +#define esp_log_buffer_char ESP_LOG_BUFFER_CHAR + + +#if CONFIG_LOG_COLORS +#define LOG_COLOR_BLACK "30" +#define LOG_COLOR_RED "31" +#define LOG_COLOR_GREEN "32" +#define LOG_COLOR_BROWN "33" +#define LOG_COLOR_BLUE "34" +#define LOG_COLOR_PURPLE "35" +#define LOG_COLOR_CYAN "36" +#define LOG_COLOR(COLOR) "\033[0;" COLOR "m" +#define LOG_BOLD(COLOR) "\033[1;" COLOR "m" +#define LOG_RESET_COLOR "\033[0m" +#define LOG_COLOR_E LOG_COLOR(LOG_COLOR_RED) +#define LOG_COLOR_W LOG_COLOR(LOG_COLOR_BROWN) +#define LOG_COLOR_I LOG_COLOR(LOG_COLOR_GREEN) +#define LOG_COLOR_D +#define LOG_COLOR_V +#else //CONFIG_LOG_COLORS +#define LOG_COLOR_E +#define LOG_COLOR_W +#define LOG_COLOR_I +#define LOG_COLOR_D +#define LOG_COLOR_V +#define LOG_RESET_COLOR +#endif //CONFIG_LOG_COLORS + +#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%d) %s: " format LOG_RESET_COLOR "\n" + +/** @endcond */ + +/// macro to output logs in startup code, before heap allocator and syscalls have been initialized. log at ``ESP_LOG_ERROR`` level. @see ``printf``,``ESP_LOGE`` +#define ESP_EARLY_LOGE( tag, format, ... ) ESP_LOG_EARLY_IMPL(tag, format, ESP_LOG_ERROR, E, ##__VA_ARGS__) +/// macro to output logs in startup code at ``ESP_LOG_WARN`` level. @see ``ESP_EARLY_LOGE``,``ESP_LOGE``, ``printf`` +#define ESP_EARLY_LOGW( tag, format, ... ) ESP_LOG_EARLY_IMPL(tag, format, ESP_LOG_WARN, W, ##__VA_ARGS__) +/// macro to output logs in startup code at ``ESP_LOG_INFO`` level. @see ``ESP_EARLY_LOGE``,``ESP_LOGE``, ``printf`` +#define ESP_EARLY_LOGI( tag, format, ... ) ESP_LOG_EARLY_IMPL(tag, format, ESP_LOG_INFO, I, ##__VA_ARGS__) +/// macro to output logs in startup code at ``ESP_LOG_DEBUG`` level. @see ``ESP_EARLY_LOGE``,``ESP_LOGE``, ``printf`` +#define ESP_EARLY_LOGD( tag, format, ... ) ESP_LOG_EARLY_IMPL(tag, format, ESP_LOG_DEBUG, D, ##__VA_ARGS__) +/// macro to output logs in startup code at ``ESP_LOG_VERBOSE`` level. @see ``ESP_EARLY_LOGE``,``ESP_LOGE``, ``printf`` +#define ESP_EARLY_LOGV( tag, format, ... ) ESP_LOG_EARLY_IMPL(tag, format, ESP_LOG_VERBOSE, V, ##__VA_ARGS__) + +#define ESP_LOG_EARLY_IMPL(tag, format, log_level, log_tag_letter, ...) do { \ + if (LOG_LOCAL_LEVEL >= log_level) { \ + ets_printf(LOG_FORMAT(log_tag_letter, format), esp_log_timestamp(), tag, ##__VA_ARGS__); \ + }} while(0) + +#ifndef BOOTLOADER_BUILD +#define ESP_LOGE( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR, tag, format, ##__VA_ARGS__) +#define ESP_LOGW( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_WARN, tag, format, ##__VA_ARGS__) +#define ESP_LOGI( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_INFO, tag, format, ##__VA_ARGS__) +#define ESP_LOGD( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_DEBUG, tag, format, ##__VA_ARGS__) +#define ESP_LOGV( tag, format, ... ) ESP_LOG_LEVEL_LOCAL(ESP_LOG_VERBOSE, tag, format, ##__VA_ARGS__) +#else +/** + * macro to output logs at ESP_LOG_ERROR level. + * + * @param tag tag of the log, which can be used to change the log level by ``esp_log_level_set`` at runtime. + * + * @see ``printf`` + */ +#define ESP_LOGE( tag, format, ... ) ESP_EARLY_LOGE(tag, format, ##__VA_ARGS__) +/// macro to output logs at ``ESP_LOG_WARN`` level. @see ``ESP_LOGE`` +#define ESP_LOGW( tag, format, ... ) ESP_EARLY_LOGW(tag, format, ##__VA_ARGS__) +/// macro to output logs at ``ESP_LOG_INFO`` level. @see ``ESP_LOGE`` +#define ESP_LOGI( tag, format, ... ) ESP_EARLY_LOGI(tag, format, ##__VA_ARGS__) +/// macro to output logs at ``ESP_LOG_DEBUG`` level. @see ``ESP_LOGE`` +#define ESP_LOGD( tag, format, ... ) ESP_EARLY_LOGD(tag, format, ##__VA_ARGS__) +/// macro to output logs at ``ESP_LOG_VERBOSE`` level. @see ``ESP_LOGE`` +#define ESP_LOGV( tag, format, ... ) ESP_EARLY_LOGV(tag, format, ##__VA_ARGS__) +#endif // BOOTLOADER_BUILD + +/** runtime macro to output logs at a specified level. + * + * @param tag tag of the log, which can be used to change the log level by ``esp_log_level_set`` at runtime. + * @param level level of the output log. + * @param format format of the output log. see ``printf`` + * @param ... variables to be replaced into the log. see ``printf`` + * + * @see ``printf`` + */ +#define ESP_LOG_LEVEL(level, tag, format, ...) do { \ + if (level==ESP_LOG_ERROR ) { \ + esp_log_write(ESP_LOG_ERROR, tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } \ + else if (level==ESP_LOG_WARN ) { esp_log_write(ESP_LOG_WARN, tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } \ + else if (level==ESP_LOG_DEBUG ) { esp_log_write(ESP_LOG_DEBUG, tag, LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } \ + else if (level==ESP_LOG_VERBOSE ) { esp_log_write(ESP_LOG_VERBOSE, tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } \ + else { esp_log_write(ESP_LOG_INFO, tag, LOG_FORMAT(I, format), esp_log_timestamp(), tag, ##__VA_ARGS__); } \ + } while(0) + +/** runtime macro to output logs at a specified level. Also check the level with ``LOG_LOCAL_LEVEL``. + * + * @see ``printf``, ``ESP_LOG_LEVEL`` + */ +#define ESP_LOG_LEVEL_LOCAL(level, tag, format, ...) do { \ + if ( LOG_LOCAL_LEVEL >= level ) ESP_LOG_LEVEL(level, tag, format, ##__VA_ARGS__); \ + } while(0) + +#else /* RIOT_VERSION */ + +#include "esp_common.h" + +#ifndef LOG_LOCAL_LEVEL +#define LOG_LOCAL_LEVEL (esp_log_level_t)LOG_LEVEL +#endif + +#define ESP_LOG_LEVEL(level, tag, format, ...) \ + do { \ + if ((esp_log_level_t)level==ESP_LOG_ERROR ) { \ + LOG_TAG(level, E, tag, format, ##__VA_ARGS__); \ + } \ + else if ((esp_log_level_t)level==ESP_LOG_WARN ) { \ + LOG_TAG(level, W, tag, format, ##__VA_ARGS__); \ + } \ + else if ((esp_log_level_t)level==ESP_LOG_INFO ) { \ + LOG_TAG(level, I, tag, format, ##__VA_ARGS__); \ + } \ + else if ((esp_log_level_t)level==ESP_LOG_DEBUG ) { \ + LOG_TAG(level, D, tag, format, ##__VA_ARGS__); \ + } \ + else if ((esp_log_level_t)level==ESP_LOG_VERBOSE ) { \ + LOG_TAG(level, V, tag, format, ##__VA_ARGS__); \ + } \ + } while(0) + +#define ESP_LOG_LEVEL_LOCAL(level, tag, format, ...) \ + do { \ + if ( LOG_LOCAL_LEVEL >= level ) { \ + ESP_LOG_LEVEL(level, tag, format, ##__VA_ARGS__); \ + } \ + } while(0) + +#endif /* RIOT_VERSION */ + +#ifdef __cplusplus +} +#endif + +#endif /* LOG_ESP_LOG_H */ diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/.gitignore b/cpu/esp8266/vendor/esp-idf/nvs_flash/.gitignore new file mode 100644 index 000000000000..3318e40684b2 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/.gitignore @@ -0,0 +1,7 @@ +test_nvs_host/test_nvs +test_nvs_host/coverage_report +test_nvs_host/coverage.info +**/*.gcno +**/*.gcda +**/*.gcov +**/*.o diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/Makefile b/cpu/esp8266/vendor/esp-idf/nvs_flash/Makefile new file mode 100644 index 000000000000..83332d4b1b20 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/Makefile @@ -0,0 +1,9 @@ +MODULE=esp_idf_nvs_flash + +include $(RIOTBASE)/Makefile.base + +CFLAGS += -DESP_PLATFORM +CXXFLAGS += -std=c++11 +INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/log/include +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/nvs_flash/include +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/spi_flash/include diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/Makefile b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/Makefile new file mode 100644 index 000000000000..315ae9edaff2 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/Makefile @@ -0,0 +1,8 @@ +MODULE=esp_idf_nvs_flash + +include $(RIOTBASE)/Makefile.base + +CFLAGS += -DESP_PLATFORM -DNVS_CRC_HEADER_FILE=\"crc.h\" +CXXFLAGS += -std=c++11 +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/nvs_flash/include +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/util/include diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/compressed_enum_table.hpp b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/compressed_enum_table.hpp new file mode 100644 index 000000000000..319d86a45ce5 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/compressed_enum_table.hpp @@ -0,0 +1,79 @@ +// 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 compressed_enum_table_h +#define compressed_enum_table_h + +#include +#include +#include + +template +class CompressedEnumTable +{ +public: + uint32_t* data() + { + return mData; + } + + const uint32_t* data() const + { + return mData; + } + + Tenum get(size_t index) const + { + assert(index >= 0 && index < Nitems); + size_t wordIndex = index / ITEMS_PER_WORD; + size_t offset = (index % ITEMS_PER_WORD) * Nbits; + + return static_cast((mData[wordIndex] >> offset) & VALUE_MASK); + } + + void set(size_t index, Tenum val) + { + assert(index >= 0 && index < Nitems); + size_t wordIndex = index / ITEMS_PER_WORD; + size_t offset = (index % ITEMS_PER_WORD) * Nbits; + + uint32_t v = static_cast(val) << offset; + mData[wordIndex] = (mData[wordIndex] & ~(VALUE_MASK << offset)) | v; + } + + static constexpr size_t getWordIndex(size_t index) + { + return index / ITEMS_PER_WORD; + } + + static constexpr size_t byteSize() + { + return WORD_COUNT * 4; + } + + static constexpr size_t count() + { + return Nitems; + } + + +protected: + static_assert(32 % Nbits == 0, "Nbits must divide 32"); + static const size_t ITEMS_PER_WORD = 32 / Nbits; + static const size_t WORD_COUNT = ( Nbits * Nitems + 31 ) / 32; + static const uint32_t VALUE_MASK = (1 << Nbits) - 1; + uint32_t mData[WORD_COUNT]; +}; + +#endif /* compressed_enum_table_h */ diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/intrusive_list.h b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/intrusive_list.h new file mode 100644 index 000000000000..fc92442cd762 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/intrusive_list.h @@ -0,0 +1,248 @@ +// 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 intrusive_list_h +#define intrusive_list_h + +#include + +template +class intrusive_list; + +template +class intrusive_list_node +{ +protected: + friend class intrusive_list; + T* mPrev = nullptr; + T* mNext = nullptr; +}; + +template +class intrusive_list +{ + typedef intrusive_list_node TNode; + static_assert(std::is_base_of::value, ""); + +public: + + class iterator : public std::iterator + { + public: + + iterator() : mPos(nullptr) {} + + iterator(T* pos) : mPos(pos) {} + + iterator operator++(int) + { + auto result = *this; + mPos = mPos->mNext; + return result; + } + + iterator operator--(int) + { + auto result = *this; + mPos = mPos->mPrev; + return result; + } + + iterator& operator++() + { + mPos = mPos->mNext; + return *this; + } + + iterator& operator--() + { + mPos = mPos->mPrev; + return *this; + } + + + bool operator==(const iterator& other) const + { + return mPos == other.mPos; + } + + bool operator!=(const iterator& other) const + { + return !(*this == other); + } + + T& operator*() + { + return *mPos; + } + + const T& operator*() const + { + return *mPos; + } + + T* operator->() + { + return mPos; + } + + const T* operator->() const + { + return mPos; + } + + operator T*() + { + return mPos; + } + + operator const T*() const + { + return mPos; + } + + + protected: + T* mPos; + }; + + void push_back(T* node) + { + if (mLast) { + mLast->mNext = node; + } + node->mPrev = mLast; + node->mNext = nullptr; + mLast = node; + if (mFirst == nullptr) { + mFirst = node; + } + ++mSize; + } + + void push_front(T* node) + { + node->mPrev = nullptr; + node->mNext = mFirst; + if (mFirst) { + mFirst->mPrev = node; + } + mFirst = node; + if (mLast == nullptr) { + mLast = node; + } + ++mSize; + } + + T& back() + { + return *mLast; + } + + const T& back() const + { + return *mLast; + } + + T& front() + { + return *mFirst; + } + + const T& front() const + { + return *mFirst; + } + + void pop_front() + { + erase(mFirst); + } + + void pop_back() + { + erase(mLast); + } + + void insert(iterator next, T* node) + { + if (static_cast(next) == nullptr) { + push_back(node); + } else { + auto prev = next->mPrev; + if (!prev) { + push_front(node); + } else { + prev->mNext = node; + next->mPrev = node; + node->mNext = next; + node->mPrev = &(*prev); + ++mSize; + } + } + } + + void erase(iterator it) + { + auto prev = it->mPrev; + auto next = it->mNext; + + if (prev) { + prev->mNext = next; + } else { + mFirst = next; + } + if (next) { + next->mPrev = prev; + } else { + mLast = prev; + } + --mSize; + } + + iterator begin() + { + return iterator(mFirst); + } + + iterator end() + { + return iterator(nullptr); + } + + size_t size() const + { + return mSize; + } + + bool empty() const + { + return mSize == 0; + } + + + void clear() + { + while (mFirst) { + erase(mFirst); + } + } + +protected: + T* mFirst = nullptr; + T* mLast = nullptr; + size_t mSize = 0; +}; + + +#endif /* intrusive_list_h */ diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs.hpp b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs.hpp new file mode 100644 index 000000000000..d2f9d3d014cd --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs.hpp @@ -0,0 +1,25 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef nvs_hpp +#define nvs_hpp + + +#include +#include "nvs.h" +#include "nvs_types.hpp" +#include "nvs_page.hpp" +#include "nvs_pagemanager.hpp" +#include "nvs_storage.hpp" + +#endif /* nvs_hpp */ diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_api.cpp b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_api.cpp new file mode 100644 index 000000000000..15f76d1dd290 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_api.cpp @@ -0,0 +1,460 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "nvs.hpp" +#include "nvs_flash.h" +#include "nvs_storage.hpp" +#include "intrusive_list.h" +#include "nvs_platform.hpp" +#include "esp_partition.h" +#include "sdkconfig.h" + +#ifdef ESP_PLATFORM +// Uncomment this line to force output from this module +// #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG +#include "esp_log.h" +static const char* TAG = "nvs"; +#else +#define ESP_LOGD(...) +#endif + +class HandleEntry : public intrusive_list_node +{ + static uint32_t s_nvs_next_handle; +public: + HandleEntry() {} + + HandleEntry(bool readOnly, uint8_t nsIndex, nvs::Storage* StoragePtr) : + mHandle(++s_nvs_next_handle), // Begin the handle value with 1 + mReadOnly(readOnly), + mNsIndex(nsIndex), + mStoragePtr(StoragePtr) + { + } + + nvs_handle mHandle; + uint8_t mReadOnly; + uint8_t mNsIndex; + nvs::Storage* mStoragePtr; +}; + +#ifdef ESP_PLATFORM +SemaphoreHandle_t nvs::Lock::mSemaphore = NULL; +#endif + +using namespace std; +using namespace nvs; + +static intrusive_list s_nvs_handles; +uint32_t HandleEntry::s_nvs_next_handle; +static intrusive_list s_nvs_storage_list; + +static nvs::Storage* lookup_storage_from_name(const char *name) +{ + auto it = find_if(begin(s_nvs_storage_list), end(s_nvs_storage_list), [=](Storage& e) -> bool { + return (strcmp(e.getPartName(), name) == 0); + }); + + if (it == end(s_nvs_storage_list)) { + return NULL; + } + return it; +} + +extern "C" void nvs_dump(const char *partName) +{ + Lock lock; + nvs::Storage* pStorage; + + pStorage = lookup_storage_from_name(partName); + if (pStorage == NULL) { + return; + } + + pStorage->debugDump(); + return; +} + +extern "C" esp_err_t nvs_flash_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount) +{ + ESP_LOGD(TAG, "nvs_flash_init_custom partition=%s start=%d count=%d", partName, baseSector, sectorCount); + nvs::Storage* new_storage = NULL; + nvs::Storage* storage = lookup_storage_from_name(partName); + if (storage == NULL) { + new_storage = new nvs::Storage((const char *)partName); + storage = new_storage; + } + + esp_err_t err = storage->init(baseSector, sectorCount); + if (new_storage != NULL) { + if (err == ESP_OK) { + s_nvs_storage_list.push_back(new_storage); + } else { + delete new_storage; + } + } + return err; +} + +#ifdef ESP_PLATFORM +extern "C" esp_err_t nvs_flash_init_partition(const char *part_name) +{ + Lock::init(); + Lock lock; + nvs::Storage* mStorage; + + mStorage = lookup_storage_from_name(part_name); + if (mStorage) { + return ESP_OK; + } + + const esp_partition_t* partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, part_name); + if (partition == NULL) { + return ESP_ERR_NOT_FOUND; + } + + return nvs_flash_init_custom(part_name, partition->address / SPI_FLASH_SEC_SIZE, + partition->size / SPI_FLASH_SEC_SIZE); +} + +extern "C" esp_err_t nvs_flash_init(void) +{ + return nvs_flash_init_partition(NVS_DEFAULT_PART_NAME); +} + +extern "C" esp_err_t nvs_flash_deinit_partition(const char* partition_name) +{ + Lock::init(); + Lock lock; + + nvs::Storage* storage = lookup_storage_from_name(partition_name); + if (!storage) { + return ESP_ERR_NVS_NOT_INITIALIZED; + } + + /* Clean up handles related to the storage being deinitialized */ + auto it = s_nvs_handles.begin(); + auto next = it; + while(it != s_nvs_handles.end()) { + next++; + if (it->mStoragePtr == storage) { + ESP_LOGD(TAG, "Deleting handle %d (ns=%d) related to partition \"%s\" (missing call to nvs_close?)", + it->mHandle, it->mNsIndex, partition_name); + s_nvs_handles.erase(it); + delete static_cast(it); + } + it = next; + } + + /* Finally delete the storage itself */ + s_nvs_storage_list.erase(storage); + delete storage; + + return ESP_OK; +} + +extern "C" esp_err_t nvs_flash_deinit(void) +{ + return nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME); +} + +extern "C" esp_err_t nvs_flash_erase_partition(const char *part_name) +{ + const esp_partition_t* partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, part_name); + if (partition == NULL) { + return ESP_ERR_NOT_FOUND; + } + + return esp_partition_erase_range(partition, 0, partition->size); +} + +extern "C" esp_err_t nvs_flash_erase() +{ + return nvs_flash_erase_partition(NVS_DEFAULT_PART_NAME); +} +#endif + +static esp_err_t nvs_find_ns_handle(nvs_handle handle, HandleEntry& entry) +{ + auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](HandleEntry& e) -> bool { + return e.mHandle == handle; + }); + if (it == end(s_nvs_handles)) { + return ESP_ERR_NVS_INVALID_HANDLE; + } + entry = *it; + return ESP_OK; +} + +extern "C" esp_err_t nvs_open_from_partition(const char *part_name, const char* name, nvs_open_mode open_mode, nvs_handle *out_handle) +{ + Lock lock; + ESP_LOGD(TAG, "%s %s %d", __func__, name, open_mode); + uint8_t nsIndex; + nvs::Storage* sHandle; + + sHandle = lookup_storage_from_name(part_name); + if (sHandle == NULL) { + return ESP_ERR_NVS_PART_NOT_FOUND; + } + + esp_err_t err = sHandle->createOrOpenNamespace(name, open_mode == NVS_READWRITE, nsIndex); + if (err != ESP_OK) { + return err; + } + + HandleEntry *handle_entry = new HandleEntry(open_mode==NVS_READONLY, nsIndex, sHandle); + s_nvs_handles.push_back(handle_entry); + + *out_handle = handle_entry->mHandle; + + return ESP_OK; +} + +extern "C" esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_handle) +{ + if (s_nvs_storage_list.size() == 0) { + return ESP_ERR_NVS_NOT_INITIALIZED; + } + + return nvs_open_from_partition(NVS_DEFAULT_PART_NAME, name, open_mode, out_handle); +} + +extern "C" void nvs_close(nvs_handle handle) +{ + Lock lock; + ESP_LOGD(TAG, "%s %d", __func__, handle); + auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](HandleEntry& e) -> bool { + return e.mHandle == handle; + }); + if (it == end(s_nvs_handles)) { + return; + } + s_nvs_handles.erase(it); + delete static_cast(it); +} + +extern "C" esp_err_t nvs_erase_key(nvs_handle handle, const char* key) +{ + Lock lock; + ESP_LOGD(TAG, "%s %s\r\n", __func__, key); + HandleEntry entry; + auto err = nvs_find_ns_handle(handle, entry); + if (err != ESP_OK) { + return err; + } + if (entry.mReadOnly) { + return ESP_ERR_NVS_READ_ONLY; + } + return entry.mStoragePtr->eraseItem(entry.mNsIndex, key); +} + +extern "C" esp_err_t nvs_erase_all(nvs_handle handle) +{ + Lock lock; + ESP_LOGD(TAG, "%s\r\n", __func__); + HandleEntry entry; + auto err = nvs_find_ns_handle(handle, entry); + if (err != ESP_OK) { + return err; + } + if (entry.mReadOnly) { + return ESP_ERR_NVS_READ_ONLY; + } + return entry.mStoragePtr->eraseNamespace(entry.mNsIndex); +} + +template +static esp_err_t nvs_set(nvs_handle handle, const char* key, T value) +{ + Lock lock; + ESP_LOGD(TAG, "%s %s %d %d", __func__, key, sizeof(T), (uint32_t) value); + HandleEntry entry; + auto err = nvs_find_ns_handle(handle, entry); + if (err != ESP_OK) { + return err; + } + if (entry.mReadOnly) { + return ESP_ERR_NVS_READ_ONLY; + } + return entry.mStoragePtr->writeItem(entry.mNsIndex, key, value); +} + +extern "C" esp_err_t nvs_set_i8 (nvs_handle handle, const char* key, int8_t value) +{ + return nvs_set(handle, key, value); +} + +extern "C" esp_err_t nvs_set_u8 (nvs_handle handle, const char* key, uint8_t value) +{ + return nvs_set(handle, key, value); +} + +extern "C" esp_err_t nvs_set_i16 (nvs_handle handle, const char* key, int16_t value) +{ + return nvs_set(handle, key, value); +} + +extern "C" esp_err_t nvs_set_u16 (nvs_handle handle, const char* key, uint16_t value) +{ + return nvs_set(handle, key, value); +} + +extern "C" esp_err_t nvs_set_i32 (nvs_handle handle, const char* key, int32_t value) +{ + return nvs_set(handle, key, value); +} + +extern "C" esp_err_t nvs_set_u32 (nvs_handle handle, const char* key, uint32_t value) +{ + return nvs_set(handle, key, value); +} + +extern "C" esp_err_t nvs_set_i64 (nvs_handle handle, const char* key, int64_t value) +{ + return nvs_set(handle, key, value); +} + +extern "C" esp_err_t nvs_set_u64 (nvs_handle handle, const char* key, uint64_t value) +{ + return nvs_set(handle, key, value); +} + +extern "C" esp_err_t nvs_commit(nvs_handle handle) +{ + Lock lock; + // no-op for now, to be used when intermediate cache is added + HandleEntry entry; + return nvs_find_ns_handle(handle, entry); +} + +extern "C" esp_err_t nvs_set_str(nvs_handle handle, const char* key, const char* value) +{ + Lock lock; + ESP_LOGD(TAG, "%s %s %s", __func__, key, value); + HandleEntry entry; + auto err = nvs_find_ns_handle(handle, entry); + if (err != ESP_OK) { + return err; + } + return entry.mStoragePtr->writeItem(entry.mNsIndex, nvs::ItemType::SZ, key, value, strlen(value) + 1); +} + +extern "C" esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, size_t length) +{ + Lock lock; + ESP_LOGD(TAG, "%s %s %d", __func__, key, length); + HandleEntry entry; + auto err = nvs_find_ns_handle(handle, entry); + if (err != ESP_OK) { + return err; + } + return entry.mStoragePtr->writeItem(entry.mNsIndex, nvs::ItemType::BLOB, key, value, length); +} + + +template +static esp_err_t nvs_get(nvs_handle handle, const char* key, T* out_value) +{ + Lock lock; + ESP_LOGD(TAG, "%s %s %d", __func__, key, sizeof(T)); + HandleEntry entry; + auto err = nvs_find_ns_handle(handle, entry); + if (err != ESP_OK) { + return err; + } + return entry.mStoragePtr->readItem(entry.mNsIndex, key, *out_value); +} + +extern "C" esp_err_t nvs_get_i8 (nvs_handle handle, const char* key, int8_t* out_value) +{ + return nvs_get(handle, key, out_value); +} + +extern "C" esp_err_t nvs_get_u8 (nvs_handle handle, const char* key, uint8_t* out_value) +{ + return nvs_get(handle, key, out_value); +} + +extern "C" esp_err_t nvs_get_i16 (nvs_handle handle, const char* key, int16_t* out_value) +{ + return nvs_get(handle, key, out_value); +} + +extern "C" esp_err_t nvs_get_u16 (nvs_handle handle, const char* key, uint16_t* out_value) +{ + return nvs_get(handle, key, out_value); +} + +extern "C" esp_err_t nvs_get_i32 (nvs_handle handle, const char* key, int32_t* out_value) +{ + return nvs_get(handle, key, out_value); +} + +extern "C" esp_err_t nvs_get_u32 (nvs_handle handle, const char* key, uint32_t* out_value) +{ + return nvs_get(handle, key, out_value); +} + +extern "C" esp_err_t nvs_get_i64 (nvs_handle handle, const char* key, int64_t* out_value) +{ + return nvs_get(handle, key, out_value); +} + +extern "C" esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value) +{ + return nvs_get(handle, key, out_value); +} + +static esp_err_t nvs_get_str_or_blob(nvs_handle handle, nvs::ItemType type, const char* key, void* out_value, size_t* length) +{ + Lock lock; + ESP_LOGD(TAG, "%s %s", __func__, key); + HandleEntry entry; + auto err = nvs_find_ns_handle(handle, entry); + if (err != ESP_OK) { + return err; + } + + size_t dataSize; + err = entry.mStoragePtr->getItemDataSize(entry.mNsIndex, type, key, dataSize); + if (err != ESP_OK) { + return err; + } + + if (length == nullptr) { + return ESP_ERR_NVS_INVALID_LENGTH; + } else if (out_value == nullptr) { + *length = dataSize; + return ESP_OK; + } else if (*length < dataSize) { + *length = dataSize; + return ESP_ERR_NVS_INVALID_LENGTH; + } + + *length = dataSize; + return entry.mStoragePtr->readItem(entry.mNsIndex, type, key, out_value, dataSize); +} + +extern "C" esp_err_t nvs_get_str(nvs_handle handle, const char* key, char* out_value, size_t* length) +{ + return nvs_get_str_or_blob(handle, nvs::ItemType::SZ, key, out_value, length); +} + +extern "C" esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size_t* length) +{ + return nvs_get_str_or_blob(handle, nvs::ItemType::BLOB, key, out_value, length); +} + diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_item_hash_list.cpp b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_item_hash_list.cpp new file mode 100644 index 000000000000..845dd091065b --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_item_hash_list.cpp @@ -0,0 +1,107 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "nvs_item_hash_list.hpp" + +namespace nvs +{ + +HashList::HashList() +{ +} + +void HashList::clear() +{ + for (auto it = mBlockList.begin(); it != mBlockList.end();) { + auto tmp = it; + ++it; + mBlockList.erase(tmp); + delete static_cast(tmp); + } +} + +HashList::~HashList() +{ + clear(); +} + +HashList::HashListBlock::HashListBlock() +{ + static_assert(sizeof(HashListBlock) == HashListBlock::BYTE_SIZE, + "cache block size calculation incorrect"); +} + +void HashList::insert(const Item& item, size_t index) +{ + const uint32_t hash_24 = item.calculateCrc32WithoutValue() & 0xffffff; + // add entry to the end of last block if possible + if (mBlockList.size()) { + auto& block = mBlockList.back(); + if (block.mCount < HashListBlock::ENTRY_COUNT) { + block.mNodes[block.mCount++] = HashListNode(hash_24, index); + return; + } + } + // if the above failed, create a new block and add entry to it + HashListBlock* newBlock = new HashListBlock; + mBlockList.push_back(newBlock); + newBlock->mNodes[0] = HashListNode(hash_24, index); + newBlock->mCount++; +} + +void HashList::erase(size_t index, bool itemShouldExist) +{ + for (auto it = mBlockList.begin(); it != mBlockList.end();) { + bool haveEntries = false; + for (size_t i = 0; i < it->mCount; ++i) { + if (it->mNodes[i].mIndex == index) { + it->mNodes[i].mIndex = 0xff; + return; + } + if (it->mNodes[i].mIndex != 0xff) { + haveEntries = true; + } + } + if (!haveEntries) { + auto tmp = it; + ++it; + mBlockList.erase(tmp); + delete static_cast(tmp); + } else { + ++it; + } + } + if (itemShouldExist) { + assert(false && "item should have been present in cache"); + } +} + +size_t HashList::find(size_t start, const Item& item) +{ + const uint32_t hash_24 = item.calculateCrc32WithoutValue() & 0xffffff; + for (auto it = mBlockList.begin(); it != mBlockList.end(); ++it) { + for (size_t index = 0; index < it->mCount; ++index) { + HashListNode& e = it->mNodes[index]; + if (e.mIndex >= start && + e.mHash == hash_24 && + e.mIndex != 0xff) { + return e.mIndex; + } + } + } + return SIZE_MAX; +} + + +} // namespace nvs diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_item_hash_list.hpp b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_item_hash_list.hpp new file mode 100644 index 000000000000..e759cd818a8a --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_item_hash_list.hpp @@ -0,0 +1,74 @@ +// 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 nvs_item_hash_list_h +#define nvs_item_hash_list_h + +#include "nvs.h" +#include "nvs_types.hpp" +#include "intrusive_list.h" + +namespace nvs +{ + +class HashList +{ +public: + HashList(); + ~HashList(); + + void insert(const Item& item, size_t index); + void erase(const size_t index, bool itemShouldExist=true); + size_t find(size_t start, const Item& item); + void clear(); + +private: + HashList(const HashList& other); + const HashList& operator= (const HashList& rhs); + +protected: + + struct HashListNode { + HashListNode() : + mIndex(0xff), mHash(0) + { + } + + HashListNode(uint32_t hash, size_t index) : + mIndex((uint32_t) index), mHash(hash) + { + } + + uint32_t mIndex : 8; + uint32_t mHash : 24; + }; + + struct HashListBlock : public intrusive_list_node { + HashListBlock(); + + static const size_t BYTE_SIZE = 128; + static const size_t ENTRY_COUNT = (BYTE_SIZE - sizeof(intrusive_list_node) - sizeof(size_t)) / 4; + + size_t mCount = 0; + HashListNode mNodes[ENTRY_COUNT]; + }; + + typedef intrusive_list TBlockList; + TBlockList mBlockList; +}; // class HashList + +} // namespace nvs + + +#endif /* nvs_item_hash_list_h */ diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_page.cpp b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_page.cpp new file mode 100644 index 000000000000..efadc1855b52 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_page.cpp @@ -0,0 +1,893 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "nvs_page.hpp" +#if defined(ESP_PLATFORM) +#if defined(NVS_CRC_HEADER_FILE) +#include NVS_CRC_HEADER_FILE +#else +#include +#endif +#else +#include "crc.h" +#endif +#include +#include + +namespace nvs +{ + +uint32_t Page::Header::calculateCrc32() +{ + return crc32_le(0xffffffff, + reinterpret_cast(this) + offsetof(Header, mSeqNumber), + offsetof(Header, mCrc32) - offsetof(Header, mSeqNumber)); +} + +esp_err_t Page::load(uint32_t sectorNumber) +{ + mBaseAddress = sectorNumber * SEC_SIZE; + mUsedEntryCount = 0; + mErasedEntryCount = 0; + + Header header; + auto rc = spi_flash_read(mBaseAddress, &header, sizeof(header)); + if (rc != ESP_OK) { + mState = PageState::INVALID; + return rc; + } + if (header.mState == PageState::UNINITIALIZED) { + mState = header.mState; + // check if the whole page is really empty + // reading the whole page takes ~40 times less than erasing it + uint32_t line[8]; + for (uint32_t i = 0; i < SPI_FLASH_SEC_SIZE; i += sizeof(line)) { + rc = spi_flash_read(mBaseAddress + i, line, sizeof(line)); + if (rc != ESP_OK) { + mState = PageState::INVALID; + return rc; + } + if (std::any_of(line, line + 4, [](uint32_t val) -> bool { return val != 0xffffffff; })) { + // page isn't as empty after all, mark it as corrupted + mState = PageState::CORRUPT; + break; + } + } + } else if (header.mCrc32 != header.calculateCrc32()) { + header.mState = PageState::CORRUPT; + } else { + mState = header.mState; + mSeqNumber = header.mSeqNumber; + } + + switch (mState) { + case PageState::UNINITIALIZED: + break; + + case PageState::FULL: + case PageState::ACTIVE: + case PageState::FREEING: + mLoadEntryTable(); + break; + + default: + mState = PageState::CORRUPT; + break; + } + + return ESP_OK; +} + +esp_err_t Page::writeEntry(const Item& item) +{ + auto rc = spi_flash_write(getEntryAddress(mNextFreeEntry), &item, sizeof(item)); + if (rc != ESP_OK) { + mState = PageState::INVALID; + return rc; + } + + auto err = alterEntryState(mNextFreeEntry, EntryState::WRITTEN); + if (err != ESP_OK) { + return err; + } + + if (mFirstUsedEntry == INVALID_ENTRY) { + mFirstUsedEntry = mNextFreeEntry; + } + + ++mUsedEntryCount; + ++mNextFreeEntry; + + return ESP_OK; +} + +esp_err_t Page::writeEntryData(const uint8_t* data, size_t size) +{ + assert(size % ENTRY_SIZE == 0); + assert(mNextFreeEntry != INVALID_ENTRY); + assert(mFirstUsedEntry != INVALID_ENTRY); + const uint16_t count = size / ENTRY_SIZE; + + const uint8_t* buf = data; + +#ifdef ESP_PLATFORM + /* On the ESP32, data can come from DROM, which is not accessible by spi_flash_write + * function. To work around this, we copy the data to heap if it came from DROM. + * Hopefully this won't happen very often in practice. For data from DRAM, we should + * still be able to write it to flash directly. + * TODO: figure out how to make this platform-specific check nicer (probably by introducing + * a platform-specific flash layer). + */ + if ((uint32_t) data < 0x3ff00000) { + buf = (uint8_t*) malloc(size); + if (!buf) { + return ESP_ERR_NO_MEM; + } + memcpy((void*)buf, data, size); + } +#endif //ESP_PLATFORM + auto rc = spi_flash_write(getEntryAddress(mNextFreeEntry), buf, size); +#ifdef ESP_PLATFORM + if (buf != data) { + free((void*)buf); + } +#endif //ESP_PLATFORM + if (rc != ESP_OK) { + mState = PageState::INVALID; + return rc; + } + auto err = alterEntryRangeState(mNextFreeEntry, mNextFreeEntry + count, EntryState::WRITTEN); + if (err != ESP_OK) { + return err; + } + mUsedEntryCount += count; + mNextFreeEntry += count; + return ESP_OK; +} + +esp_err_t Page::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize) +{ + Item item; + esp_err_t err; + + if (mState == PageState::INVALID) { + return ESP_ERR_NVS_INVALID_STATE; + } + + if (mState == PageState::UNINITIALIZED) { + err = initialize(); + if (err != ESP_OK) { + return err; + } + } + + if (mState == PageState::FULL) { + return ESP_ERR_NVS_PAGE_FULL; + } + + const size_t keySize = strlen(key); + if (keySize > Item::MAX_KEY_LENGTH) { + return ESP_ERR_NVS_KEY_TOO_LONG; + } + + if (dataSize > Page::BLOB_MAX_SIZE) { + return ESP_ERR_NVS_VALUE_TOO_LONG; + } + + size_t totalSize = ENTRY_SIZE; + size_t entriesCount = 1; + if (datatype == ItemType::SZ || datatype == ItemType::BLOB) { + size_t roundedSize = (dataSize + ENTRY_SIZE - 1) & ~(ENTRY_SIZE - 1); + totalSize += roundedSize; + entriesCount += roundedSize / ENTRY_SIZE; + } + + // primitive types should fit into one entry + assert(totalSize == ENTRY_SIZE || datatype == ItemType::BLOB || datatype == ItemType::SZ); + + if (mNextFreeEntry == INVALID_ENTRY || mNextFreeEntry + entriesCount > ENTRY_COUNT) { + // page will not fit this amount of data + return ESP_ERR_NVS_PAGE_FULL; + } + + // write first item + size_t span = (totalSize + ENTRY_SIZE - 1) / ENTRY_SIZE; + item = Item(nsIndex, datatype, span, key); + mHashList.insert(item, mNextFreeEntry); + + if (datatype != ItemType::SZ && datatype != ItemType::BLOB) { + memcpy(item.data, data, dataSize); + item.crc32 = item.calculateCrc32(); + err = writeEntry(item); + if (err != ESP_OK) { + return err; + } + } else { + const uint8_t* src = reinterpret_cast(data); + item.varLength.dataCrc32 = Item::calculateCrc32(src, dataSize); + item.varLength.dataSize = dataSize; + item.varLength.reserved2 = 0xffff; + item.crc32 = item.calculateCrc32(); + err = writeEntry(item); + if (err != ESP_OK) { + return err; + } + + size_t left = dataSize / ENTRY_SIZE * ENTRY_SIZE; + if (left > 0) { + err = writeEntryData(static_cast(data), left); + if (err != ESP_OK) { + return err; + } + } + + size_t tail = dataSize - left; + if (tail > 0) { + std::fill_n(item.rawData, ENTRY_SIZE / 4, 0xffffffff); + memcpy(item.rawData, static_cast(data) + left, tail); + err = writeEntry(item); + if (err != ESP_OK) { + return err; + } + } + + } + return ESP_OK; +} + +esp_err_t Page::readItem(uint8_t nsIndex, ItemType datatype, const char* key, void* data, size_t dataSize) +{ + size_t index = 0; + Item item; + + if (mState == PageState::INVALID) { + return ESP_ERR_NVS_INVALID_STATE; + } + + esp_err_t rc = findItem(nsIndex, datatype, key, index, item); + if (rc != ESP_OK) { + return rc; + } + + if (datatype != ItemType::SZ && datatype != ItemType::BLOB) { + if (dataSize != getAlignmentForType(datatype)) { + return ESP_ERR_NVS_TYPE_MISMATCH; + } + + memcpy(data, item.data, dataSize); + return ESP_OK; + } + + if (dataSize < static_cast(item.varLength.dataSize)) { + return ESP_ERR_NVS_INVALID_LENGTH; + } + + uint8_t* dst = reinterpret_cast(data); + size_t left = item.varLength.dataSize; + for (size_t i = index + 1; i < index + item.span; ++i) { + Item ditem; + rc = readEntry(i, ditem); + if (rc != ESP_OK) { + return rc; + } + size_t willCopy = ENTRY_SIZE; + willCopy = (left < willCopy)?left:willCopy; + memcpy(dst, ditem.rawData, willCopy); + left -= willCopy; + dst += willCopy; + } + if (Item::calculateCrc32(reinterpret_cast(data), item.varLength.dataSize) != item.varLength.dataCrc32) { + rc = eraseEntryAndSpan(index); + if (rc != ESP_OK) { + return rc; + } + return ESP_ERR_NVS_NOT_FOUND; + } + return ESP_OK; +} + +esp_err_t Page::eraseItem(uint8_t nsIndex, ItemType datatype, const char* key) +{ + size_t index = 0; + Item item; + esp_err_t rc = findItem(nsIndex, datatype, key, index, item); + if (rc != ESP_OK) { + return rc; + } + return eraseEntryAndSpan(index); +} + +esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key) +{ + size_t index = 0; + Item item; + return findItem(nsIndex, datatype, key, index, item); +} + +esp_err_t Page::eraseEntryAndSpan(size_t index) +{ + auto state = mEntryTable.get(index); + assert(state == EntryState::WRITTEN || state == EntryState::EMPTY); + + size_t span = 1; + if (state == EntryState::WRITTEN) { + Item item; + auto rc = readEntry(index, item); + if (rc != ESP_OK) { + return rc; + } + if (item.calculateCrc32() != item.crc32) { + mHashList.erase(index, false); + rc = alterEntryState(index, EntryState::ERASED); + --mUsedEntryCount; + ++mErasedEntryCount; + if (rc != ESP_OK) { + return rc; + } + } else { + mHashList.erase(index); + span = item.span; + for (ptrdiff_t i = index + span - 1; i >= static_cast(index); --i) { + if (mEntryTable.get(i) == EntryState::WRITTEN) { + --mUsedEntryCount; + } + ++mErasedEntryCount; + } + if (span == 1) { + rc = alterEntryState(index, EntryState::ERASED); + } else { + rc = alterEntryRangeState(index, index + span, EntryState::ERASED); + } + if (rc != ESP_OK) { + return rc; + } + } + } else { + auto rc = alterEntryState(index, EntryState::ERASED); + if (rc != ESP_OK) { + return rc; + } + } + + if (index == mFirstUsedEntry) { + updateFirstUsedEntry(index, span); + } + + if (index + span > mNextFreeEntry) { + mNextFreeEntry = index + span; + } + + return ESP_OK; +} + +void Page::updateFirstUsedEntry(size_t index, size_t span) +{ + assert(index == mFirstUsedEntry); + mFirstUsedEntry = INVALID_ENTRY; + size_t end = mNextFreeEntry; + if (end > ENTRY_COUNT) { + end = ENTRY_COUNT; + } + for (size_t i = index + span; i < end; ++i) { + if (mEntryTable.get(i) == EntryState::WRITTEN) { + mFirstUsedEntry = i; + break; + } + } +} + +esp_err_t Page::copyItems(Page& other) +{ + if (mFirstUsedEntry == INVALID_ENTRY) { + return ESP_ERR_NVS_NOT_FOUND; + } + + if (other.mState == PageState::UNINITIALIZED) { + auto err = other.initialize(); + if (err != ESP_OK) { + return err; + } + } + + Item entry; + size_t readEntryIndex = mFirstUsedEntry; + + while (readEntryIndex < ENTRY_COUNT) { + + if (mEntryTable.get(readEntryIndex) != EntryState::WRITTEN) { + assert(readEntryIndex != mFirstUsedEntry); + readEntryIndex++; + continue; + } + auto err = readEntry(readEntryIndex, entry); + if (err != ESP_OK) { + return err; + } + + other.mHashList.insert(entry, other.mNextFreeEntry); + err = other.writeEntry(entry); + if (err != ESP_OK) { + return err; + } + size_t span = entry.span; + size_t end = readEntryIndex + span; + + assert(end <= ENTRY_COUNT); + + for (size_t i = readEntryIndex + 1; i < end; ++i) { + readEntry(i, entry); + err = other.writeEntry(entry); + if (err != ESP_OK) { + return err; + } + } + readEntryIndex = end; + + } + return ESP_OK; +} + +esp_err_t Page::mLoadEntryTable() +{ + // for states where we actually care about data in the page, read entry state table + if (mState == PageState::ACTIVE || + mState == PageState::FULL || + mState == PageState::FREEING) { + auto rc = spi_flash_read(mBaseAddress + ENTRY_TABLE_OFFSET, mEntryTable.data(), + mEntryTable.byteSize()); + if (rc != ESP_OK) { + mState = PageState::INVALID; + return rc; + } + } + + mErasedEntryCount = 0; + mUsedEntryCount = 0; + for (size_t i = 0; i < ENTRY_COUNT; ++i) { + auto s = mEntryTable.get(i); + if (s == EntryState::WRITTEN) { + if (mFirstUsedEntry == INVALID_ENTRY) { + mFirstUsedEntry = i; + } + ++mUsedEntryCount; + } else if (s == EntryState::ERASED) { + ++mErasedEntryCount; + } + } + + // for PageState::ACTIVE, we may have more data written to this page + // as such, we need to figure out where the first unused entry is + if (mState == PageState::ACTIVE) { + for (size_t i = 0; i < ENTRY_COUNT; ++i) { + if (mEntryTable.get(i) == EntryState::EMPTY) { + mNextFreeEntry = i; + break; + } + } + + // however, if power failed after some data was written into the entry. + // but before the entry state table was altered, the entry locacted via + // entry state table may actually be half-written. + // this is easy to check by reading EntryHeader (i.e. first word) + while (mNextFreeEntry < ENTRY_COUNT) { + uint32_t entryAddress = getEntryAddress(mNextFreeEntry); + uint32_t header; + auto rc = spi_flash_read(entryAddress, &header, sizeof(header)); + if (rc != ESP_OK) { + mState = PageState::INVALID; + return rc; + } + if (header != 0xffffffff) { + auto oldState = mEntryTable.get(mNextFreeEntry); + auto err = alterEntryState(mNextFreeEntry, EntryState::ERASED); + if (err != ESP_OK) { + mState = PageState::INVALID; + return err; + } + ++mNextFreeEntry; + if (oldState == EntryState::WRITTEN) { + --mUsedEntryCount; + } + ++mErasedEntryCount; + } + else { + break; + } + } + + // check that all variable-length items are written or erased fully + Item item; + size_t lastItemIndex = INVALID_ENTRY; + size_t end = mNextFreeEntry; + if (end > ENTRY_COUNT) { + end = ENTRY_COUNT; + } + size_t span; + for (size_t i = 0; i < end; i += span) { + span = 1; + if (mEntryTable.get(i) == EntryState::ERASED) { + lastItemIndex = INVALID_ENTRY; + continue; + } + + lastItemIndex = i; + + auto err = readEntry(i, item); + if (err != ESP_OK) { + mState = PageState::INVALID; + return err; + } + + if (item.crc32 != item.calculateCrc32()) { + err = eraseEntryAndSpan(i); + if (err != ESP_OK) { + mState = PageState::INVALID; + return err; + } + continue; + } + + mHashList.insert(item, i); + + // search for potential duplicate item + size_t duplicateIndex = mHashList.find(0, item); + + if (item.datatype == ItemType::BLOB || item.datatype == ItemType::SZ) { + span = item.span; + bool needErase = false; + for (size_t j = i; j < i + span; ++j) { + if (mEntryTable.get(j) != EntryState::WRITTEN) { + needErase = true; + lastItemIndex = INVALID_ENTRY; + break; + } + } + if (needErase) { + eraseEntryAndSpan(i); + continue; + } + } + + if (duplicateIndex < i) { + eraseEntryAndSpan(duplicateIndex); + } + } + + // check that last item is not duplicate + if (lastItemIndex != INVALID_ENTRY) { + size_t findItemIndex = 0; + Item dupItem; + if (findItem(item.nsIndex, item.datatype, item.key, findItemIndex, dupItem) == ESP_OK) { + if (findItemIndex < lastItemIndex) { + auto err = eraseEntryAndSpan(findItemIndex); + if (err != ESP_OK) { + mState = PageState::INVALID; + return err; + } + } + } + } + } else if (mState == PageState::FULL || mState == PageState::FREEING) { + // We have already filled mHashList for page in active state. + // Do the same for the case when page is in full or freeing state. + Item item; + for (size_t i = mFirstUsedEntry; i < ENTRY_COUNT; ++i) { + if (mEntryTable.get(i) != EntryState::WRITTEN) { + continue; + } + + auto err = readEntry(i, item); + if (err != ESP_OK) { + mState = PageState::INVALID; + return err; + } + + if (item.crc32 != item.calculateCrc32()) { + err = eraseEntryAndSpan(i); + if (err != ESP_OK) { + mState = PageState::INVALID; + return err; + } + continue; + } + assert(item.span > 0); + + mHashList.insert(item, i); + size_t span = item.span; + + if (item.datatype == ItemType::BLOB || item.datatype == ItemType::SZ) { + for (size_t j = i + 1; j < i + span; ++j) { + if (mEntryTable.get(j) != EntryState::WRITTEN) { + eraseEntryAndSpan(i); + break; + } + } + } + + i += span - 1; + } + + } + + return ESP_OK; +} + + +esp_err_t Page::initialize() +{ + assert(mState == PageState::UNINITIALIZED); + mState = PageState::ACTIVE; + Header header; + header.mState = mState; + header.mSeqNumber = mSeqNumber; + header.mCrc32 = header.calculateCrc32(); + + auto rc = spi_flash_write(mBaseAddress, &header, sizeof(header)); + if (rc != ESP_OK) { + mState = PageState::INVALID; + return rc; + } + + mNextFreeEntry = 0; + std::fill_n(mEntryTable.data(), mEntryTable.byteSize() / sizeof(uint32_t), 0xffffffff); + return ESP_OK; +} + +esp_err_t Page::alterEntryState(size_t index, EntryState state) +{ + assert(index < ENTRY_COUNT); + mEntryTable.set(index, state); + size_t wordToWrite = mEntryTable.getWordIndex(index); + uint32_t word = mEntryTable.data()[wordToWrite]; + auto rc = spi_flash_write(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast(wordToWrite) * 4, + &word, sizeof(word)); + if (rc != ESP_OK) { + mState = PageState::INVALID; + return rc; + } + return ESP_OK; +} + +esp_err_t Page::alterEntryRangeState(size_t begin, size_t end, EntryState state) +{ + assert(end <= ENTRY_COUNT); + assert(end > begin); + size_t wordIndex = mEntryTable.getWordIndex(end - 1); + for (ptrdiff_t i = end - 1; i >= static_cast(begin); --i) { + mEntryTable.set(i, state); + size_t nextWordIndex; + if (i == static_cast(begin)) { + nextWordIndex = (size_t) -1; + } else { + nextWordIndex = mEntryTable.getWordIndex(i - 1); + } + if (nextWordIndex != wordIndex) { + uint32_t word = mEntryTable.data()[wordIndex]; + auto rc = spi_flash_write(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast(wordIndex) * 4, + &word, 4); + if (rc != ESP_OK) { + return rc; + } + } + wordIndex = nextWordIndex; + } + return ESP_OK; +} + +esp_err_t Page::alterPageState(PageState state) +{ + uint32_t state_val = static_cast(state); + auto rc = spi_flash_write(mBaseAddress, &state_val, sizeof(state)); + if (rc != ESP_OK) { + mState = PageState::INVALID; + return rc; + } + mState = (PageState) state; + return ESP_OK; +} + +esp_err_t Page::readEntry(size_t index, Item& dst) const +{ + auto rc = spi_flash_read(getEntryAddress(index), &dst, sizeof(dst)); + if (rc != ESP_OK) { + return rc; + } + return ESP_OK; +} + +esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, size_t &itemIndex, Item& item) +{ + if (mState == PageState::CORRUPT || mState == PageState::INVALID || mState == PageState::UNINITIALIZED) { + return ESP_ERR_NVS_NOT_FOUND; + } + + size_t findBeginIndex = itemIndex; + if (findBeginIndex >= ENTRY_COUNT) { + return ESP_ERR_NVS_NOT_FOUND; + } + + size_t start = mFirstUsedEntry; + if (findBeginIndex > mFirstUsedEntry && findBeginIndex < ENTRY_COUNT) { + start = findBeginIndex; + } + + size_t end = mNextFreeEntry; + if (end > ENTRY_COUNT) { + end = ENTRY_COUNT; + } + + if (nsIndex != NS_ANY && datatype != ItemType::ANY && key != NULL) { + size_t cachedIndex = mHashList.find(start, Item(nsIndex, datatype, 0, key)); + if (cachedIndex < ENTRY_COUNT) { + start = cachedIndex; + } else { + return ESP_ERR_NVS_NOT_FOUND; + } + } + + size_t next; + for (size_t i = start; i < end; i = next) { + next = i + 1; + if (mEntryTable.get(i) != EntryState::WRITTEN) { + continue; + } + + auto rc = readEntry(i, item); + if (rc != ESP_OK) { + mState = PageState::INVALID; + return rc; + } + + auto crc32 = item.calculateCrc32(); + if (item.crc32 != crc32) { + rc = eraseEntryAndSpan(i); + if (rc != ESP_OK) { + mState = PageState::INVALID; + return rc; + } + continue; + } + + if (item.datatype == ItemType::BLOB || item.datatype == ItemType::SZ) { + next = i + item.span; + } + + if (nsIndex != NS_ANY && item.nsIndex != nsIndex) { + continue; + } + + if (key != nullptr && strncmp(key, item.key, Item::MAX_KEY_LENGTH) != 0) { + continue; + } + + if (datatype != ItemType::ANY && item.datatype != datatype) { + return ESP_ERR_NVS_TYPE_MISMATCH; + } + + itemIndex = i; + + return ESP_OK; + } + + return ESP_ERR_NVS_NOT_FOUND; +} + +esp_err_t Page::getSeqNumber(uint32_t& seqNumber) const +{ + if (mState != PageState::UNINITIALIZED && mState != PageState::INVALID && mState != PageState::CORRUPT) { + seqNumber = mSeqNumber; + return ESP_OK; + } + return ESP_ERR_NVS_NOT_INITIALIZED; +} + + +esp_err_t Page::setSeqNumber(uint32_t seqNumber) +{ + if (mState != PageState::UNINITIALIZED) { + return ESP_ERR_NVS_INVALID_STATE; + } + mSeqNumber = seqNumber; + return ESP_OK; +} + +esp_err_t Page::erase() +{ + auto sector = mBaseAddress / SPI_FLASH_SEC_SIZE; + auto rc = spi_flash_erase_sector(sector); + if (rc != ESP_OK) { + mState = PageState::INVALID; + return rc; + } + mUsedEntryCount = 0; + mErasedEntryCount = 0; + mFirstUsedEntry = INVALID_ENTRY; + mNextFreeEntry = INVALID_ENTRY; + mState = PageState::UNINITIALIZED; + mHashList.clear(); + return ESP_OK; +} + +esp_err_t Page::markFreeing() +{ + if (mState != PageState::FULL && mState != PageState::ACTIVE) { + return ESP_ERR_NVS_INVALID_STATE; + } + return alterPageState(PageState::FREEING); +} + +esp_err_t Page::markFull() +{ + if (mState != PageState::ACTIVE) { + return ESP_ERR_NVS_INVALID_STATE; + } + return alterPageState(PageState::FULL); +} + +const char* Page::pageStateToName(PageState ps) +{ + switch (ps) { + case PageState::CORRUPT: + return "CORRUPT"; + + case PageState::ACTIVE: + return "ACTIVE"; + + case PageState::FREEING: + return "FREEING"; + + case PageState::FULL: + return "FULL"; + + case PageState::INVALID: + return "INVALID"; + + case PageState::UNINITIALIZED: + return "UNINITIALIZED"; + + default: + assert(0 && "invalid state value"); + return ""; + } +} + +void Page::debugDump() const +{ + printf("state=%x (%s) addr=%x seq=%d\nfirstUsed=%d nextFree=%d used=%d erased=%d\n", (uint32_t) mState, pageStateToName(mState), mBaseAddress, mSeqNumber, static_cast(mFirstUsedEntry), static_cast(mNextFreeEntry), mUsedEntryCount, mErasedEntryCount); + size_t skip = 0; + for (size_t i = 0; i < ENTRY_COUNT; ++i) { + printf("%3d: ", static_cast(i)); + EntryState state = mEntryTable.get(i); + if (state == EntryState::EMPTY) { + printf("E\n"); + } else if (state == EntryState::ERASED) { + printf("X\n"); + } else if (state == EntryState::WRITTEN) { + Item item; + readEntry(i, item); + if (skip == 0) { + printf("W ns=%2u type=%2u span=%3u key=\"%s\" len=%d\n", item.nsIndex, static_cast(item.datatype), item.span, item.key, (item.span != 1)?((int)item.varLength.dataSize):-1); + if (item.span > 0 && item.span <= ENTRY_COUNT - i) { + skip = item.span - 1; + } else { + skip = 0; + } + } else { + printf("D\n"); + skip--; + } + } + } +} + +} // namespace nvs diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_page.hpp b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_page.hpp new file mode 100644 index 000000000000..413da45894b3 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_page.hpp @@ -0,0 +1,221 @@ +// 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 nvs_page_hpp +#define nvs_page_hpp + +#include "nvs.h" +#include "nvs_types.hpp" +#include +#include +#include +#include +#include "esp_spi_flash.h" +#include "compressed_enum_table.hpp" +#include "intrusive_list.h" +#include "nvs_item_hash_list.hpp" + +namespace nvs +{ + + +class Page : public intrusive_list_node +{ +public: + static const uint32_t PSB_INIT = 0x1; + static const uint32_t PSB_FULL = 0x2; + static const uint32_t PSB_FREEING = 0x4; + static const uint32_t PSB_CORRUPT = 0x8; + + static const uint32_t ESB_WRITTEN = 0x1; + static const uint32_t ESB_ERASED = 0x2; + + static const uint32_t SEC_SIZE = SPI_FLASH_SEC_SIZE; + + static const size_t ENTRY_SIZE = 32; + static const size_t ENTRY_COUNT = 126; + static const uint32_t INVALID_ENTRY = 0xffffffff; + + static const size_t BLOB_MAX_SIZE = ENTRY_SIZE * (ENTRY_COUNT / 2 - 1); + + static const uint8_t NS_INDEX = 0; + static const uint8_t NS_ANY = 255; + + enum class PageState : uint32_t { + // All bits set, default state after flash erase. Page has not been initialized yet. + UNINITIALIZED = 0xffffffff, + + // Page is initialized, and will accept writes. + ACTIVE = UNINITIALIZED & ~PSB_INIT, + + // Page is marked as full and will not accept new writes. + FULL = ACTIVE & ~PSB_FULL, + + // Data is being moved from this page to a new one. + FREEING = FULL & ~PSB_FREEING, + + // Page was found to be in a corrupt and unrecoverable state. + // Instead of being erased immediately, it will be kept for diagnostics and data recovery. + // It will be erased once we run out out free pages. + CORRUPT = FREEING & ~PSB_CORRUPT, + + // Page object wasn't loaded from flash memory + INVALID = 0 + }; + + PageState state() const + { + return mState; + } + + esp_err_t load(uint32_t sectorNumber); + + esp_err_t getSeqNumber(uint32_t& seqNumber) const; + + esp_err_t setSeqNumber(uint32_t seqNumber); + + esp_err_t writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize); + + esp_err_t readItem(uint8_t nsIndex, ItemType datatype, const char* key, void* data, size_t dataSize); + + esp_err_t eraseItem(uint8_t nsIndex, ItemType datatype, const char* key); + + esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key); + + esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, size_t &itemIndex, Item& item); + + template + esp_err_t writeItem(uint8_t nsIndex, const char* key, const T& value) + { + return writeItem(nsIndex, itemTypeOf(value), key, &value, sizeof(value)); + } + + template + esp_err_t readItem(uint8_t nsIndex, const char* key, T& value) + { + return readItem(nsIndex, itemTypeOf(value), key, &value, sizeof(value)); + } + + template + esp_err_t eraseItem(uint8_t nsIndex, const char* key) + { + return eraseItem(nsIndex, itemTypeOf(), key); + } + + size_t getUsedEntryCount() const + { + return mUsedEntryCount; + } + + size_t getErasedEntryCount() const + { + return mErasedEntryCount; + } + + + esp_err_t markFull(); + + esp_err_t markFreeing(); + + esp_err_t copyItems(Page& other); + + esp_err_t erase(); + + void debugDump() const; + +protected: + + class Header + { + public: + Header() + { + std::fill_n(mReserved, sizeof(mReserved)/sizeof(mReserved[0]), UINT32_MAX); + } + + PageState mState; // page state + uint32_t mSeqNumber; // sequence number of this page + uint32_t mReserved[5]; // unused, must be 0xffffffff + uint32_t mCrc32; // crc of everything except mState + + uint32_t calculateCrc32(); + }; + + enum class EntryState { + EMPTY = 0x3, // 0b11, default state after flash erase + WRITTEN = EMPTY & ~ESB_WRITTEN, // entry was written + ERASED = WRITTEN & ~ESB_ERASED, // entry was written and then erased + INVALID = 0x4 // entry is in inconsistent state (write started but ESB_WRITTEN has not been set yet) + }; + + esp_err_t mLoadEntryTable(); + + esp_err_t initialize(); + + esp_err_t alterEntryState(size_t index, EntryState state); + + esp_err_t alterEntryRangeState(size_t begin, size_t end, EntryState state); + + esp_err_t alterPageState(PageState state); + + esp_err_t readEntry(size_t index, Item& dst) const; + + esp_err_t writeEntry(const Item& item); + + esp_err_t writeEntryData(const uint8_t* data, size_t size); + + esp_err_t eraseEntryAndSpan(size_t index); + + void updateFirstUsedEntry(size_t index, size_t span); + + static constexpr size_t getAlignmentForType(ItemType type) + { + return static_cast(type) & 0x0f; + } + + uint32_t getEntryAddress(size_t entry) const + { + assert(entry < ENTRY_COUNT); + return mBaseAddress + ENTRY_DATA_OFFSET + static_cast(entry) * ENTRY_SIZE; + } + + static const char* pageStateToName(PageState ps); + + +protected: + uint32_t mBaseAddress = 0; + PageState mState = PageState::INVALID; + uint32_t mSeqNumber = UINT32_MAX; + typedef CompressedEnumTable TEntryTable; + TEntryTable mEntryTable; + size_t mNextFreeEntry = INVALID_ENTRY; + size_t mFirstUsedEntry = INVALID_ENTRY; + uint16_t mUsedEntryCount = 0; + uint16_t mErasedEntryCount = 0; + + HashList mHashList; + + static const uint32_t HEADER_OFFSET = 0; + static const uint32_t ENTRY_TABLE_OFFSET = HEADER_OFFSET + 32; + static const uint32_t ENTRY_DATA_OFFSET = ENTRY_TABLE_OFFSET + 32; + + static_assert(sizeof(Header) == 32, "header size must be 32 bytes"); + static_assert(ENTRY_TABLE_OFFSET % 32 == 0, "entry table offset should be aligned"); + static_assert(ENTRY_DATA_OFFSET % 32 == 0, "entry data offset should be aligned"); + +}; // class Page + +} // namespace nvs + + +#endif /* nvs_page_hpp */ diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_pagemanager.cpp b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_pagemanager.cpp new file mode 100644 index 000000000000..31240d98b966 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_pagemanager.cpp @@ -0,0 +1,203 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "nvs_pagemanager.hpp" + +namespace nvs +{ +esp_err_t PageManager::load(uint32_t baseSector, uint32_t sectorCount) +{ + mBaseSector = baseSector; + mPageCount = sectorCount; + mPageList.clear(); + mFreePageList.clear(); + mPages.reset(new Page[sectorCount]); + + for (uint32_t i = 0; i < sectorCount; ++i) { + auto err = mPages[i].load(baseSector + i); + if (err != ESP_OK) { + return err; + } + uint32_t seqNumber; + if (mPages[i].getSeqNumber(seqNumber) != ESP_OK) { + mFreePageList.push_back(&mPages[i]); + } else { + auto pos = std::find_if(std::begin(mPageList), std::end(mPageList), [=](const Page& page) -> bool { + uint32_t otherSeqNumber; + return page.getSeqNumber(otherSeqNumber) == ESP_OK && otherSeqNumber > seqNumber; + }); + if (pos == mPageList.end()) { + mPageList.push_back(&mPages[i]); + } else { + mPageList.insert(pos, &mPages[i]); + } + } + } + + if (mPageList.empty()) { + mSeqNumber = 0; + return activatePage(); + } else { + uint32_t lastSeqNo; + ESP_ERROR_CHECK( mPageList.back().getSeqNumber(lastSeqNo) ); + mSeqNumber = lastSeqNo + 1; + } + + // if power went out after a new item for the given key was written, + // but before the old one was erased, we end up with a duplicate item + Page& lastPage = back(); + size_t lastItemIndex = SIZE_MAX; + Item item; + size_t itemIndex = 0; + while (lastPage.findItem(Page::NS_ANY, ItemType::ANY, nullptr, itemIndex, item) == ESP_OK) { + itemIndex += item.span; + lastItemIndex = itemIndex; + } + + if (lastItemIndex != SIZE_MAX) { + auto last = PageManager::TPageListIterator(&lastPage); + for (auto it = begin(); it != last; ++it) { + + if ((it->state() != Page::PageState::FREEING) && + (it->eraseItem(item.nsIndex, item.datatype, item.key) == ESP_OK)) { + break; + } + } + } + + // check if power went out while page was being freed + for (auto it = begin(); it!= end(); ++it) { + if (it->state() == Page::PageState::FREEING) { + Page* newPage = &mPageList.back(); + if (newPage->state() == Page::PageState::ACTIVE) { + auto err = newPage->erase(); + if (err != ESP_OK) { + return err; + } + mPageList.erase(newPage); + mFreePageList.push_back(newPage); + } + auto err = activatePage(); + if (err != ESP_OK) { + return err; + } + newPage = &mPageList.back(); + + err = it->copyItems(*newPage); + if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) { + return err; + } + + err = it->erase(); + if (err != ESP_OK) { + return err; + } + + Page* p = static_cast(it); + mPageList.erase(it); + mFreePageList.push_back(p); + break; + } + } + + // partition should have at least one free page + if (mFreePageList.size() == 0) { + return ESP_ERR_NVS_NO_FREE_PAGES; + } + + return ESP_OK; +} + +esp_err_t PageManager::requestNewPage() +{ + if (mFreePageList.empty()) { + return ESP_ERR_NVS_INVALID_STATE; + } + + // do we have at least two free pages? in that case no erasing is required + if (mFreePageList.size() >= 2) { + return activatePage(); + } + + // find the page with the higest number of erased items + TPageListIterator maxUnusedItemsPageIt; + size_t maxUnusedItems = 0; + for (auto it = begin(); it != end(); ++it) { + + auto unused = Page::ENTRY_COUNT - it->getUsedEntryCount(); + if (unused > maxUnusedItems) { + maxUnusedItemsPageIt = it; + maxUnusedItems = unused; + } + } + + if (maxUnusedItems == 0) { + return ESP_ERR_NVS_NOT_ENOUGH_SPACE; + } + + esp_err_t err = activatePage(); + if (err != ESP_OK) { + return err; + } + + Page* newPage = &mPageList.back(); + + Page* erasedPage = maxUnusedItemsPageIt; + +#ifndef NDEBUG + size_t usedEntries = erasedPage->getUsedEntryCount(); +#endif + err = erasedPage->markFreeing(); + if (err != ESP_OK) { + return err; + } + err = erasedPage->copyItems(*newPage); + if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) { + return err; + } + + err = erasedPage->erase(); + if (err != ESP_OK) { + return err; + } + +#ifndef NDEBUG + assert(usedEntries == newPage->getUsedEntryCount()); +#endif + + mPageList.erase(maxUnusedItemsPageIt); + mFreePageList.push_back(erasedPage); + + return ESP_OK; +} + +esp_err_t PageManager::activatePage() +{ + if (mFreePageList.empty()) { + return ESP_ERR_NVS_NOT_ENOUGH_SPACE; + } + Page* p = &mFreePageList.front(); + if (p->state() == Page::PageState::CORRUPT) { + auto err = p->erase(); + if (err != ESP_OK) { + return err; + } + } + mFreePageList.pop_front(); + mPageList.push_back(p); + p->setSeqNumber(mSeqNumber); + ++mSeqNumber; + return ESP_OK; +} + +} // namespace nvs diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_pagemanager.hpp b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_pagemanager.hpp new file mode 100644 index 000000000000..10c545f0ffc6 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_pagemanager.hpp @@ -0,0 +1,70 @@ +// 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 nvs_pagemanager_hpp +#define nvs_pagemanager_hpp + +#include +#include +#include "nvs_types.hpp" +#include "nvs_page.hpp" +#include "nvs_pagemanager.hpp" +#include "intrusive_list.h" + +namespace nvs +{ +class PageManager +{ + using TPageList = intrusive_list; + using TPageListIterator = TPageList::iterator; +public: + + PageManager() {} + + esp_err_t load(uint32_t baseSector, uint32_t sectorCount); + + TPageListIterator begin() + { + return mPageList.begin(); + } + + TPageListIterator end() + { + return mPageList.end(); + } + + Page& back() + { + return mPageList.back(); + } + + esp_err_t requestNewPage(); + +protected: + friend class Iterator; + + esp_err_t activatePage(); + + TPageList mPageList; + TPageList mFreePageList; + std::unique_ptr mPages; + uint32_t mBaseSector; + uint32_t mPageCount; + uint32_t mSeqNumber; +}; // class PageManager + + +} // namespace nvs + + +#endif /* nvs_pagemanager_hpp */ diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_platform.hpp b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_platform.hpp new file mode 100644 index 000000000000..0973c4875c38 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_platform.hpp @@ -0,0 +1,81 @@ +// 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 nvs_platform_h +#define nvs_platform_h + + +#ifdef ESP_PLATFORM +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" + +namespace nvs +{ + +class Lock +{ +public: + Lock() + { + if (mSemaphore) { + xSemaphoreTake(mSemaphore, portMAX_DELAY); + } + } + + ~Lock() + { + if (mSemaphore) { + xSemaphoreGive(mSemaphore); + } + } + + static esp_err_t init() + { + if (mSemaphore) { + return ESP_OK; + } + mSemaphore = xSemaphoreCreateMutex(); + if (!mSemaphore) { + return ESP_ERR_NO_MEM; + } + return ESP_OK; + } + + static void uninit() + { + if (mSemaphore) { + vSemaphoreDelete(mSemaphore); + } + mSemaphore = nullptr; + } + + static SemaphoreHandle_t mSemaphore; +}; +} // namespace nvs + +#else // ESP_PLATFORM +namespace nvs +{ +class Lock +{ +public: + Lock() { } + ~Lock() { } + static void init() {} + static void uninit() {} +}; +} // namespace nvs +#endif // ESP_PLATFORM + + +#endif /* nvs_platform_h */ diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_storage.cpp b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_storage.cpp new file mode 100644 index 000000000000..f8da28fa242b --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_storage.cpp @@ -0,0 +1,294 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "nvs_storage.hpp" + +#ifndef ESP_PLATFORM +#include +#include +#endif + +namespace nvs +{ + +Storage::~Storage() +{ + clearNamespaces(); +} + +void Storage::clearNamespaces() +{ + for (auto it = std::begin(mNamespaces); it != std::end(mNamespaces); ) { + auto tmp = it; + ++it; + mNamespaces.erase(tmp); + delete static_cast(tmp); + } +} + +esp_err_t Storage::init(uint32_t baseSector, uint32_t sectorCount) +{ + auto err = mPageManager.load(baseSector, sectorCount); + if (err != ESP_OK) { + mState = StorageState::INVALID; + return err; + } + + // load namespaces list + clearNamespaces(); + std::fill_n(mNamespaceUsage.data(), mNamespaceUsage.byteSize() / 4, 0); + for (auto it = mPageManager.begin(); it != mPageManager.end(); ++it) { + Page& p = *it; + size_t itemIndex = 0; + Item item; + while (p.findItem(Page::NS_INDEX, ItemType::U8, nullptr, itemIndex, item) == ESP_OK) { + NamespaceEntry* entry = new NamespaceEntry; + item.getKey(entry->mName, sizeof(entry->mName) - 1); + item.getValue(entry->mIndex); + mNamespaces.push_back(entry); + mNamespaceUsage.set(entry->mIndex, true); + itemIndex += item.span; + } + } + mNamespaceUsage.set(0, true); + mNamespaceUsage.set(255, true); + mState = StorageState::ACTIVE; +#ifndef ESP_PLATFORM + debugCheck(); +#endif + return ESP_OK; +} + +bool Storage::isValid() const +{ + return mState == StorageState::ACTIVE; +} + +esp_err_t Storage::findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item) +{ + for (auto it = std::begin(mPageManager); it != std::end(mPageManager); ++it) { + size_t itemIndex = 0; + auto err = it->findItem(nsIndex, datatype, key, itemIndex, item); + if (err == ESP_OK) { + page = it; + return ESP_OK; + } + } + return ESP_ERR_NVS_NOT_FOUND; +} + +esp_err_t Storage::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize) +{ + if (mState != StorageState::ACTIVE) { + return ESP_ERR_NVS_NOT_INITIALIZED; + } + + Page* findPage = nullptr; + Item item; + auto err = findItem(nsIndex, datatype, key, findPage, item); + if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) { + return err; + } + + Page& page = getCurrentPage(); + err = page.writeItem(nsIndex, datatype, key, data, dataSize); + if (err == ESP_ERR_NVS_PAGE_FULL) { + if (page.state() != Page::PageState::FULL) { + err = page.markFull(); + if (err != ESP_OK) { + return err; + } + } + err = mPageManager.requestNewPage(); + if (err != ESP_OK) { + return err; + } + + err = getCurrentPage().writeItem(nsIndex, datatype, key, data, dataSize); + if (err == ESP_ERR_NVS_PAGE_FULL) { + return ESP_ERR_NVS_NOT_ENOUGH_SPACE; + } + if (err != ESP_OK) { + return err; + } + } else if (err != ESP_OK) { + return err; + } + + if (findPage) { + if (findPage->state() == Page::PageState::UNINITIALIZED || + findPage->state() == Page::PageState::INVALID) { + ESP_ERROR_CHECK( findItem(nsIndex, datatype, key, findPage, item) ); + } + err = findPage->eraseItem(nsIndex, datatype, key); + if (err == ESP_ERR_FLASH_OP_FAIL) { + return ESP_ERR_NVS_REMOVE_FAILED; + } + if (err != ESP_OK) { + return err; + } + } +#ifndef ESP_PLATFORM + debugCheck(); +#endif + return ESP_OK; +} + +esp_err_t Storage::createOrOpenNamespace(const char* nsName, bool canCreate, uint8_t& nsIndex) +{ + if (mState != StorageState::ACTIVE) { + return ESP_ERR_NVS_NOT_INITIALIZED; + } + auto it = std::find_if(mNamespaces.begin(), mNamespaces.end(), [=] (const NamespaceEntry& e) -> bool { + return strncmp(nsName, e.mName, sizeof(e.mName) - 1) == 0; + }); + if (it == std::end(mNamespaces)) { + if (!canCreate) { + return ESP_ERR_NVS_NOT_FOUND; + } + + uint8_t ns; + for (ns = 1; ns < 255; ++ns) { + if (mNamespaceUsage.get(ns) == false) { + break; + } + } + + if (ns == 255) { + return ESP_ERR_NVS_NOT_ENOUGH_SPACE; + } + + auto err = writeItem(Page::NS_INDEX, ItemType::U8, nsName, &ns, sizeof(ns)); + if (err != ESP_OK) { + return err; + } + mNamespaceUsage.set(ns, true); + nsIndex = ns; + + NamespaceEntry* entry = new NamespaceEntry; + entry->mIndex = ns; + strncpy(entry->mName, nsName, sizeof(entry->mName) - 1); + entry->mName[sizeof(entry->mName) - 1] = 0; + mNamespaces.push_back(entry); + + } else { + nsIndex = it->mIndex; + } + return ESP_OK; +} + +esp_err_t Storage::readItem(uint8_t nsIndex, ItemType datatype, const char* key, void* data, size_t dataSize) +{ + if (mState != StorageState::ACTIVE) { + return ESP_ERR_NVS_NOT_INITIALIZED; + } + + Item item; + Page* findPage = nullptr; + auto err = findItem(nsIndex, datatype, key, findPage, item); + if (err != ESP_OK) { + return err; + } + + return findPage->readItem(nsIndex, datatype, key, data, dataSize); +} + +esp_err_t Storage::eraseItem(uint8_t nsIndex, ItemType datatype, const char* key) +{ + if (mState != StorageState::ACTIVE) { + return ESP_ERR_NVS_NOT_INITIALIZED; + } + + Item item; + Page* findPage = nullptr; + auto err = findItem(nsIndex, datatype, key, findPage, item); + if (err != ESP_OK) { + return err; + } + + return findPage->eraseItem(nsIndex, datatype, key); +} + +esp_err_t Storage::eraseNamespace(uint8_t nsIndex) +{ + if (mState != StorageState::ACTIVE) { + return ESP_ERR_NVS_NOT_INITIALIZED; + } + + for (auto it = std::begin(mPageManager); it != std::end(mPageManager); ++it) { + while (true) { + auto err = it->eraseItem(nsIndex, ItemType::ANY, nullptr); + if (err == ESP_ERR_NVS_NOT_FOUND) { + break; + } + else if (err != ESP_OK) { + return err; + } + } + } + return ESP_OK; + +} + +esp_err_t Storage::getItemDataSize(uint8_t nsIndex, ItemType datatype, const char* key, size_t& dataSize) +{ + if (mState != StorageState::ACTIVE) { + return ESP_ERR_NVS_NOT_INITIALIZED; + } + + Item item; + Page* findPage = nullptr; + auto err = findItem(nsIndex, datatype, key, findPage, item); + if (err != ESP_OK) { + return err; + } + + dataSize = item.varLength.dataSize; + return ESP_OK; +} + +void Storage::debugDump() +{ + for (auto p = mPageManager.begin(); p != mPageManager.end(); ++p) { + p->debugDump(); + } +} + +#ifndef ESP_PLATFORM +void Storage::debugCheck() +{ + std::map keys; + + for (auto p = mPageManager.begin(); p != mPageManager.end(); ++p) { + size_t itemIndex = 0; + size_t usedCount = 0; + Item item; + while (p->findItem(Page::NS_ANY, ItemType::ANY, nullptr, itemIndex, item) == ESP_OK) { + std::stringstream keyrepr; + keyrepr << static_cast(item.nsIndex) << "_" << static_cast(item.datatype) << "_" << item.key; + std::string keystr = keyrepr.str(); + if (keys.find(keystr) != std::end(keys)) { + printf("Duplicate key: %s\n", keystr.c_str()); + debugDump(); + assert(0); + } + keys.insert(std::make_pair(keystr, static_cast(p))); + itemIndex += item.span; + usedCount += item.span; + } + assert(usedCount == p->getUsedEntryCount()); + } +} +#endif //ESP_PLATFORM + +} diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_storage.hpp b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_storage.hpp new file mode 100644 index 000000000000..3c0e0c85a5be --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_storage.hpp @@ -0,0 +1,117 @@ +// 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 nvs_storage_hpp +#define nvs_storage_hpp + +#include +#include +#include +#include "nvs.hpp" +#include "nvs_types.hpp" +#include "nvs_page.hpp" +#include "nvs_pagemanager.hpp" + +//extern void dumpBytes(const uint8_t* data, size_t count); + +namespace nvs +{ + +class Storage : public intrusive_list_node +{ + enum class StorageState : uint32_t { + INVALID, + ACTIVE, + }; + + struct NamespaceEntry : public intrusive_list_node { + public: + char mName[Item::MAX_KEY_LENGTH + 1]; + uint8_t mIndex; + }; + + typedef intrusive_list TNamespaces; + +public: + ~Storage(); + + Storage(const char *pName = NVS_DEFAULT_PART_NAME) : mPartitionName(pName) { }; + + esp_err_t init(uint32_t baseSector, uint32_t sectorCount); + + bool isValid() const; + + esp_err_t createOrOpenNamespace(const char* nsName, bool canCreate, uint8_t& nsIndex); + + esp_err_t writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize); + + esp_err_t readItem(uint8_t nsIndex, ItemType datatype, const char* key, void* data, size_t dataSize); + + esp_err_t getItemDataSize(uint8_t nsIndex, ItemType datatype, const char* key, size_t& dataSize); + + esp_err_t eraseItem(uint8_t nsIndex, ItemType datatype, const char* key); + + template + esp_err_t writeItem(uint8_t nsIndex, const char* key, const T& value) + { + return writeItem(nsIndex, itemTypeOf(value), key, &value, sizeof(value)); + } + + template + esp_err_t readItem(uint8_t nsIndex, const char* key, T& value) + { + return readItem(nsIndex, itemTypeOf(value), key, &value, sizeof(value)); + } + + esp_err_t eraseItem(uint8_t nsIndex, const char* key) + { + return eraseItem(nsIndex, ItemType::ANY, key); + } + + esp_err_t eraseNamespace(uint8_t nsIndex); + + const char *getPartName() const + { + return mPartitionName; + } + + void debugDump(); + + void debugCheck(); + + +protected: + + Page& getCurrentPage() + { + return mPageManager.back(); + } + + void clearNamespaces(); + + esp_err_t findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item); + +protected: + const char *mPartitionName; + size_t mPageCount; + PageManager mPageManager; + TNamespaces mNamespaces; + CompressedEnumTable mNamespaceUsage; + StorageState mState = StorageState::INVALID; +}; + +} // namespace nvs + + + +#endif /* nvs_storage_hpp */ diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_test_api.h b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_test_api.h new file mode 100644 index 000000000000..3cf3e7fa1897 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_test_api.h @@ -0,0 +1,50 @@ +// 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. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "nvs_flash.h" + +/** + * @brief Initialize NVS flash storage with custom flash sector layout + * + * @note This API is intended to be used in unit tests. + * + * @param partName Partition name of the NVS partition as per partition table + * @param baseSector Flash sector (units of 4096 bytes) offset to start NVS + * @param sectorCount Length (in flash sectors) of NVS region. + NVS partition must be at least 3 sectors long. + * @return ESP_OK if flash was successfully initialized + */ +esp_err_t nvs_flash_init_custom(const char *partName, uint32_t baseSector, uint32_t sectorCount); + + +/** + * @brief Dump contents of NVS storage to stdout + * + * This function may be used for debugging purposes to inspect the state + * of NVS pages. For each page, list of entries is also dumped. + * + * @param partName Partition name of the NVS partition as per partition table + */ +void nvs_dump(const char *partName); + + +#ifdef __cplusplus +} +#endif diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_types.cpp b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_types.cpp new file mode 100644 index 000000000000..db4841df42f6 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_types.cpp @@ -0,0 +1,56 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "nvs_types.hpp" + +#if defined(ESP_PLATFORM) +#if defined(NVS_CRC_HEADER_FILE) +#include NVS_CRC_HEADER_FILE +#else +#include +#endif +#else +#include "crc.h" +#endif + +namespace nvs +{ +uint32_t Item::calculateCrc32() const +{ + uint32_t result = 0xffffffff; + const uint8_t* p = reinterpret_cast(this); + result = crc32_le(result, p + offsetof(Item, nsIndex), + offsetof(Item, crc32) - offsetof(Item, nsIndex)); + result = crc32_le(result, p + offsetof(Item, key), sizeof(key)); + result = crc32_le(result, p + offsetof(Item, data), sizeof(data)); + return result; +} + +uint32_t Item::calculateCrc32WithoutValue() const +{ + uint32_t result = 0xffffffff; + const uint8_t* p = reinterpret_cast(this); + result = crc32_le(result, p + offsetof(Item, nsIndex), + offsetof(Item, datatype) - offsetof(Item, nsIndex)); + result = crc32_le(result, p + offsetof(Item, key), sizeof(key)); + return result; +} + +uint32_t Item::calculateCrc32(const uint8_t* data, size_t size) +{ + uint32_t result = 0xffffffff; + result = crc32_le(result, data, size); + return result; +} + +} // namespace nvs diff --git a/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_types.hpp b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_types.hpp new file mode 100644 index 000000000000..5306744b5f22 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/nvs_flash/src/nvs_types.hpp @@ -0,0 +1,118 @@ +// 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 nvs_types_h +#define nvs_types_h + +#include +#include +#include +#include +#include +#include "nvs.h" +#include "compressed_enum_table.hpp" + + +namespace nvs +{ + +enum class ItemType : uint8_t { + U8 = 0x01, + I8 = 0x11, + U16 = 0x02, + I16 = 0x12, + U32 = 0x04, + I32 = 0x14, + U64 = 0x08, + I64 = 0x18, + SZ = 0x21, + BLOB = 0x41, + ANY = 0xff +}; + +template::value, void*>::type = nullptr> +constexpr ItemType itemTypeOf() +{ + return static_cast(((std::is_signed::value)?0x10:0x00) | sizeof(T)); +} + +template +constexpr ItemType itemTypeOf(const T&) +{ + return itemTypeOf(); +} + +class Item +{ +public: + union { + struct { + uint8_t nsIndex; + ItemType datatype; + uint8_t span; + uint8_t reserved; + uint32_t crc32; + char key[16]; + union { + struct { + uint16_t dataSize; + uint16_t reserved2; + uint32_t dataCrc32; + } varLength; + uint8_t data[8]; + }; + }; + uint8_t rawData[32]; + }; + + static const size_t MAX_KEY_LENGTH = sizeof(key) - 1; + + Item(uint8_t nsIndex, ItemType datatype, uint8_t span, const char* key_) + : nsIndex(nsIndex), datatype(datatype), span(span), reserved(0xff) + { + std::fill_n(reinterpret_cast(key), sizeof(key) / 4, 0xffffffff); + std::fill_n(reinterpret_cast(data), sizeof(data) / 4, 0xffffffff); + if (key_) { + strncpy(key, key_, sizeof(key) - 1); + key[sizeof(key) - 1] = 0; + } else { + key[0] = 0; + } + } + + Item() + { + } + + uint32_t calculateCrc32() const; + uint32_t calculateCrc32WithoutValue() const; + static uint32_t calculateCrc32(const uint8_t* data, size_t size); + + void getKey(char* dst, size_t dstSize) + { + strncpy(dst, key, (dstSize + void getValue(T& dst) + { + assert(itemTypeOf(dst) == datatype); + dst = *reinterpret_cast(data); + } +}; + +} // namespace nvs + + + +#endif /* nvs_types_h */ diff --git a/cpu/esp8266/vendor/esp-idf/partition_table/gen_esp32part.py b/cpu/esp8266/vendor/esp-idf/partition_table/gen_esp32part.py new file mode 100755 index 000000000000..e789261f272b --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/partition_table/gen_esp32part.py @@ -0,0 +1,389 @@ +#!/usr/bin/env python +# +# ESP32 partition table generation tool +# +# Converts partition tables to/from CSV and binary formats. +# +# See http://esp-idf.readthedocs.io/en/latest/api-guides/partition-tables.html +# for explanation of partition table structure and uses. +# +# 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. +from __future__ import print_function, division +import argparse +import os +import re +import struct +import sys + +MAX_PARTITION_LENGTH = 0xC00 # 3K for partition data (96 entries) leaves 1K in a 4K sector for signature + +__version__ = '1.0' + +quiet = False + +def status(msg): + """ Print status message to stderr """ + if not quiet: + critical(msg) + +def critical(msg): + """ Print critical message to stderr """ + if not quiet: + sys.stderr.write(msg) + sys.stderr.write('\n') + +class PartitionTable(list): + def __init__(self): + super(PartitionTable, self).__init__(self) + + @classmethod + def from_csv(cls, csv_contents): + res = PartitionTable() + lines = csv_contents.splitlines() + + def expand_vars(f): + f = os.path.expandvars(f) + m = re.match(r'(?= MAX_PARTITION_LENGTH: + raise InputError("Binary partition table length (%d) longer than max" % len(result)) + result += b"\xFF" * (MAX_PARTITION_LENGTH - len(result)) # pad the sector, for signing + return result + + def to_csv(self, simple_formatting=False): + rows = [ "# Espressif ESP32 Partition Table", + "# Name, Type, SubType, Offset, Size, Flags" ] + rows += [ x.to_csv(simple_formatting) for x in self ] + return "\n".join(rows) + "\n" + +class PartitionDefinition(object): + APP_TYPE = 0x00 + DATA_TYPE = 0x01 + TYPES = { + "app" : APP_TYPE, + "data" : DATA_TYPE, + } + + # Keep this map in sync with esp_partition_subtype_t enum in esp_partition.h + SUBTYPES = { + APP_TYPE : { + "factory" : 0x00, + "test" : 0x20, + }, + DATA_TYPE : { + "ota" : 0x00, + "phy" : 0x01, + "nvs" : 0x02, + "coredump" : 0x03, + "esphttpd" : 0x80, + "fat" : 0x81, + "spiffs" : 0x82, + }, + } + + MAGIC_BYTES = b"\xAA\x50" + + ALIGNMENT = { + APP_TYPE : 0x1000, + DATA_TYPE : 0x04, + } + + # dictionary maps flag name (as used in CSV flags list, property name) + # to bit set in flags words in binary format + FLAGS = { + "encrypted" : 0 + } + + # add subtypes for the 16 OTA slot values ("ota_XXX, etc.") + for ota_slot in range(16): + SUBTYPES[TYPES["app"]]["ota_%d" % ota_slot] = 0x10 + ota_slot + + def __init__(self): + self.name = "" + self.type = None + self.subtype = None + self.offset = None + self.size = None + self.encrypted = False + + @classmethod + def from_csv(cls, line): + """ Parse a line from the CSV """ + line_w_defaults = line + ",,,," # lazy way to support default fields + fields = [ f.strip() for f in line_w_defaults.split(",") ] + + res = PartitionDefinition() + res.name = fields[0] + res.type = res.parse_type(fields[1]) + res.subtype = res.parse_subtype(fields[2]) + res.offset = res.parse_address(fields[3]) + res.size = res.parse_address(fields[4]) + if res.size is None: + raise InputError("Size field can't be empty") + + flags = fields[5].split(":") + for flag in flags: + if flag in cls.FLAGS: + setattr(res, flag, True) + elif len(flag) > 0: + raise InputError("CSV flag column contains unknown flag '%s'" % (flag)) + + return res + + def __eq__(self, other): + return self.name == other.name and self.type == other.type \ + and self.subtype == other.subtype and self.offset == other.offset \ + and self.size == other.size + + def __repr__(self): + def maybe_hex(x): + return "0x%x" % x if x is not None else "None" + return "PartitionDefinition('%s', 0x%x, 0x%x, %s, %s)" % (self.name, self.type, self.subtype or 0, + maybe_hex(self.offset), maybe_hex(self.size)) + + def __str__(self): + return "Part '%s' %d/%d @ 0x%x size 0x%x" % (self.name, self.type, self.subtype, self.offset or -1, self.size or -1) + + def __cmp__(self, other): + return self.offset - other.offset + + def parse_type(self, strval): + if strval == "": + raise InputError("Field 'type' can't be left empty.") + return parse_int(strval, self.TYPES) + + def parse_subtype(self, strval): + if strval == "": + return 0 # default + return parse_int(strval, self.SUBTYPES.get(self.type, {})) + + def parse_address(self, strval): + if strval == "": + return None # PartitionTable will fill in default + return parse_int(strval) + + def verify(self): + if self.type is None: + raise ValidationError(self, "Type field is not set") + if self.subtype is None: + raise ValidationError(self, "Subtype field is not set") + if self.offset is None: + raise ValidationError(self, "Offset field is not set") + align = self.ALIGNMENT.get(self.type, 4) + if self.offset % align: + raise ValidationError(self, "Offset 0x%x is not aligned to 0x%x" % (self.offset, align)) + if self.size is None: + raise ValidationError(self, "Size field is not set") + + STRUCT_FORMAT = "<2sBBLL16sL" + + @classmethod + def from_binary(cls, b): + if len(b) != 32: + raise InputError("Partition definition length must be exactly 32 bytes. Got %d bytes." % len(b)) + res = cls() + (magic, res.type, res.subtype, res.offset, + res.size, res.name, flags) = struct.unpack(cls.STRUCT_FORMAT, b) + if b"\x00" in res.name: # strip null byte padding from name string + res.name = res.name[:res.name.index(b"\x00")] + res.name = res.name.decode() + if magic != cls.MAGIC_BYTES: + raise InputError("Invalid magic bytes (%r) for partition definition" % magic) + for flag,bit in cls.FLAGS.items(): + if flags & (1< */ -#define ENABLE_DEBUG 0 -#include "debug.h" - -#include "periph_cpu.h" +#include "sdk_conf.h" diff --git a/cpu/esp8266/vendor/esp-idf/spi_flash/Makefile b/cpu/esp8266/vendor/esp-idf/spi_flash/Makefile new file mode 100644 index 000000000000..9f729dce41de --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/spi_flash/Makefile @@ -0,0 +1,5 @@ +MODULE=esp_idf_spi_flash + +include $(RIOTBASE)/Makefile.base + +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/bootloader_support/include diff --git a/cpu/esp8266/vendor/esp-idf/spi_flash/spi_flash.c b/cpu/esp8266/vendor/esp-idf/spi_flash/spi_flash.c new file mode 100644 index 000000000000..9139d59e565d --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/spi_flash/spi_flash.c @@ -0,0 +1,779 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "spi_flash.h" +#include "esp8266/spi_register.h" +#include "esp8266/pin_mux_register.h" +#include "priv/esp_spi_flash_raw.h" + +#include "esp_attr.h" +#include "esp_wifi_osi.h" +#include "esp_system.h" +#include "esp_log.h" +#include "esp_task_wdt.h" +#include "esp_image_format.h" + +#define SPI_FLASH_ISSI_ENABLE_QIO_MODE (BIT(6)) + +/*gd25q32c*/ +#define SPI_FLASH_GD25Q32C_WRITE_STATUSE1_CMD (0X01) +#define SPI_FLASH_GD25Q32C_WRITE_STATUSE2_CMD (0X31) +#define SPI_FLASH_GD25Q32C_WRITE_STATUSE3_CMD (0X11) + +#define SPI_FLASH_GD25Q32C_READ_STATUSE1_CMD (0X05) +#define SPI_FLASH_GD25Q32C_READ_STATUSE2_CMD (0X35) +#define SPI_FLASH_GD25Q32C_READ_STATUSE3_CMD (0X15) + +#define SPI_FLASH_GD25Q32C_QIO_MODE (BIT(1)) + +#define SPI_ISSI_FLASH_WRITE_PROTECT_STATUS (BIT(2)|BIT(3)|BIT(4)|BIT(5)) +#define SPI_EON_25Q16A_WRITE_PROTECT_STATUS (BIT(2)|BIT(3)|BIT(4)|BIT(5)) +#define SPI_EON_25Q16B_WRITE_PROTECT_STATUS (BIT(2)|BIT(3)|BIT(4)|BIT(5)) +#define SPI_GD25Q32_FLASH_WRITE_PROTECT_STATUS (BIT(2)|BIT(3)|BIT(4)|BIT(5)|BIT(6)) +#define SPI_FLASH_RDSR2 0x35 +#define SPI_FLASH_PROTECT_STATUS (BIT(2)|BIT(3)|BIT(4)|BIT(5)|BIT(6)|BIT(14)) + +#ifndef BOOTLOADER_BUILD +#define FLASH_INTR_DECLARE(t) +#define FLASH_INTR_LOCK(t) vPortEnterCritical() +#define FLASH_INTR_UNLOCK(t) vPortExitCritical() +#else +#define FLASH_INTR_DECLARE(t) +#define FLASH_INTR_LOCK(t) +#define FLASH_INTR_UNLOCK(t) +#endif + +#define FLASH_ALIGN_BYTES 4 +#define FLASH_ALIGN(addr) ((((size_t)addr) + (FLASH_ALIGN_BYTES - 1)) & (~(FLASH_ALIGN_BYTES - 1))) +#define FLASH_ALIGN_BEFORE(addr) (FLASH_ALIGN(addr) - 4) +#define NOT_ALIGN(addr) (((size_t)addr) & (FLASH_ALIGN_BYTES - 1)) +#define IS_ALIGN(addr) (NOT_ALIGN(addr) == 0) + +extern void vPortEnterCritical(void); +extern void vPortExitCritical(void); + +esp_spi_flash_chip_t flashchip = { + 0x1640ef, + CONFIG_SPI_FLASH_SIZE, + 64 * 1024, + 4 * 1024, + 256, + 0xffff +}; + +uint8_t FlashIsOnGoing = 0; + +bool spi_user_cmd(spi_cmd_dir_t mode, spi_cmd_t *p_cmd) +{ + bool ret; + FLASH_INTR_DECLARE(c_tmp); + + if ((p_cmd->addr_len != 0 && p_cmd->addr == NULL) + || (p_cmd->data_len != 0 && p_cmd->data == NULL) + || (p_cmd == NULL)) { + return false; + } + + FLASH_INTR_LOCK(c_tmp); + FlashIsOnGoing = 1; + + ret = spi_user_cmd_raw(&flashchip, mode, p_cmd); + + FlashIsOnGoing = 0; + FLASH_INTR_UNLOCK(c_tmp); + + return ret; +} + +bool special_flash_read_status(uint8_t command, uint32_t* status, int len) +{ + bool ret; + spi_cmd_t cmd; + + if( len > 2 || len < 1) { + return false; + } + + cmd.cmd = command; + cmd.cmd_len = 1; + cmd.addr = NULL; + cmd.addr_len = 0; + cmd.dummy_bits = 0; + cmd.data = status; + cmd.data_len = len; + + ret = spi_user_cmd(SPI_RX, &cmd); + + return ret; +} + +bool special_flash_write_status(uint8_t command, uint32_t status, int len, bool write_en) +{ + bool ret; + spi_cmd_t cmd; + + if (len > 2 || len < 1) { + return false; + } + + cmd.cmd = command; + cmd.cmd_len = 1; + cmd.addr = NULL; + cmd.addr_len = 0; + cmd.dummy_bits = 0; + cmd.data = &status; + cmd.data_len = len > 1 ? 2 : 1; + if (write_en) { + ret = spi_user_cmd(SPI_WRSR, &cmd); + } else { + ret = spi_user_cmd(SPI_TX | SPI_RAW, &cmd); + } + + return ret; +} + +uint8_t en25q16x_read_sfdp(void) +{ + spi_cmd_t cmd; + uint32_t addr = 0x00003000; + uint32_t data = 0; + + cmd.cmd = 0x5a; + cmd.cmd_len = 1; + + cmd.addr = &addr; + cmd.addr_len = 3; + cmd.dummy_bits = 8; + + cmd.data = &data; + cmd.data_len = 1; + + spi_user_cmd(SPI_RX, &cmd); + + return ((uint8_t) data); +} + +uint32_t spi_flash_get_id(void) +{ + uint32_t rdid = 0; + FLASH_INTR_DECLARE(c_tmp); + + FLASH_INTR_LOCK(c_tmp); + + FlashIsOnGoing = 1; + + rdid = spi_flash_get_id_raw(&flashchip); + + FlashIsOnGoing = 0; + + FLASH_INTR_UNLOCK(c_tmp); + + return rdid; +} + +esp_err_t spi_flash_read_status(uint32_t *status) +{ + esp_err_t ret; + FLASH_INTR_DECLARE(c_tmp); + + FLASH_INTR_LOCK(c_tmp); + + FlashIsOnGoing = 1; + + ret = spi_flash_read_status_raw(&flashchip, status); + + FlashIsOnGoing = 0; + + FLASH_INTR_UNLOCK(c_tmp); + + return ret; +} + +esp_err_t spi_flash_write_status(uint32_t status_value) +{ + FLASH_INTR_DECLARE(c_tmp); + + FLASH_INTR_LOCK(c_tmp); + + FlashIsOnGoing = 1; + + spi_flash_write_status_raw(&flashchip, status_value); + + FlashIsOnGoing = 0; + + FLASH_INTR_UNLOCK(c_tmp); + + return ESP_OK; +} + +bool spi_flash_check_wr_protect(void) +{ + uint32_t flash_id=spi_flash_get_id(); + uint32_t status=0; + //check for EN25Q16A/B flash chips + if ((flash_id & 0xffffff) == 0x15701c) { + uint8_t sfdp = en25q16x_read_sfdp(); + if (sfdp == 0xE5) { + //This is EN25Q16A, set bit6 in the same way as issi flash chips. + if(spi_flash_read_status(&status)==0) { //Read status Ok + if(status&(SPI_EON_25Q16A_WRITE_PROTECT_STATUS)) { //Write_protect + special_flash_write_status(0x1, status&(~(SPI_EON_25Q16A_WRITE_PROTECT_STATUS)), 1, true); + } + } + } else if (sfdp == 0xED) { + //This is EN25Q16B + if(spi_flash_read_status(&status)==0) { //Read status Ok + if(status&(SPI_EON_25Q16B_WRITE_PROTECT_STATUS)) { //Write_protect + special_flash_write_status(0x1, status&(~(SPI_EON_25Q16B_WRITE_PROTECT_STATUS)), 1, true); + } + } + } + } + //MXIC :0XC2 + //ISSI :0X9D + // ets_printf("spi_flash_check_wr_protect\r\n"); + else if(((flash_id&0xFF)==0X9D)||((flash_id&0xFF)==0XC2)||((flash_id & 0xFF) == 0x1C)) { + if(spi_flash_read_status(&status)==0) { //Read status Ok + if(status&(SPI_ISSI_FLASH_WRITE_PROTECT_STATUS)) { //Write_protect + special_flash_write_status(0x1, status&(~(SPI_ISSI_FLASH_WRITE_PROTECT_STATUS)), 1, true); + } + } + } + //GD25Q32C:0X16409D + //GD25Q128 + else if(((flash_id&0xFFFFFFFF)==0X1640C8)||((flash_id&0xFFFFFFFF)==0X1840C8)) { + if(spi_flash_read_status(&status)==0) { //Read status Ok + if(status&SPI_GD25Q32_FLASH_WRITE_PROTECT_STATUS) { + special_flash_write_status(0x01, status&(~(SPI_GD25Q32_FLASH_WRITE_PROTECT_STATUS)), 1, true); + } + } + } + //Others + else { + if(spi_flash_read_status(&status)==0) { //Read status Ok + uint32_t status1 = 0; //flash_gd25q32c_read_status(GD25Q32C_STATUS2); + special_flash_read_status(SPI_FLASH_RDSR2, &status1, 1); + status=(status1 << 8)|(status & 0xff); + if(status&SPI_FLASH_PROTECT_STATUS) { + status=((status&(~SPI_FLASH_PROTECT_STATUS))&0xffff); + spi_flash_write_status(status); + } + } + } + return true; +} + +static void spi_flash_enable_qio_bit6(void) +{ + uint8_t wrsr_cmd = 0x1; + uint32_t issi_qio = SPI_FLASH_ISSI_ENABLE_QIO_MODE; + special_flash_write_status(wrsr_cmd, issi_qio, 1, true); +} + +static bool spi_flash_issi_enable_QIO_mode(void) +{ + uint32_t status = 0; + if(spi_flash_read_status(&status) == 0) { + if((status&SPI_FLASH_ISSI_ENABLE_QIO_MODE)) { + return true; + } + } + else { + return false; + } + + spi_flash_enable_qio_bit6(); + + if(spi_flash_read_status(&status) == 0) { + if((status&SPI_FLASH_ISSI_ENABLE_QIO_MODE)) { + return true; + } else { + return false; + } + } else { + return false; + } +} + +static uint8_t flash_gd25q32c_read_status(enum GD25Q32C_status status_index) +{ + uint8_t rdsr_cmd=0; + if(GD25Q32C_STATUS1 == status_index) { + rdsr_cmd = SPI_FLASH_GD25Q32C_READ_STATUSE1_CMD; + } + else if(GD25Q32C_STATUS2 == status_index) { + rdsr_cmd = SPI_FLASH_GD25Q32C_READ_STATUSE2_CMD; + } + else if(GD25Q32C_STATUS3 == status_index) { + rdsr_cmd = SPI_FLASH_GD25Q32C_READ_STATUSE3_CMD; + } + else { + + } + uint32_t status; + special_flash_read_status(rdsr_cmd, &status, 1); + return ((uint8_t)status); +} + +static void flash_gd25q32c_write_status(enum GD25Q32C_status status_index,uint8_t status) +{ + uint32_t wrsr_cmd=0; + uint32_t new_status = status; + if(GD25Q32C_STATUS1 == status_index) { + wrsr_cmd = SPI_FLASH_GD25Q32C_WRITE_STATUSE1_CMD; + } + else if(GD25Q32C_STATUS2 == status_index) { + wrsr_cmd = SPI_FLASH_GD25Q32C_WRITE_STATUSE2_CMD; + } + else if(GD25Q32C_STATUS3 == status_index) { + wrsr_cmd = SPI_FLASH_GD25Q32C_WRITE_STATUSE3_CMD; + } + else { + //ets_printf("[ERR]Not konw GD25Q32C status idx %d\n ",spi_wr_status_cmd); + } + special_flash_write_status(wrsr_cmd, new_status, 1, true); +} + +static bool flash_gd25q32c_enable_QIO_mode(void) +{ + uint8_t data = 0; + if((data=flash_gd25q32c_read_status(GD25Q32C_STATUS2))&SPI_FLASH_GD25Q32C_QIO_MODE) { + return true; + } + else { + flash_gd25q32c_write_status(GD25Q32C_STATUS2,SPI_FLASH_GD25Q32C_QIO_MODE); + if(flash_gd25q32c_read_status(GD25Q32C_STATUS2)&SPI_FLASH_GD25Q32C_QIO_MODE) { + return true; + } + else { + return false; + } + } +} + +void special_flash_set_mode(uint8_t command, bool disable_wait_idle) +{ + spi_cmd_t cmd; + cmd.cmd = command; + cmd.cmd_len = 1; + cmd.addr = NULL; + cmd.addr_len = 0; + cmd.dummy_bits = 0; + cmd.data = NULL; + cmd.data_len = 0; + if (disable_wait_idle) { + spi_user_cmd(SPI_TX | SPI_RAW, &cmd); + } else { + spi_user_cmd(SPI_TX, &cmd); + } +} + +bool en25q16x_write_volatile_status(uint8_t vsr) +{ + //enter OTP mode + special_flash_set_mode(0x3a, true); + //volatile status register write enable + special_flash_set_mode(0x50, true); + //send 0x01 + 0x40 to set WHDIS bit + special_flash_write_status(0x01, vsr, 1, false); + //check + uint32_t status = 0; + special_flash_read_status(0x05, &status, 1); + //Leave OTP mode + special_flash_set_mode(0x04, false); + + if (status == 0x40) { + return true; + } else { + return false; + } +} + +void user_spi_flash_dio_to_qio_pre_init(void) +{ + uint32_t flash_id = spi_flash_get_id(); + bool to_qio = false; + //check for EN25Q16A/B flash chips + if ((flash_id & 0xffffff) == 0x15701c) { + uint8_t sfdp = en25q16x_read_sfdp(); + if (sfdp == 0xE5) { + //This is EN25Q16A, set bit6 in the same way as issi flash chips. + if (spi_flash_issi_enable_QIO_mode() == true) { + to_qio = true; + } + } else if (sfdp == 0xED) { + //This is EN25Q16B + if (en25q16x_write_volatile_status(0x40) == true) { + to_qio = true; + } + } + } + // ISSI : 0x9D + // MXIC : 0xC2 + // GD25Q32C & GD25Q128C : 0x1640C8 + // EON : 0X1C + // ENABLE FLASH QIO 0X01H+BIT6 + else if (((flash_id & 0xFF) == 0x9D) || ((flash_id & 0xFF) == 0xC2) || ((flash_id & 0xFF) == 0x1C) ) { + if (spi_flash_issi_enable_QIO_mode() == true) { + to_qio = true; + } + //ENABLE FLASH QIO 0X31H+BIT2 + } else if (((flash_id & 0xFFFFFF) == 0x1640C8) || ((flash_id & 0xFFFFFF) == 0x1840C8)) { + if (flash_gd25q32c_enable_QIO_mode() == true) { + to_qio = true; + } + //ENBALE FLASH QIO 0X01H+0X00+0X02 + } else { + if (spi_flash_enable_qmode_raw(&flashchip) == ESP_OK) { + to_qio = true; + } + } + + if (to_qio == true) { + spi_flash_switch_to_qio_raw(); + } +} + +esp_err_t spi_flash_erase_sector(size_t sec) +{ + FLASH_INTR_DECLARE(c_tmp); + + esp_err_t ret; + + if (sec >= (flashchip.chip_size / flashchip.sector_size)) { + return ESP_ERR_FLASH_OP_FAIL; + } + + if (spi_flash_check_wr_protect() == false) { + return ESP_ERR_FLASH_OP_FAIL; + } + + FLASH_INTR_LOCK(c_tmp); + FlashIsOnGoing = 1; + + ret = spi_flash_erase_sector_raw(&flashchip, sec, flashchip.sector_size); + + FlashIsOnGoing = 0; + FLASH_INTR_UNLOCK(c_tmp); + + return ret; +} + +static esp_err_t spi_flash_program(uint32_t target, uint32_t *src_addr, size_t len) +{ + uint32_t page_size; + uint32_t pgm_len, pgm_num; + uint8_t i; + + page_size = flashchip.page_size; + pgm_len = page_size - (target % page_size); + + if (len < pgm_len) { + if (ESP_OK != spi_flash_write_raw(&flashchip, target, src_addr, len)) { + return ESP_ERR_FLASH_OP_FAIL; + } + } else { + if (ESP_OK != spi_flash_write_raw(&flashchip, target, src_addr, pgm_len)) { + return ESP_ERR_FLASH_OP_FAIL; + } + + //whole page program + pgm_num = (len - pgm_len) / page_size; + + for (i = 0; i < pgm_num; i++) { + if (ESP_OK != spi_flash_write_raw(&flashchip, target + pgm_len, src_addr + (pgm_len >> 2), page_size)) { + return ESP_ERR_FLASH_OP_FAIL; + } + + pgm_len += page_size; + } + + //remain parts to program + if (ESP_OK != spi_flash_write_raw(&flashchip, target + pgm_len, src_addr + (pgm_len >> 2), len - pgm_len)) { + return ESP_ERR_FLASH_OP_FAIL; + } + } + + return ESP_OK; +} + +static esp_err_t __spi_flash_write(size_t dest_addr, const void *src, size_t size) +{ + esp_err_t ret; + FLASH_INTR_DECLARE(c_tmp); + + FLASH_INTR_LOCK(c_tmp); + FlashIsOnGoing = 1; + + ret = spi_flash_program(dest_addr, (uint32_t *)src, size); + + FlashIsOnGoing = 0; + FLASH_INTR_UNLOCK(c_tmp); + + return ret; +} + +esp_err_t spi_flash_write(size_t dest_addr, const void *src, size_t size) +{ +#undef FLASH_WRITE +#define FLASH_WRITE(dest, src, size) \ +{ \ + ret = __spi_flash_write(dest, src, size); \ + esp_task_wdt_reset(); \ + if (ret) { \ + return ret; \ + } \ +} + +#undef FLASH_READ +#define FLASH_READ(dest, src, size) \ +{ \ + ret = spi_flash_read(dest, src, size); \ + if (ret) { \ + return ret; \ + } \ +} + + esp_err_t ret = ESP_ERR_FLASH_OP_FAIL; + uint8_t *tmp = (uint8_t *)src; + + if (!size) + return ESP_OK; + + if (src == NULL) { + return ESP_ERR_FLASH_OP_FAIL; + } + + if ((dest_addr + size) > flashchip.chip_size) { + return ESP_ERR_FLASH_OP_FAIL; + } + + if (spi_flash_check_wr_protect() == false) { + return ESP_ERR_FLASH_OP_FAIL; + } + + if (NOT_ALIGN(dest_addr) + || NOT_ALIGN(tmp) + || NOT_ALIGN(size) + || IS_FLASH(src)) { + uint8_t buf[SPI_READ_BUF_MAX]; + + if (NOT_ALIGN(dest_addr)) { + size_t r_addr = FLASH_ALIGN_BEFORE(dest_addr); + size_t c_off = dest_addr - r_addr; + size_t wbytes = FLASH_ALIGN_BYTES - c_off; + + wbytes = wbytes > size ? size : wbytes; + + FLASH_READ(r_addr, buf, FLASH_ALIGN_BYTES); + memcpy(&buf[c_off], tmp, wbytes); + FLASH_WRITE(r_addr, buf, FLASH_ALIGN_BYTES); + + dest_addr += wbytes; + tmp += wbytes; + size -= wbytes; + } + + while (size > 0) { + size_t len = size >= SPI_READ_BUF_MAX ? SPI_READ_BUF_MAX : size; + size_t wlen = FLASH_ALIGN(len); + + if (wlen != len) { + size_t l_b = wlen - FLASH_ALIGN_BYTES; + + FLASH_READ(dest_addr + l_b, &buf[l_b], FLASH_ALIGN_BYTES); + } + + memcpy(buf, tmp, len); + + FLASH_WRITE(dest_addr, buf, wlen); + + dest_addr += len; + tmp += len; + size -= len; + } + } else { + FLASH_WRITE(dest_addr, src, size); + } + + return ret; +} + +static esp_err_t __spi_flash_read(size_t src_addr, void *dest, size_t size) +{ + esp_err_t ret; + FLASH_INTR_DECLARE(c_tmp); + + FLASH_INTR_LOCK(c_tmp); + FlashIsOnGoing = 1; + + ret = spi_flash_read_raw(&flashchip, src_addr, dest, size); + + FlashIsOnGoing = 0; + FLASH_INTR_UNLOCK(c_tmp); + + return ret == 0 ? ESP_OK : ESP_ERR_FLASH_OP_FAIL; +} + +esp_err_t spi_flash_read(size_t src_addr, void *dest, size_t size) +{ +#undef FLASH_READ +#define FLASH_READ(addr, dest, size) \ +{ \ + ret = __spi_flash_read(addr, dest, size); \ + esp_task_wdt_reset(); \ + if (ret) \ + return ret; \ +} + + esp_err_t ret; + uint8_t *tmp = (uint8_t *)dest; + + if (!size) + return ESP_OK; + + if (tmp == NULL) { + return ESP_ERR_FLASH_OP_FAIL; + } + + if (NOT_ALIGN(src_addr) + || NOT_ALIGN(tmp) + || NOT_ALIGN(size)) { + uint8_t buf[SPI_READ_BUF_MAX]; + + if (NOT_ALIGN(src_addr)) { + size_t r_addr = FLASH_ALIGN_BEFORE(src_addr); + size_t c_off = src_addr - r_addr; + size_t wbytes = FLASH_ALIGN_BYTES - c_off; + + wbytes = wbytes > size ? size : wbytes; + + FLASH_READ(r_addr, buf, FLASH_ALIGN_BYTES); + memcpy(tmp, &buf[c_off], wbytes); + + tmp += wbytes; + src_addr += wbytes; + size -= wbytes; + } + + while (size) { + size_t len = size >= SPI_READ_BUF_MAX ? SPI_READ_BUF_MAX : size; + size_t wlen = FLASH_ALIGN(len); + + FLASH_READ(src_addr, buf, wlen); + + memcpy(tmp, buf, len); + + src_addr += len; + tmp += len; + size -= len; + } + } else { + FLASH_READ(src_addr, tmp, size); + } + + return ESP_OK; +} + +/** + * @brief Erase a range of flash sectors + */ +esp_err_t spi_flash_erase_range(size_t start_address, size_t size) +{ + esp_err_t ret; + size_t sec, num; + + if (start_address % SPI_FLASH_SEC_SIZE + || size % SPI_FLASH_SEC_SIZE) { + return ESP_ERR_FLASH_OP_FAIL; + } + + if (spi_flash_check_wr_protect() == false) { + return ESP_ERR_FLASH_OP_FAIL; + } + + sec = start_address / SPI_FLASH_SEC_SIZE; + num = size / SPI_FLASH_SEC_SIZE; + + /* + * call "spi_flash_erase_sector" continuely to make the function to be able + * to enter/exit critical state so that system core can feed watch + */ + do { + ret = spi_flash_erase_sector(sec++); + + esp_task_wdt_reset(); + } while (ret == ESP_OK && --num); + + return ret; +} + +void esp_spi_flash_init(uint32_t spi_speed, uint32_t spi_mode) +{ + uint32_t freqdiv, freqbits; + + SET_PERI_REG_MASK(PERIPHS_SPI_FLASH_USRREG, BIT5); + + if (spi_speed < 3) + freqdiv = spi_speed + 2; + else if (0x0F == spi_speed) + freqdiv = 1; + else + freqdiv = 2; + + if (1 >= freqdiv) { + freqbits = SPI_FLASH_CLK_EQU_SYSCLK; + SET_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL, SPI_FLASH_CLK_EQU_SYSCLK); + SET_PERI_REG_MASK(PERIPHS_IO_MUX_CONF_U, SPI0_CLK_EQU_SYSCLK); + } else { + freqbits = ((freqdiv - 1) << 8) + ((freqdiv / 2 - 1) << 4) + (freqdiv - 1); + CLEAR_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL, SPI_FLASH_CLK_EQU_SYSCLK); + CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_CONF_U, SPI0_CLK_EQU_SYSCLK); + } + SET_PERI_REG_BITS(PERIPHS_SPI_FLASH_CTRL, 0xfff, freqbits, 0); + + if (spi_mode == ESP_IMAGE_SPI_MODE_QIO || spi_mode == ESP_IMAGE_SPI_MODE_QOUT) { + user_spi_flash_dio_to_qio_pre_init(); + + ESP_EARLY_LOGI("qio_mode", "Enabling default flash chip QIO"); + } +} + +uintptr_t spi_flash_cache2phys(const void *cached) +{ + uint32_t map_size; + uintptr_t addr_offset; + uintptr_t addr = (uintptr_t)cached; + + const uint32_t reg = REG_READ(CACHE_FLASH_CTRL_REG); + const uint32_t segment = (reg >> CACHE_MAP_SEGMENT_S) & CACHE_MAP_SEGMENT_MASK; + + if (reg & CACHE_MAP_2M) { + map_size = CACHE_2M_SIZE; + addr_offset = 0; + } else { + map_size = CACHE_1M_SIZE; + if (reg & CACHE_MAP_1M_HIGH) + addr_offset = CACHE_1M_SIZE; + else + addr_offset = 0; + } + + if (addr <= CACHE_BASE_ADDR || addr >= CACHE_BASE_ADDR + map_size) + return SPI_FLASH_CACHE2PHYS_FAIL; + + return segment * CACHE_2M_SIZE + (addr + addr_offset - CACHE_BASE_ADDR); +} diff --git a/cpu/esp8266/vendor/esp-idf/spi_flash/spi_flash_raw.c b/cpu/esp8266/vendor/esp-idf/spi_flash/spi_flash_raw.c new file mode 100644 index 000000000000..06305be659fc --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/spi_flash/spi_flash_raw.c @@ -0,0 +1,290 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "spi_flash.h" +#include "priv/esp_spi_flash_raw.h" + +#include "esp8266/eagle_soc.h" +#include "esp8266/pin_mux_register.h" +#include "esp8266/spi_register.h" + +void Cache_Read_Disable_2(void) +{ + CLEAR_PERI_REG_MASK(CACHE_FLASH_CTRL_REG,CACHE_READ_EN_BIT); + while(REG_READ(SPI_EXT2(0)) != 0) { } + CLEAR_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL,SPI_ENABLE_AHB); +} + +void Cache_Read_Enable_2(void) +{ + SET_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL,SPI_ENABLE_AHB); + SET_PERI_REG_MASK(CACHE_FLASH_CTRL_REG,CACHE_READ_EN_BIT); +} +void Cache_Read_Enable_New(void) __attribute__((alias("Cache_Read_Enable_2"))); + +uint32_t spi_flash_get_id_raw(esp_spi_flash_chip_t *chip) +{ + uint32_t rdid = 0; + + Cache_Read_Disable(); + + Wait_SPI_Idle(chip); + + WRITE_PERI_REG(PERIPHS_SPI_FLASH_C0, 0); // clear regisrter + WRITE_PERI_REG(PERIPHS_SPI_FLASH_CMD, SPI_FLASH_RDID); + while(READ_PERI_REG(PERIPHS_SPI_FLASH_CMD)!=0); + + rdid = READ_PERI_REG(PERIPHS_SPI_FLASH_C0)&0xffffff; + + Cache_Read_Enable_New(); + + return rdid; +} + +esp_err_t spi_flash_read_status_raw(esp_spi_flash_chip_t *chip, uint32_t *status) +{ + esp_err_t ret; + + Cache_Read_Disable_2(); + + ret = SPI_read_status(chip, status); + + Cache_Read_Enable_2(); + + return ret; +} + +esp_err_t spi_flash_write_status_raw(esp_spi_flash_chip_t *chip, uint32_t status_value) +{ + Cache_Read_Disable_2(); + + Wait_SPI_Idle(chip); + + if (ESP_OK != SPI_write_enable(chip)) + return ESP_ERR_FLASH_OP_FAIL; + + if(ESP_OK != SPI_write_status(chip, status_value)) + return ESP_ERR_FLASH_OP_FAIL; + + Wait_SPI_Idle(chip); + + Cache_Read_Enable_2(); + + return ESP_OK; +} + +esp_err_t spi_flash_erase_sector_raw(esp_spi_flash_chip_t *chip, size_t sec, size_t sec_size) +{ + esp_err_t ret = ESP_OK; + + Cache_Read_Disable_2(); + + if (ESP_OK != SPI_write_enable(chip)) { + ret = ESP_ERR_FLASH_OP_FAIL; + } + + if (ESP_OK != SPI_sector_erase(chip, sec * sec_size)) { + ret = ESP_ERR_FLASH_OP_FAIL; + } + + Cache_Read_Enable_2(); + + return ret; +} + +esp_err_t spi_flash_enable_qmode_raw(esp_spi_flash_chip_t *chip) +{ + esp_err_t ret; + + Cache_Read_Disable_2(); + + ret = Enable_QMode(chip); + + Wait_SPI_Idle(chip); + + Cache_Read_Enable_2(); + + return ret; +} + +esp_err_t spi_flash_write_raw(esp_spi_flash_chip_t *chip, size_t dest_addr, const void *src, size_t size) +{ + esp_err_t ret; + + Cache_Read_Disable_2(); + + ret = SPI_page_program(chip, dest_addr, (void *)src, size); + + Cache_Read_Enable_2(); + + return ret; +} + +esp_err_t spi_flash_read_raw(esp_spi_flash_chip_t *chip, size_t src_addr, void *dest, size_t size) +{ + esp_err_t ret; + + Cache_Read_Disable_2(); + + ret = SPI_read_data(chip, src_addr, dest, size); + + Cache_Read_Enable_2(); + + return ret; +} + +bool spi_user_cmd_raw(esp_spi_flash_chip_t *chip, spi_cmd_dir_t mode, spi_cmd_t *p_cmd) +{ + int idx = 0; + + // Cache Disable + Cache_Read_Disable_2(); + //wait spi idle + if((mode & SPI_RAW) == 0) { + Wait_SPI_Idle(chip); + } + //save reg + uint32_t io_mux_reg = READ_PERI_REG(PERIPHS_IO_MUX_CONF_U); + uint32_t spi_clk_reg = READ_PERI_REG(SPI_CLOCK(SPI)); + uint32_t spi_ctrl_reg = READ_PERI_REG(SPI_CTRL(SPI)); + uint32_t spi_user_reg = READ_PERI_REG(SPI_USER(SPI)); + + if (mode & SPI_WRSR) { + // enable write register + SPI_write_enable(chip); + } + + SET_PERI_REG_MASK(SPI_USER(SPI),SPI_USR_COMMAND); + + //Disable flash operation mode + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_FLASH_MODE); + //SET SPI SEND BUFFER MODE + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MISO_HIGHPART); + //CLEAR EQU SYS CLK + CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_CONF_U,SPI0_CLK_EQU_SYS_CLK); + + SET_PERI_REG_MASK(SPI_USER(SPI), SPI_CS_SETUP|SPI_CS_HOLD|SPI_USR_COMMAND|SPI_USR_MOSI); + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_FLASH_MODE); + //CLEAR DAUL OR QUAD LINES TRANSMISSION MODE + CLEAR_PERI_REG_MASK(SPI_CTRL(SPI), SPI_QIO_MODE|SPI_DIO_MODE|SPI_DOUT_MODE|SPI_QOUT_MODE); + WRITE_PERI_REG(SPI_CLOCK(SPI), + ((3&SPI_CLKCNT_N)<cmd_len != 0) { + //Max CMD length is 16 bits + SET_PERI_REG_BITS(SPI_USER2(SPI), SPI_USR_COMMAND_BITLEN, p_cmd->cmd_len * 8 - 1, SPI_USR_COMMAND_BITLEN_S); + //Enable CMD + SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_COMMAND); + //LOAD CMD + SET_PERI_REG_BITS(SPI_USER2(SPI), SPI_USR_COMMAND_VALUE, p_cmd->cmd, SPI_USR_COMMAND_VALUE_S); + } else { + //CLEAR CMD + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_COMMAND); + SET_PERI_REG_BITS(SPI_USER2(SPI), SPI_USR_COMMAND_BITLEN, 0, SPI_USR_COMMAND_BITLEN_S); + } + if (p_cmd->dummy_bits != 0) { + //SET dummy bits + SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_DUMMY_CYCLELEN, p_cmd->dummy_bits - 1, SPI_USR_DUMMY_CYCLELEN_S); + //Enable dummy + SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_DUMMY); + } else { + //CLEAR DUMMY + SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_DUMMY_CYCLELEN, 0, SPI_USR_DUMMY_CYCLELEN_S); + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_DUMMY); + } + + //SET USER ADDRESS + if (p_cmd->addr_len != 0) { + //Set addr lenght + SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_ADDR_BITLEN, p_cmd->addr_len * 8 - 1, SPI_USR_ADDR_BITLEN_S); + //Enable user address + SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_ADDR); + WRITE_PERI_REG(SPI_ADDR(SPI), *p_cmd->addr); + } else { + //CLEAR ADDR + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_ADDR); + SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_ADDR_BITLEN, 0, SPI_USR_ADDR_BITLEN_S); + } + + uint32_t *value = p_cmd->data; + if (((mode & SPI_TX) || (mode & SPI_WRSR)) && p_cmd->data_len != 0) { + //Enable MOSI, disable MISO + SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MOSI); + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MISO); + do { + WRITE_PERI_REG((SPI_W0(SPI) + (idx << 2)), *value++); + } while ( ++idx < (p_cmd->data_len / 4)); + SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_MOSI_BITLEN, ((p_cmd->data_len) * 8 - 1), SPI_USR_MOSI_BITLEN_S); + + } else if ((mode & SPI_RX) && p_cmd->data_len != 0) { + //Enable MISO, disable MOSI + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MOSI); + SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MISO); + SET_PERI_REG_BITS(SPI_USER1(SPI),SPI_USR_MISO_BITLEN, p_cmd->data_len * 8 - 1, SPI_USR_MISO_BITLEN_S); + int fifo_idx = 0; + do { + WRITE_PERI_REG((SPI_W0(SPI) + (fifo_idx << 2)), 0); + } while ( ++fifo_idx < (p_cmd->data_len / 4)); + } else { + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MOSI); + CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MISO); + SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_MISO_BITLEN, 0, SPI_USR_MISO_BITLEN_S); + SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_MOSI_BITLEN, 0, SPI_USR_MOSI_BITLEN_S); + } + + //Start command + SET_PERI_REG_MASK(SPI_CMD(SPI), SPI_USR); + while (READ_PERI_REG(SPI_CMD(SPI)) & SPI_USR); + + if (mode & SPI_RX) { + do { + *p_cmd->data ++ = READ_PERI_REG(SPI_W0(SPI) + (idx << 2)); + } while (++idx < (p_cmd->data_len / 4)); + } + + //recover + WRITE_PERI_REG(PERIPHS_IO_MUX_CONF_U,io_mux_reg); + WRITE_PERI_REG(SPI_CTRL(SPI),spi_ctrl_reg); + WRITE_PERI_REG(SPI_CLOCK(SPI),spi_clk_reg); + WRITE_PERI_REG(SPI_USER(SPI),spi_user_reg); + + if((mode & SPI_RAW) == 0) { + Wait_SPI_Idle(chip); + } + //enable icache + Cache_Read_Enable_2(); + + return true; +} + +void spi_flash_switch_to_qio_raw(void) +{ + CLEAR_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL, SPI_QIO_MODE + |SPI_QOUT_MODE + |SPI_DIO_MODE + |SPI_DOUT_MODE + |SPI_FASTRD_MODE); + + SET_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL, SPI_QIO_MODE | SPI_FASTRD_MODE); +} diff --git a/cpu/esp8266/vendor/esp-idf/util/src/Makefile b/cpu/esp8266/vendor/esp-idf/util/src/Makefile new file mode 100644 index 000000000000..ebf2ebba1d4d --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/util/src/Makefile @@ -0,0 +1,5 @@ +MODULE=esp_idf_util + +include $(RIOTBASE)/Makefile.base + +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/util/include diff --git a/cpu/esp8266/vendor/esp-idf/util/src/crc.c b/cpu/esp8266/vendor/esp-idf/util/src/crc.c new file mode 100644 index 000000000000..6bf5cfaedc32 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/util/src/crc.c @@ -0,0 +1,144 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "crc.h" + +static const uint32_t crc32_le_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, + 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, + 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, + 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, + 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, + 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, + 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, + 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, + 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, + 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, + 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, + 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, + 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, + + 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, + 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, + 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, + 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, + 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, + 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, + 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, + 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, + 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, + 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, + 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, + 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, + 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL +}; + +static const uint16_t crc16_le_table[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +static const uint8_t crc8_le_table[] = { + 0x00, 0x5e, 0xbc, 0xe2, 0x61, 0x3f, 0xdd, 0x83, 0xc2, 0x9c, 0x7e, 0x20, 0xa3, 0xfd, 0x1f, 0x41, + 0x9d, 0xc3, 0x21, 0x7f, 0xfc, 0xa2, 0x40, 0x1e, 0x5f, 0x01, 0xe3, 0xbd, 0x3e, 0x60, 0x82, 0xdc, + 0x23, 0x7d, 0x9f, 0xc1, 0x42, 0x1c, 0xfe, 0xa0, 0xe1, 0xbf, 0x5d, 0x03, 0x80, 0xde, 0x3c, 0x62, + 0xbe, 0xe0, 0x02, 0x5c, 0xdf, 0x81, 0x63, 0x3d, 0x7c, 0x22, 0xc0, 0x9e, 0x1d, 0x43, 0xa1, 0xff, + 0x46, 0x18, 0xfa, 0xa4, 0x27, 0x79, 0x9b, 0xc5, 0x84, 0xda, 0x38, 0x66, 0xe5, 0xbb, 0x59, 0x07, + 0xdb, 0x85, 0x67, 0x39, 0xba, 0xe4, 0x06, 0x58, 0x19, 0x47, 0xa5, 0xfb, 0x78, 0x26, 0xc4, 0x9a, + 0x65, 0x3b, 0xd9, 0x87, 0x04, 0x5a, 0xb8, 0xe6, 0xa7, 0xf9, 0x1b, 0x45, 0xc6, 0x98, 0x7a, 0x24, + 0xf8, 0xa6, 0x44, 0x1a, 0x99, 0xc7, 0x25, 0x7b, 0x3a, 0x64, 0x86, 0xd8, 0x5b, 0x05, 0xe7, 0xb9, + 0x8c, 0xd2, 0x30, 0x6e, 0xed, 0xb3, 0x51, 0x0f, 0x4e, 0x10, 0xf2, 0xac, 0x2f, 0x71, 0x93, 0xcd, + 0x11, 0x4f, 0xad, 0xf3, 0x70, 0x2e, 0xcc, 0x92, 0xd3, 0x8d, 0x6f, 0x31, 0xb2, 0xec, 0x0e, 0x50, + 0xaf, 0xf1, 0x13, 0x4d, 0xce, 0x90, 0x72, 0x2c, 0x6d, 0x33, 0xd1, 0x8f, 0x0c, 0x52, 0xb0, 0xee, + 0x32, 0x6c, 0x8e, 0xd0, 0x53, 0x0d, 0xef, 0xb1, 0xf0, 0xae, 0x4c, 0x12, 0x91, 0xcf, 0x2d, 0x73, + 0xca, 0x94, 0x76, 0x28, 0xab, 0xf5, 0x17, 0x49, 0x08, 0x56, 0xb4, 0xea, 0x69, 0x37, 0xd5, 0x8b, + 0x57, 0x09, 0xeb, 0xb5, 0x36, 0x68, 0x8a, 0xd4, 0x95, 0xcb, 0x29, 0x77, 0xf4, 0xaa, 0x48, 0x16, + 0xe9, 0xb7, 0x55, 0x0b, 0x88, 0xd6, 0x34, 0x6a, 0x2b, 0x75, 0x97, 0xc9, 0x4a, 0x14, 0xf6, 0xa8, + 0x74, 0x2a, 0xc8, 0x96, 0x15, 0x4b, 0xa9, 0xf7, 0xb6, 0xe8, 0x0a, 0x54, 0xd7, 0x89, 0x6b, 0x35 +}; + +uint16_t crc16_le(uint16_t crc, const uint8_t* buf, uint32_t len) +{ + uint32_t i; + + crc = ~crc; + + for (i = 0; i < len; i++) { + crc = crc16_le_table[(crc ^ buf[i]) & 0xff] ^ (crc >> 8); + } + + return ~crc; +} + +uint32_t crc32_le(uint32_t crc, const uint8_t* buf, uint32_t len) +{ + uint32_t i; + + crc = ~crc; + + for (i = 0; i < len; i++) { + crc = crc32_le_table[(crc ^ buf[i]) & 0xff] ^ (crc >> 8); + } + + return ~crc; +} + +uint8_t esp_crc8(uint8_t const* p, uint32_t len) +{ + uint8_t crc = 0x00; + + while (len--) { + crc = crc8_le_table[crc ^ *p++]; + } + + return crc; +} \ No newline at end of file diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/COPYING b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/COPYING new file mode 100644 index 000000000000..7efce0dee1a7 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/COPYING @@ -0,0 +1,22 @@ +wpa_supplicant and hostapd +-------------------------- + +Copyright (c) 2002-2016, Jouni Malinen and contributors +All Rights Reserved. + + +See the README file for the current license terms. + +This software was previously distributed under BSD/GPL v2 dual license +terms that allowed either of those license alternatives to be +selected. As of February 11, 2012, the project has chosen to use only +the BSD license option for future distribution. As such, the GPL v2 +license option is no longer used. It should be noted that the BSD +license option (the one with advertisement clause removed) is compatible +with GPL and as such, does not prevent use of this software in projects +that use GPL. + +Some of the files may still include pointers to GPL version 2 license +terms. However, such copyright and license notifications are maintained +only for attribution purposes and any distribution of this software +after February 11, 2012 is no longer under the GPL v2 option. diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/Makefile b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/Makefile new file mode 100644 index 000000000000..7278372c790e --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/Makefile @@ -0,0 +1,9 @@ +ifneq (,$(filter esp_idf_wpa_supplicant_port ,$(USEMODULE))) + DIRS += port +endif + +ifneq (,$(filter esp_idf_wpa_supplicant_crypto ,$(USEMODULE))) + DIRS += src/crypto +endif + +include $(RIOTBASE)/Makefile.base diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/aes.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/aes.h new file mode 100644 index 000000000000..66eca7840394 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/aes.h @@ -0,0 +1,35 @@ +/* + * AES functions + * Copyright (c) 2003-2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef AES_H +#define AES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define AES_BLOCK_SIZE 16 + +void *wpa_aes_encrypt_init(const u8 *key, size_t len); +void wpa_aes_encrypt(void *ctx, const u8 *plain, u8 *crypt); +void wpa_aes_encrypt_deinit(void *ctx); +void *wpa_aes_decrypt_init(const u8 *key, size_t len); +void wpa_aes_decrypt(void *ctx, const u8 *crypt, u8 *plain); +void wpa_aes_decrypt_deinit(void *ctx); + +#ifdef __cplusplus +} +#endif + +#endif /* AES_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/aes_i.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/aes_i.h new file mode 100644 index 000000000000..25f9b1155558 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/aes_i.h @@ -0,0 +1,139 @@ +/* + * AES (Rijndael) cipher + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef AES_I_H +#define AES_I_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "aes.h" + +/* #define FULL_UNROLL */ +#define AES_SMALL_TABLES + +extern const u32 Te0[256]; +extern const u32 Te1[256]; +extern const u32 Te2[256]; +extern const u32 Te3[256]; +extern const u32 Te4[256]; +extern const u32 Td0[256]; +extern const u32 Td1[256]; +extern const u32 Td2[256]; +extern const u32 Td3[256]; +extern const u32 Td4[256]; +extern const u32 rcon[10]; +extern const u8 Td4s[256]; +extern const u8 rcons[10]; + +#ifndef AES_SMALL_TABLES + +#define RCON(i) rcon[(i)] + +#define TE0(i) Te0[((i) >> 24) & 0xff] +#define TE1(i) Te1[((i) >> 16) & 0xff] +#define TE2(i) Te2[((i) >> 8) & 0xff] +#define TE3(i) Te3[(i) & 0xff] +#define TE41(i) (Te4[((i) >> 24) & 0xff] & 0xff000000) +#define TE42(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000) +#define TE43(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00) +#define TE44(i) (Te4[(i) & 0xff] & 0x000000ff) +#define TE421(i) (Te4[((i) >> 16) & 0xff] & 0xff000000) +#define TE432(i) (Te4[((i) >> 8) & 0xff] & 0x00ff0000) +#define TE443(i) (Te4[(i) & 0xff] & 0x0000ff00) +#define TE414(i) (Te4[((i) >> 24) & 0xff] & 0x000000ff) +#define TE411(i) (Te4[((i) >> 24) & 0xff] & 0xff000000) +#define TE422(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000) +#define TE433(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00) +#define TE444(i) (Te4[(i) & 0xff] & 0x000000ff) +#define TE4(i) (Te4[(i)] & 0x000000ff) + +#define TD0(i) Td0[((i) >> 24) & 0xff] +#define TD1(i) Td1[((i) >> 16) & 0xff] +#define TD2(i) Td2[((i) >> 8) & 0xff] +#define TD3(i) Td3[(i) & 0xff] +#define TD41(i) (Td4[((i) >> 24) & 0xff] & 0xff000000) +#define TD42(i) (Td4[((i) >> 16) & 0xff] & 0x00ff0000) +#define TD43(i) (Td4[((i) >> 8) & 0xff] & 0x0000ff00) +#define TD44(i) (Td4[(i) & 0xff] & 0x000000ff) +#define TD0_(i) Td0[(i) & 0xff] +#define TD1_(i) Td1[(i) & 0xff] +#define TD2_(i) Td2[(i) & 0xff] +#define TD3_(i) Td3[(i) & 0xff] + +#else /* AES_SMALL_TABLES */ + +#define RCON(i) (rcons[(i)] << 24) + +static inline u32 rotr(u32 val, int bits) +{ + return (val >> bits) | (val << (32 - bits)); +} + +#define TE0(i) Te0[((i) >> 24) & 0xff] +#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8) +#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16) +#define TE3(i) rotr(Te0[(i) & 0xff], 24) +#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000) +#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000) +#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00) +#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff) +#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000) +#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000) +#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00) +#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff) +#define TE411(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000) +#define TE422(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000) +#define TE433(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00) +#define TE444(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff) +#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff) + +#define TD0(i) Td0[((i) >> 24) & 0xff] +#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8) +#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16) +#define TD3(i) rotr(Td0[(i) & 0xff], 24) +#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24) +#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16) +#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8) +#define TD44(i) (Td4s[(i) & 0xff]) +#define TD0_(i) Td0[(i) & 0xff] +#define TD1_(i) rotr(Td0[(i) & 0xff], 8) +#define TD2_(i) rotr(Td0[(i) & 0xff], 16) +#define TD3_(i) rotr(Td0[(i) & 0xff], 24) + +#endif /* AES_SMALL_TABLES */ + +#ifdef _MSC_VER +#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) +#define GETU32(p) SWAP(*((u32 *)(p))) +#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); } +#else +#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \ +((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) +#define PUTU32(ct, st) { \ +(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \ +(ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } +#endif + +#define AES_PRIV_SIZE (4 * 4 * 15 + 4) +#define AES_PRIV_NR_POS (4 * 15) + +int wpa_rijndaelKeySetupEnc(u32 rk[], const u8 cipherKey[], int keyBits); + +#ifdef __cplusplus +} +#endif + +#endif /* AES_I_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/aes_wrap.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/aes_wrap.h new file mode 100644 index 000000000000..5f55a69a3ae0 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/aes_wrap.h @@ -0,0 +1,56 @@ +/* + * AES-based functions + * + * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394) + * - One-Key CBC MAC (OMAC1) hash with AES-128 + * - AES-128 CTR mode encryption + * - AES-128 EAX mode encryption/decryption + * - AES-128 CBC + * + * Copyright (c) 2003-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef AES_WRAP_H +#define AES_WRAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +int __must_check wpa_aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher); +int __must_check wpa_aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain); +int __must_check wpa_omac1_aes_128_vector(const u8 *key, size_t num_elem, + const u8 *addr[], const size_t *len, + u8 *mac); +int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, + u8 *mac); +int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out); +int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, + u8 *data, size_t data_len); +int __must_check aes_128_eax_encrypt(const u8 *key, + const u8 *nonce, size_t nonce_len, + const u8 *hdr, size_t hdr_len, + u8 *data, size_t data_len, u8 *tag); +int __must_check aes_128_eax_decrypt(const u8 *key, + const u8 *nonce, size_t nonce_len, + const u8 *hdr, size_t hdr_len, + u8 *data, size_t data_len, const u8 *tag); +int __must_check aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, + size_t data_len); +int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, + size_t data_len); + +#ifdef __cplusplus +} +#endif + +#endif /* AES_WRAP_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/base64.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/base64.h new file mode 100644 index 000000000000..9a66d29432ea --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/base64.h @@ -0,0 +1,31 @@ +/* + * Base64 encoding/decoding (RFC1341) + * Copyright (c) 2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef BASE64_H +#define BASE64_H + +#ifdef __cplusplus +extern "C" { +#endif + +unsigned char * base64_encode(const unsigned char *src, size_t len, + size_t *out_len); +unsigned char * base64_decode(const unsigned char *src, size_t len, + size_t *out_len); + +#ifdef __cplusplus +} +#endif + +#endif /* BASE64_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/common.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/common.h new file mode 100644 index 000000000000..774e68ae5757 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/common.h @@ -0,0 +1,489 @@ +/* + * wpa_supplicant/hostapd / common helper functions, etc. + * Copyright (c) 2002-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef COMMON_H +#define COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "os.h" + +#if defined(__XTENSA__) +#include +#define __BYTE_ORDER BYTE_ORDER +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#define __BIG_ENDIAN BIG_ENDIAN +#endif /*__XTENSA__*/ + +#if defined(__linux__) || defined(__GLIBC__) +#include +#include +#endif /* __linux__ */ + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ + defined(__OpenBSD__) +#include +#include +#define __BYTE_ORDER _BYTE_ORDER +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#define __BIG_ENDIAN _BIG_ENDIAN +#ifdef __OpenBSD__ +#define bswap_16 swap16 +#define bswap_32 swap32 +#define bswap_64 swap64 +#else /* __OpenBSD__ */ +#define bswap_16 bswap16 +#define bswap_32 bswap32 +#define bswap_64 bswap64 +#endif /* __OpenBSD__ */ +#endif /* defined(__FreeBSD__) || defined(__NetBSD__) || + * defined(__DragonFly__) || defined(__OpenBSD__) */ + +#ifdef __APPLE__ +#include +#include +#define __BYTE_ORDER _BYTE_ORDER +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#define __BIG_ENDIAN _BIG_ENDIAN +static inline unsigned short bswap_16(unsigned short v) +{ + return ((v & 0xff) << 8) | (v >> 8); +} + +static inline unsigned int bswap_32(unsigned int v) +{ + return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | + ((v & 0xff0000) >> 8) | (v >> 24); +} +#endif /* __APPLE__ */ + +#ifdef CONFIG_TI_COMPILER +#define __BIG_ENDIAN 4321 +#define __LITTLE_ENDIAN 1234 +#ifdef __big_endian__ +#define __BYTE_ORDER __BIG_ENDIAN +#else +#define __BYTE_ORDER __LITTLE_ENDIAN +#endif +#endif /* CONFIG_TI_COMPILER */ + +#ifdef __SYMBIAN32__ +#define __BIG_ENDIAN 4321 +#define __LITTLE_ENDIAN 1234 +#define __BYTE_ORDER __LITTLE_ENDIAN +#endif /* __SYMBIAN32__ */ + +#ifdef CONFIG_NATIVE_WINDOWS +#include + +typedef int socklen_t; + +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 /* not supported */ +#endif + +#endif /* CONFIG_NATIVE_WINDOWS */ + +#ifdef _MSC_VER +#define inline __inline + +#undef vsnprintf +#define vsnprintf _vsnprintf +#undef close +#define close closesocket +#endif /* _MSC_VER */ + + +/* Define platform specific integer types */ + +#ifdef _MSC_VER +typedef UINT64 u64; +typedef UINT32 u32; +typedef UINT16 u16; +typedef UINT8 u8; +typedef INT64 s64; +typedef INT32 s32; +typedef INT16 s16; +typedef INT8 s8; +#define WPA_TYPES_DEFINED +#endif /* _MSC_VER */ + +#ifdef __vxworks +typedef unsigned long long u64; +typedef UINT32 u32; +typedef UINT16 u16; +typedef UINT8 u8; +typedef long long s64; +typedef INT32 s32; +typedef INT16 s16; +typedef INT8 s8; +#define WPA_TYPES_DEFINED +#endif /* __vxworks */ + +#ifdef CONFIG_TI_COMPILER +#ifdef _LLONG_AVAILABLE +typedef unsigned long long u64; +#else +/* + * TODO: 64-bit variable not available. Using long as a workaround to test the + * build, but this will likely not work for all operations. + */ +typedef unsigned long u64; +#endif +typedef unsigned int u32; +typedef unsigned short u16; +typedef unsigned char u8; +#define WPA_TYPES_DEFINED +#endif /* CONFIG_TI_COMPILER */ + +#ifdef __SYMBIAN32__ +#define __REMOVE_PLATSEC_DIAGNOSTICS__ +#include +typedef TUint64 u64; +typedef TUint32 u32; +typedef TUint16 u16; +typedef TUint8 u8; +#define WPA_TYPES_DEFINED +#endif /* __SYMBIAN32__ */ + +#ifndef WPA_TYPES_DEFINED +#ifdef CONFIG_USE_INTTYPES_H +#include +#else +#include +#endif + +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; +typedef int64_t s64; +typedef int32_t s32; +typedef int16_t s16; +typedef int8_t s8; +#define WPA_TYPES_DEFINED +#endif /* !WPA_TYPES_DEFINED */ + + +/* Define platform specific byte swapping macros */ + +#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) + +static inline unsigned short wpa_swap_16(unsigned short v) +{ + return ((v & 0xff) << 8) | (v >> 8); +} + +static inline unsigned int wpa_swap_32(unsigned int v) +{ + return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | + ((v & 0xff0000) >> 8) | (v >> 24); +} + +#define le_to_host16(n) (n) +#define host_to_le16(n) (n) +#define be_to_host16(n) wpa_swap_16(n) +#define host_to_be16(n) wpa_swap_16(n) +#define le_to_host32(n) (n) +#define be_to_host32(n) wpa_swap_32(n) +#define host_to_be32(n) wpa_swap_32(n) + +#define WPA_BYTE_SWAP_DEFINED + +#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */ + + +#ifndef WPA_BYTE_SWAP_DEFINED + +#ifndef __BYTE_ORDER +#ifndef __LITTLE_ENDIAN +#ifndef __BIG_ENDIAN +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#if defined(sparc) +#define __BYTE_ORDER __BIG_ENDIAN +#endif +#endif /* __BIG_ENDIAN */ +#endif /* __LITTLE_ENDIAN */ +#endif /* __BYTE_ORDER */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define le_to_host16(n) ((__force u16) (le16) (n)) +#define host_to_le16(n) ((__force le16) (u16) (n)) +#define be_to_host16(n) bswap_16((__force u16) (be16) (n)) +#define host_to_be16(n) ((__force be16) bswap_16((n))) +#define le_to_host32(n) ((__force u32) (le32) (n)) +#define host_to_le32(n) ((__force le32) (u32) (n)) +#define be_to_host32(n) bswap_32((__force u32) (be32) (n)) +#define host_to_be32(n) ((__force be32) bswap_32((n))) +#define le_to_host64(n) ((__force u64) (le64) (n)) +#define host_to_le64(n) ((__force le64) (u64) (n)) +#define be_to_host64(n) bswap_64((__force u64) (be64) (n)) +#define host_to_be64(n) ((__force be64) bswap_64((n))) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define le_to_host16(n) bswap_16(n) +#define host_to_le16(n) bswap_16(n) +#define be_to_host16(n) (n) +#define host_to_be16(n) (n) +#define le_to_host32(n) bswap_32(n) +#define be_to_host32(n) (n) +#define host_to_be32(n) (n) +#define le_to_host64(n) bswap_64(n) +#define host_to_le64(n) bswap_64(n) +#define be_to_host64(n) (n) +#define host_to_be64(n) (n) +#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN +#endif +#else +#error Could not determine CPU byte order +#endif + +#define WPA_BYTE_SWAP_DEFINED +#endif /* !WPA_BYTE_SWAP_DEFINED */ + + +/* Macros for handling unaligned memory accesses */ + +#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1])) +#define WPA_PUT_BE16(a, val) \ + do { \ + (a)[0] = ((u16) (val)) >> 8; \ + (a)[1] = ((u16) (val)) & 0xff; \ + } while (0) + +#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) +#define WPA_PUT_LE16(a, val) \ + do { \ + (a)[1] = ((u16) (val)) >> 8; \ + (a)[0] = ((u16) (val)) & 0xff; \ + } while (0) + +#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ + ((u32) (a)[2])) +#define WPA_PUT_BE24(a, val) \ + do { \ + (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[2] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ + (((u32) (a)[2]) << 8) | ((u32) (a)[3])) +#define WPA_PUT_BE32(a, val) \ + do { \ + (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[3] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \ + (((u32) (a)[1]) << 8) | ((u32) (a)[0])) +#define WPA_PUT_LE32(a, val) \ + do { \ + (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ + (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[0] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \ + (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \ + (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \ + (((u64) (a)[6]) << 8) | ((u64) (a)[7])) +#define WPA_PUT_BE64(a, val) \ + do { \ + (a)[0] = (u8) (((u64) (val)) >> 56); \ + (a)[1] = (u8) (((u64) (val)) >> 48); \ + (a)[2] = (u8) (((u64) (val)) >> 40); \ + (a)[3] = (u8) (((u64) (val)) >> 32); \ + (a)[4] = (u8) (((u64) (val)) >> 24); \ + (a)[5] = (u8) (((u64) (val)) >> 16); \ + (a)[6] = (u8) (((u64) (val)) >> 8); \ + (a)[7] = (u8) (((u64) (val)) & 0xff); \ + } while (0) + +#define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \ + (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \ + (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \ + (((u64) (a)[1]) << 8) | ((u64) (a)[0])) + + +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif +#ifndef ETH_P_ALL +#define ETH_P_ALL 0x0003 +#endif +#ifndef ETH_P_PAE +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#endif /* ETH_P_PAE */ +#ifndef ETH_P_EAPOL +#define ETH_P_EAPOL ETH_P_PAE +#endif /* ETH_P_EAPOL */ +#ifndef ETH_P_RSN_PREAUTH +#define ETH_P_RSN_PREAUTH 0x88c7 +#endif /* ETH_P_RSN_PREAUTH */ +#ifndef ETH_P_RRB +#define ETH_P_RRB 0x890D +#endif /* ETH_P_RRB */ + + +#ifdef __GNUC__ +#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b)))) +#define STRUCT_PACKED __attribute__ ((packed)) +#else +#define PRINTF_FORMAT(a,b) +#define STRUCT_PACKED +#endif + +#ifdef CONFIG_ANSI_C_EXTRA + +#if !defined(_MSC_VER) || _MSC_VER < 1400 +/* snprintf - used in number of places; sprintf() is _not_ a good replacement + * due to possible buffer overflow; see, e.g., + * http://www.ijs.si/software/snprintf/ for portable implementation of + * snprintf. */ +int snprintf(char *str, size_t size, const char *format, ...); + +/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */ +int vsnprintf(char *str, size_t size, const char *format, va_list ap); +#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */ + +/* getopt - only used in main.c */ +int getopt(int argc, char *const argv[], const char *optstring); +extern char *optarg; +extern int optind; + +#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF +#ifndef __socklen_t_defined +typedef int socklen_t; +#endif +#endif + +/* inline - define as __inline or just define it to be empty, if needed */ +#ifdef CONFIG_NO_INLINE +#define inline +#else +#define inline __inline +#endif + +#ifndef __func__ +#define __func__ "__func__ not defined" +#endif + +#ifndef bswap_16 +#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff)) +#endif + +#ifndef bswap_32 +#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \ + (((u32) (a) << 8) & 0xff0000) | \ + (((u32) (a) >> 8) & 0xff00) | \ + (((u32) (a) >> 24) & 0xff)) +#endif + +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 +#endif + +#ifdef _WIN32_WCE +void perror(const char *s); +#endif /* _WIN32_WCE */ + +#endif /* CONFIG_ANSI_C_EXTRA */ + +#ifndef MAC2STR +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" +#endif + +#ifndef BIT +#define BIT(x) (1 << (x)) +#endif + +/* + * Definitions for sparse validation + * (http://kernel.org/pub/linux/kernel/people/josh/sparse/) + */ +#ifdef __CHECKER__ +#define __force __attribute__((force)) +#define __bitwise __attribute__((bitwise)) +#else +#define __force +#define __bitwise +#endif + +typedef u16 __bitwise be16; +typedef u16 __bitwise le16; +typedef u32 __bitwise be32; +typedef u32 __bitwise le32; +typedef u64 __bitwise be64; +typedef u64 __bitwise le64; + +#ifndef __must_check +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define __must_check __attribute__((__warn_unused_result__)) +#else +#define __must_check +#endif /* __GNUC__ */ +#endif /* __must_check */ + +int hwaddr_aton(const char *txt, u8 *addr); +int hwaddr_aton2(const char *txt, u8 *addr); +int hexstr2bin(const char *hex, u8 *buf, size_t len); +void inc_byte_array(u8 *counter, size_t len); +void wpa_get_ntp_timestamp(u8 *buf); +int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); +int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, + size_t len); + +#ifdef CONFIG_NATIVE_WINDOWS +void wpa_unicode2ascii_inplace(TCHAR *str); +TCHAR * wpa_strdup_tchar(const char *str); +#else /* CONFIG_NATIVE_WINDOWS */ +#define wpa_unicode2ascii_inplace(s) do { } while (0) +#define wpa_strdup_tchar(s) strdup((s)) +#endif /* CONFIG_NATIVE_WINDOWS */ + +const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); + +static inline int is_zero_ether_addr(const u8 *a) +{ + return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]); +} + +/* + * gcc 4.4 ends up generating strict-aliasing warnings about some very common + * networking socket uses that do not really result in a real problem and + * cannot be easily avoided with union-based type-punning due to struct + * definitions including another struct in system header files. To avoid having + * to fully disable strict-aliasing warnings, provide a mechanism to hide the + * typecast from aliasing for now. A cleaner solution will hopefully be found + * in the future to handle these cases. + */ +void * __hide_aliasing_typecast(void *foo); +#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a)) + +#ifdef __cplusplus +} +#endif + +#endif /* COMMON_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/crypto.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/crypto.h new file mode 100644 index 000000000000..60c87f87e433 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/crypto.h @@ -0,0 +1,480 @@ +/* + * WPA Supplicant / wrapper functions for crypto libraries + * Copyright (c) 2004-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * This file defines the cryptographic functions that need to be implemented + * for wpa_supplicant and hostapd. When TLS is not used, internal + * implementation of MD5, SHA1, and AES is used and no external libraries are + * required. When TLS is enabled (e.g., by enabling EAP-TLS or EAP-PEAP), the + * crypto library used by the TLS implementation is expected to be used for + * non-TLS needs, too, in order to save space by not implementing these + * functions twice. + * + * Wrapper code for using each crypto library is in its own file (crypto*.c) + * and one of these files is build and linked in to provide the functions + * defined here. + */ + +#ifndef CRYPTO_H +#define CRYPTO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "common.h" + +/** + * md4_vector - MD4 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure + */ +int wpa_md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); + +/** + * md5_vector - MD5 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure + */ +int wpa_md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); + +#ifdef CONFIG_FIPS +/** + * md5_vector_non_fips_allow - MD5 hash for data vector (non-FIPS use allowed) + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure + */ +int wpa_md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[], + const size_t *len, u8 *mac); +#else /* CONFIG_FIPS */ +#define md5_vector_non_fips_allow md5_vector +#endif /* CONFIG_FIPS */ + + +/** + * sha1_vector - SHA-1 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure + */ +int wpa_sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac); + +/** + * fips186_2-prf - NIST FIPS Publication 186-2 change notice 1 PRF + * @seed: Seed/key for the PRF + * @seed_len: Seed length in bytes + * @x: Buffer for PRF output + * @xlen: Output length in bytes + * Returns: 0 on success, -1 on failure + * + * This function implements random number generation specified in NIST FIPS + * Publication 186-2 for EAP-SIM. This PRF uses a function that is similar to + * SHA-1, but has different message padding. + */ +int __must_check wpa_fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, + size_t xlen); + +/** + * sha256_vector - SHA256 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 on failure + */ +int wpa_sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac); + +/** + * des_encrypt - Encrypt one block with DES + * @clear: 8 octets (in) + * @key: 7 octets (in) (no parity bits included) + * @cypher: 8 octets (out) + */ +void wpa_des_encrypt(const u8 *clear, const u8 *key, u8 *cypher); + +/** + * aes_encrypt_init - Initialize AES for encryption + * @key: Encryption key + * @len: Key length in bytes (usually 16, i.e., 128 bits) + * Returns: Pointer to context data or %NULL on failure + */ +void * wpa_aes_encrypt_init(const u8 *key, size_t len); + +/** + * aes_encrypt - Encrypt one AES block + * @ctx: Context pointer from aes_encrypt_init() + * @plain: Plaintext data to be encrypted (16 bytes) + * @crypt: Buffer for the encrypted data (16 bytes) + */ +void wpa_aes_encrypt(void *ctx, const u8 *plain, u8 *crypt); + +/** + * aes_encrypt_deinit - Deinitialize AES encryption + * @ctx: Context pointer from aes_encrypt_init() + */ +void wpa_aes_encrypt_deinit(void *ctx); + +/** + * aes_decrypt_init - Initialize AES for decryption + * @key: Decryption key + * @len: Key length in bytes (usually 16, i.e., 128 bits) + * Returns: Pointer to context data or %NULL on failure + */ +void * wpa_aes_decrypt_init(const u8 *key, size_t len); + +/** + * aes_decrypt - Decrypt one AES block + * @ctx: Context pointer from aes_encrypt_init() + * @crypt: Encrypted data (16 bytes) + * @plain: Buffer for the decrypted data (16 bytes) + */ +void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain); + +/** + * aes_decrypt_deinit - Deinitialize AES decryption + * @ctx: Context pointer from aes_encrypt_init() + */ +void wpa_aes_decrypt_deinit(void *ctx); + + +enum crypto_hash_alg { + CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1, + CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1, + CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256 +}; + +struct crypto_hash; + +/** + * crypto_hash_init - Initialize hash/HMAC function + * @alg: Hash algorithm + * @key: Key for keyed hash (e.g., HMAC) or %NULL if not needed + * @key_len: Length of the key in bytes + * Returns: Pointer to hash context to use with other hash functions or %NULL + * on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, + size_t key_len); + +/** + * crypto_hash_update - Add data to hash calculation + * @ctx: Context pointer from crypto_hash_init() + * @data: Data buffer to add + * @len: Length of the buffer + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len); + +/** + * crypto_hash_finish - Complete hash calculation + * @ctx: Context pointer from crypto_hash_init() + * @hash: Buffer for hash value or %NULL if caller is just freeing the hash + * context + * @len: Pointer to length of the buffer or %NULL if caller is just freeing the + * hash context; on return, this is set to the actual length of the hash value + * Returns: 0 on success, -1 if buffer is too small (len set to needed length), + * or -2 on other failures (including failed crypto_hash_update() operations) + * + * This function calculates the hash value and frees the context buffer that + * was used for hash calculation. + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int crypto_hash_finish(struct crypto_hash *ctx, u8 *hash, size_t *len); + + +enum crypto_cipher_alg { + CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES, + CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4 +}; + +struct crypto_cipher; + +/** + * crypto_cipher_init - Initialize block/stream cipher function + * @alg: Cipher algorithm + * @iv: Initialization vector for block ciphers or %NULL for stream ciphers + * @key: Cipher key + * @key_len: Length of key in bytes + * Returns: Pointer to cipher context to use with other cipher functions or + * %NULL on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, + const u8 *iv, const u8 *key, + size_t key_len); + +/** + * crypto_cipher_encrypt - Cipher encrypt + * @ctx: Context pointer from crypto_cipher_init() + * @plain: Plaintext to cipher + * @crypt: Resulting ciphertext + * @len: Length of the plaintext + * Returns: 0 on success, -1 on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int __must_check crypto_cipher_encrypt(struct crypto_cipher *ctx, + const u8 *plain, u8 *crypt, size_t len); + +/** + * crypto_cipher_decrypt - Cipher decrypt + * @ctx: Context pointer from crypto_cipher_init() + * @crypt: Ciphertext to decrypt + * @plain: Resulting plaintext + * @len: Length of the cipher text + * Returns: 0 on success, -1 on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int __must_check crypto_cipher_decrypt(struct crypto_cipher *ctx, + const u8 *crypt, u8 *plain, size_t len); + +/** + * crypto_cipher_decrypt - Free cipher context + * @ctx: Context pointer from crypto_cipher_init() + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +void crypto_cipher_deinit(struct crypto_cipher *ctx); + + +struct crypto_public_key; +struct crypto_private_key; + +/** + * crypto_public_key_import - Import an RSA public key + * @key: Key buffer (DER encoded RSA public key) + * @len: Key buffer length in bytes + * Returns: Pointer to the public key or %NULL on failure + * + * This function can just return %NULL if the crypto library supports X.509 + * parsing. In that case, crypto_public_key_from_cert() is used to import the + * public key from a certificate. + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len); + +/** + * crypto_private_key_import - Import an RSA private key + * @key: Key buffer (DER encoded RSA private key) + * @len: Key buffer length in bytes + * @passwd: Key encryption password or %NULL if key is not encrypted + * Returns: Pointer to the private key or %NULL on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +struct crypto_private_key * crypto_private_key_import(const u8 *key, + size_t len, + const char *passwd); + +/** + * crypto_public_key_from_cert - Import an RSA public key from a certificate + * @buf: DER encoded X.509 certificate + * @len: Certificate buffer length in bytes + * Returns: Pointer to public key or %NULL on failure + * + * This function can just return %NULL if the crypto library does not support + * X.509 parsing. In that case, internal code will be used to parse the + * certificate and public key is imported using crypto_public_key_import(). + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf, + size_t len); + +/** + * crypto_public_key_encrypt_pkcs1_v15 - Public key encryption (PKCS #1 v1.5) + * @key: Public key + * @in: Plaintext buffer + * @inlen: Length of plaintext buffer in bytes + * @out: Output buffer for encrypted data + * @outlen: Length of output buffer in bytes; set to used length on success + * Returns: 0 on success, -1 on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int __must_check crypto_public_key_encrypt_pkcs1_v15( + struct crypto_public_key *key, const u8 *in, size_t inlen, + u8 *out, size_t *outlen); + +/** + * crypto_private_key_decrypt_pkcs1_v15 - Private key decryption (PKCS #1 v1.5) + * @key: Private key + * @in: Encrypted buffer + * @inlen: Length of encrypted buffer in bytes + * @out: Output buffer for encrypted data + * @outlen: Length of output buffer in bytes; set to used length on success + * Returns: 0 on success, -1 on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int __must_check crypto_private_key_decrypt_pkcs1_v15( + struct crypto_private_key *key, const u8 *in, size_t inlen, + u8 *out, size_t *outlen); + +/** + * crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1) + * @key: Private key from crypto_private_key_import() + * @in: Plaintext buffer + * @inlen: Length of plaintext buffer in bytes + * @out: Output buffer for encrypted (signed) data + * @outlen: Length of output buffer in bytes; set to used length on success + * Returns: 0 on success, -1 on failure + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int __must_check crypto_private_key_sign_pkcs1(struct crypto_private_key *key, + const u8 *in, size_t inlen, + u8 *out, size_t *outlen); + +/** + * crypto_public_key_free - Free public key + * @key: Public key + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +void crypto_public_key_free(struct crypto_public_key *key); + +/** + * crypto_private_key_free - Free private key + * @key: Private key from crypto_private_key_import() + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +void crypto_private_key_free(struct crypto_private_key *key); + +/** + * crypto_public_key_decrypt_pkcs1 - Decrypt PKCS #1 signature + * @key: Public key + * @crypt: Encrypted signature data (using the private key) + * @crypt_len: Encrypted signature data length + * @plain: Buffer for plaintext (at least crypt_len bytes) + * @plain_len: Plaintext length (max buffer size on input, real len on output); + * Returns: 0 on success, -1 on failure + */ +int __must_check crypto_public_key_decrypt_pkcs1( + struct crypto_public_key *key, const u8 *crypt, size_t crypt_len, + u8 *plain, size_t *plain_len); + +/** + * crypto_global_init - Initialize crypto wrapper + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int __must_check crypto_global_init(void); + +/** + * crypto_global_deinit - Deinitialize crypto wrapper + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +void crypto_global_deinit(void); + +/** + * crypto_mod_exp - Modular exponentiation of large integers + * @base: Base integer (big endian byte array) + * @base_len: Length of base integer in bytes + * @power: Power integer (big endian byte array) + * @power_len: Length of power integer in bytes + * @modulus: Modulus integer (big endian byte array) + * @modulus_len: Length of modulus integer in bytes + * @result: Buffer for the result + * @result_len: Result length (max buffer size on input, real len on output) + * Returns: 0 on success, -1 on failure + * + * This function calculates result = base ^ power mod modulus. modules_len is + * used as the maximum size of modulus buffer. It is set to the used size on + * success. + * + * This function is only used with internal TLSv1 implementation + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need + * to implement this. + */ +int __must_check crypto_mod_exp(const u8 *base, size_t base_len, + const u8 *power, size_t power_len, + const u8 *modulus, size_t modulus_len, + u8 *result, size_t *result_len); + +/** + * rc4_skip - XOR RC4 stream to given data with skip-stream-start + * @key: RC4 key + * @keylen: RC4 key length + * @skip: number of bytes to skip from the beginning of the RC4 stream + * @data: data to be XOR'ed with RC4 stream + * @data_len: buf length + * Returns: 0 on success, -1 on failure + * + * Generate RC4 pseudo random stream for the given key, skip beginning of the + * stream, and XOR the end result with the data buffer to perform RC4 + * encryption/decryption. + */ +int wpa_rc4_skip(const u8 *key, size_t keylen, size_t skip, + u8 *data, size_t data_len); + +#ifdef __cplusplus +} +#endif + +#endif /* CRYPTO_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/dh_group5.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/dh_group5.h new file mode 100644 index 000000000000..f40af56c3a4b --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/dh_group5.h @@ -0,0 +1,31 @@ +/* + * Diffie-Hellman group 5 operations + * Copyright (c) 2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef DH_GROUP5_H +#define DH_GROUP5_H + +#ifdef __cplusplus +extern "C" { +#endif + +void * wpa_dh5_init(struct wpabuf **priv, struct wpabuf **publ); +struct wpabuf * wpa_dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, + const struct wpabuf *own_private); +void wpa_dh5_free(void *ctx); + +#ifdef __cplusplus +} +#endif + +#endif /* DH_GROUP5_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/dh_groups.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/dh_groups.h new file mode 100644 index 000000000000..0d30c91cde21 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/dh_groups.h @@ -0,0 +1,40 @@ +/* + * Diffie-Hellman groups + * Copyright (c) 2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef DH_GROUPS_H +#define DH_GROUPS_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct dh_group { + int id; + const u8 *generator; + size_t generator_len; + const u8 *prime; + size_t prime_len; +}; + +const struct dh_group * wpa_dh_groups_get(int id); +struct wpabuf * wpa_dh_init(const struct dh_group *dh, struct wpabuf **priv); +struct wpabuf * wpa_dh_derive_shared(const struct wpabuf *peer_public, + const struct wpabuf *own_private, + const struct dh_group *dh); + +#ifdef __cplusplus +} +#endif + +#endif /* DH_GROUPS_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/includes.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/includes.h new file mode 100644 index 000000000000..ca00536eddf1 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/includes.h @@ -0,0 +1,73 @@ +/* + * wpa_supplicant/hostapd - Default include files + * Copyright (c) 2005-2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * This header file is included into all C files so that commonly used header + * files can be selected with OS specific ifdef blocks in one place instead of + * having to have OS/C library specific selection in many files. + */ + +#ifndef INCLUDES_H +#define INCLUDES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Include possible build time configuration before including anything else */ +//#include "build_config.h" //don't need anymore +#ifndef __ets__ +#include +#include +#include +#include +#ifndef _WIN32_WCE +#ifndef CONFIG_TI_COMPILER +#include +#include +#endif /* CONFIG_TI_COMPILER */ +#include +#endif /* _WIN32_WCE */ +#include +#include + +#ifndef CONFIG_TI_COMPILER +#ifndef _MSC_VER +#include +#endif /* _MSC_VER */ +#endif /* CONFIG_TI_COMPILER */ + +#ifndef CONFIG_NATIVE_WINDOWS +#ifndef CONFIG_TI_COMPILER +//#include +//#include +//#include +#ifndef __vxworks +#ifndef __SYMBIAN32__ +//#include +#endif /* __SYMBIAN32__ */ +#include +#endif /* __vxworks */ +#endif /* CONFIG_TI_COMPILER */ +#endif /* CONFIG_NATIVE_WINDOWS */ + +#else + +#include "rom/ets_sys.h" + +#endif /* !__ets__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* INCLUDES_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/md5.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/md5.h new file mode 100644 index 000000000000..61736fc89394 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/md5.h @@ -0,0 +1,43 @@ +/* + * MD5 hash implementation and interface functions + * Copyright (c) 2003-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef MD5_H +#define MD5_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MD5_MAC_LEN 16 + +int wpa_hmac_md5_vector(const uint8_t *key, size_t key_len, size_t num_elem, + const uint8_t *addr[], const size_t *len, uint8_t *mac); +int wpa_hmac_md5(const uint8_t *key, size_t key_len, const uint8_t *data, size_t data_len, + uint8_t *mac); +#ifdef CONFIG_FIPS +int wpa_hmac_md5_vector_non_fips_allow(const uint8_t *key, size_t key_len, + size_t num_elem, const uint8_t *addr[], + const size_t *len, uint8_t *mac); +int wpa_hmac_md5_non_fips_allow(const uint8_t *key, size_t key_len, const uint8_t *data, + size_t data_len, uint8_t *mac); +#else /* CONFIG_FIPS */ +#define wpa_hmac_md5_vector_non_fips_allow wpa_hmac_md5_vector +#define wpa_hmac_md5_non_fips_allow wpa_hmac_md5 +#endif /* CONFIG_FIPS */ + +#ifdef __cplusplus +} +#endif + +#endif /* MD5_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/md5_i.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/md5_i.h new file mode 100644 index 000000000000..f3c31e9ad169 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/md5_i.h @@ -0,0 +1,37 @@ +/* + * MD5 internal definitions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef MD5_I_H +#define MD5_I_H + +struct MD5Context { + u32 buf[4]; + u32 bits[2]; + u8 in[64]; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +void wpa_MD5Init(struct MD5Context *context); +void wpa_MD5Update(struct MD5Context *context, unsigned char const *buf, + unsigned len); +void wpa_MD5Final(unsigned char digest[16], struct MD5Context *context); + +#ifdef __cplusplus +} +#endif + +#endif /* MD5_I_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/random.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/random.h new file mode 100644 index 000000000000..0c874dc54775 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/random.h @@ -0,0 +1,42 @@ +/* + * Random number generator + * Copyright (c) 2010-2011, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef RANDOM_H +#define RANDOM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define CONFIG_NO_RANDOM_POOL + +#ifdef CONFIG_NO_RANDOM_POOL +#define random_init(e) do { } while (0) +#define random_deinit() do { } while (0) +#define random_add_randomness(b, l) do { } while (0) +#define random_get_bytes(b, l) os_get_random((b), (l)) +#define random_pool_ready() 1 +#define random_mark_pool_ready() do { } while (0) +#else /* CONFIG_NO_RANDOM_POOL */ +void random_init(const char *entropy_file); +void random_deinit(void); +void random_add_randomness(const void *buf, size_t len); +int random_get_bytes(void *buf, size_t len); +#endif /* CONFIG_NO_RANDOM_POOL */ + +#ifdef __cplusplus +} +#endif + +#endif /* RANDOM_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/sha1.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/sha1.h new file mode 100644 index 000000000000..a482ef1a9ce9 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/sha1.h @@ -0,0 +1,39 @@ +/* + * SHA1 hash implementation and interface functions + * Copyright (c) 2003-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef SHA1_H +#define SHA1_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SHA1_MAC_LEN 20 + +int wpa_hmac_sha1_vector(const uint8_t *key, size_t key_len, size_t num_elem, + const uint8_t *addr[], const size_t *len, uint8_t *mac); +int wpa_hmac_sha1(const uint8_t *key, size_t key_len, const uint8_t *data, size_t data_len, + uint8_t *mac); +int wpa_sha1_prf(const uint8_t *key, size_t key_len, const char *label, + const uint8_t *data, size_t data_len, uint8_t *buf, size_t buf_len); +int wpa_sha1_t_prf(const uint8_t *key, size_t key_len, const char *label, + const uint8_t *seed, size_t seed_len, uint8_t *buf, size_t buf_len); +int wpa_pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, + int iterations, uint8_t *buf, size_t buflen); + +#ifdef __cplusplus +} +#endif + +#endif /* SHA1_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/sha1_i.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/sha1_i.h new file mode 100644 index 000000000000..9c05ea479d03 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/sha1_i.h @@ -0,0 +1,37 @@ +/* + * SHA1 internal definitions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef SHA1_I_H +#define SHA1_I_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct SHA1Context { + u32 state[5]; + u32 count[2]; + unsigned char buffer[64]; +}; + +void wpa_SHA1Init(struct SHA1Context *context); +void wpa_SHA1Update(struct SHA1Context *context, const void *data, u32 len); +void wpa_SHA1Final(unsigned char digest[20], struct SHA1Context *context); +void wpa_SHA1Transform(u32 state[5], const unsigned char buffer[64]); + +#ifdef __cplusplus +} +#endif + +#endif /* SHA1_I_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/sha256.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/sha256.h new file mode 100644 index 000000000000..55ec598522d7 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/sha256.h @@ -0,0 +1,35 @@ +/* + * SHA256 hash implementation and interface functions + * Copyright (c) 2003-2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef SHA256_H +#define SHA256_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SHA256_MAC_LEN 32 + +void wpa_hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac); +void wpa_hmac_sha256(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *mac); +void wpa_sha256_prf(const u8 *key, size_t key_len, const char *label, + const u8 *data, size_t data_len, u8 *buf, size_t buf_len); + +#ifdef __cplusplus +} +#endif + +#endif /* SHA256_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/wepkey.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/wepkey.h new file mode 100644 index 000000000000..ce7792c72d8a --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/include/crypto/wepkey.h @@ -0,0 +1,45 @@ +/* + * wepkey.h - Generate WEP keys from a passphrase + * + * Copyright (C) 2008 by OpenMoko, Inc. + * Written by Werner Almesberger + * All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + +/* + * wpkey_64 and wepkey_128 implement the keyphrase hash algorithm found in many + * (but not all) common access points, including the Linksys WRT54G series. + */ + +#ifndef WEPKEY_H +#define WEPKEY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "c_types.h" + + +#define WEPKEY_64_BYTES 5 +#define WEPKEY_128_BYTES 13 + + +/* + * "size" is the size of the buffer at "out", in bytes. It has to be at least 5 + * or 13 bytes, respectively. "n" is the key index, in the range 0...3. + */ + +size_t wepkey_64(uint8_t *out, size_t size, const char *in, int n); +size_t wepkey_128(uint8_t *out, size_t size, const char *in, int n); + +#ifdef __cplusplus +} +#endif + +#endif /* !WEPKEY_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/port/Makefile b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/port/Makefile new file mode 100644 index 000000000000..1280d9b90a96 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/port/Makefile @@ -0,0 +1,19 @@ +MODULE=esp_idf_wpa_supplicant_port + +include $(RIOTBASE)/Makefile.base + +# we have to do it in that way to avoid that $(RIOTBASE)/sys/include/crypto +# is found first +INCLUDES = -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/wpa_supplicant/port/include +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/wpa_supplicant/include +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/wpa_supplicant/port/include +CFLAGS += -D__ets__ -DESPRESSIF_USE -DESP_PLATFORM=1 +CFLAGS += -Wno-strict-aliasing + +include $(RIOTCPU)/$(CPU)/Makefile.include + +INCLUDES += -I$(RIOTBASE)/core/include +INCLUDES += -I$(RIOTBASE)/sys/include +INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/log/include +INCLUDES += -I$(RIOTCPU)/$(CPU)/include +INCLUDES += -I$(RIOTBOARD)/$(BOARD)/include diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/port/include/os.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/port/include/os.h new file mode 100644 index 000000000000..0cbe638ee014 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/port/include/os.h @@ -0,0 +1,297 @@ +/* + * OS specific functions + * Copyright (c) 2005-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef OS_H +#define OS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef RIOT_VERSION +#include "syscalls.h" +#define os_memset system_secure_memset +#endif + +#include "esp_types.h" +#include +#include +#include +#include "esp_err.h" +#include "rom/ets_sys.h" + +#include "FreeRTOS.h" +#include "esp_libc.h" + +typedef long os_time_t; + +/** + * os_sleep - Sleep (sec, usec) + * @sec: Number of seconds to sleep + * @usec: Number of microseconds to sleep + */ +void os_sleep(os_time_t sec, os_time_t usec); + +struct os_time { + os_time_t sec; + os_time_t usec; +}; + +/** + * os_get_time - Get current time (sec, usec) + * @t: Pointer to buffer for the time + * Returns: 0 on success, -1 on failure + */ +int os_get_time(struct os_time *t); + + +/* Helper macros for handling struct os_time */ + +#define os_time_before(a, b) \ + ((a)->sec < (b)->sec || \ + ((a)->sec == (b)->sec && (a)->usec < (b)->usec)) + +#define os_time_sub(a, b, res) do { \ + (res)->sec = (a)->sec - (b)->sec; \ + (res)->usec = (a)->usec - (b)->usec; \ + if ((res)->usec < 0) { \ + (res)->sec--; \ + (res)->usec += 1000000; \ + } \ +} while (0) + +/** + * os_mktime - Convert broken-down time into seconds since 1970-01-01 + * @year: Four digit year + * @month: Month (1 .. 12) + * @day: Day of month (1 .. 31) + * @hour: Hour (0 .. 23) + * @min: Minute (0 .. 59) + * @sec: Second (0 .. 60) + * @t: Buffer for returning calendar time representation (seconds since + * 1970-01-01 00:00:00) + * Returns: 0 on success, -1 on failure + * + * Note: The result is in seconds from Epoch, i.e., in UTC, not in local time + * which is used by POSIX mktime(). + */ +int os_mktime(int year, int month, int day, int hour, int min, int sec, + os_time_t *t); + + +/** + * os_daemonize - Run in the background (detach from the controlling terminal) + * @pid_file: File name to write the process ID to or %NULL to skip this + * Returns: 0 on success, -1 on failure + */ +int os_daemonize(const char *pid_file); + +/** + * os_daemonize_terminate - Stop running in the background (remove pid file) + * @pid_file: File name to write the process ID to or %NULL to skip this + */ +void os_daemonize_terminate(const char *pid_file); + +/** + * os_get_random - Get cryptographically strong pseudo random data + * @buf: Buffer for pseudo random data + * @len: Length of the buffer + * Returns: 0 on success, -1 on failure + */ +int os_get_random(unsigned char *buf, size_t len); + +/** + * os_random - Get pseudo random value (not necessarily very strong) + * Returns: Pseudo random value + */ +unsigned long os_random(void); + +/** + * os_rel2abs_path - Get an absolute path for a file + * @rel_path: Relative path to a file + * Returns: Absolute path for the file or %NULL on failure + * + * This function tries to convert a relative path of a file to an absolute path + * in order for the file to be found even if current working directory has + * changed. The returned value is allocated and caller is responsible for + * freeing it. It is acceptable to just return the same path in an allocated + * buffer, e.g., return strdup(rel_path). This function is only used to find + * configuration files when os_daemonize() may have changed the current working + * directory and relative path would be pointing to a different location. + */ +char * os_rel2abs_path(const char *rel_path); + +/** + * os_program_init - Program initialization (called at start) + * Returns: 0 on success, -1 on failure + * + * This function is called when a programs starts. If there are any OS specific + * processing that is needed, it can be placed here. It is also acceptable to + * just return 0 if not special processing is needed. + */ +int os_program_init(void); + +/** + * os_program_deinit - Program deinitialization (called just before exit) + * + * This function is called just before a program exists. If there are any OS + * specific processing, e.g., freeing resourced allocated in os_program_init(), + * it should be done here. It is also acceptable for this function to do + * nothing. + */ +void os_program_deinit(void); + +/** + * os_setenv - Set environment variable + * @name: Name of the variable + * @value: Value to set to the variable + * @overwrite: Whether existing variable should be overwritten + * Returns: 0 on success, -1 on error + * + * This function is only used for wpa_cli action scripts. OS wrapper does not + * need to implement this if such functionality is not needed. + */ +int os_setenv(const char *name, const char *value, int overwrite); + +/** + * os_unsetenv - Delete environent variable + * @name: Name of the variable + * Returns: 0 on success, -1 on error + * + * This function is only used for wpa_cli action scripts. OS wrapper does not + * need to implement this if such functionality is not needed. + */ +int os_unsetenv(const char *name); + +/** + * os_readfile - Read a file to an allocated memory buffer + * @name: Name of the file to read + * @len: For returning the length of the allocated buffer + * Returns: Pointer to the allocated buffer or %NULL on failure + * + * This function allocates memory and reads the given file to this buffer. Both + * binary and text files can be read with this function. The caller is + * responsible for freeing the returned buffer with os_free(). + */ +char * os_readfile(const char *name, size_t *len); + +/* + * The following functions are wrapper for standard ANSI C or POSIX functions. + * By default, they are just defined to use the standard function name and no + * os_*.c implementation is needed for them. This avoids extra function calls + * by allowing the C pre-processor take care of the function name mapping. + * + * If the target system uses a C library that does not provide these functions, + * build_config.h can be used to define the wrappers to use a different + * function name. This can be done on function-by-function basis since the + * defines here are only used if build_config.h does not define the os_* name. + * If needed, os_*.c file can be used to implement the functions that are not + * included in the C library on the target system. Alternatively, + * OS_NO_C_LIB_DEFINES can be defined to skip all defines here in which case + * these functions need to be implemented in os_*.c file for the target system. + */ + +#ifndef os_bzero +#define os_bzero(s, n) bzero(s, n) +#endif + + +#ifndef os_strdup +#ifdef _MSC_VER +#define os_strdup(s) _strdup(s) +#else +#define os_strdup(s) strdup(s) +#endif +#endif +char * ets_strdup(const char *s); + +#ifndef os_memcpy +#define os_memcpy(d, s, n) memcpy((d), (s), (n)) +#endif +#ifndef os_memmove +#define os_memmove(d, s, n) memmove((d), (s), (n)) +#endif +#ifndef os_memset +#define os_memset(s, c, n) memset(s, c, n) +#endif +#ifndef os_memcmp +#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n)) +#endif + +#ifndef os_strlen +#define os_strlen(s) strlen(s) +#endif +#ifndef os_strcasecmp +#ifdef _MSC_VER +#define os_strcasecmp(s1, s2) _stricmp((s1), (s2)) +#else +#define os_strcasecmp(s1, s2) strcasecmp((s1), (s2)) +#endif +#endif +#ifndef os_strncasecmp +#ifdef _MSC_VER +#define os_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n)) +#else +#define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n)) +#endif +#endif +#ifndef os_strchr +#define os_strchr(s, c) strchr((s), (c)) +#endif +#ifndef os_strcmp +#define os_strcmp(s1, s2) strcmp((s1), (s2)) +#endif +#ifndef os_strncmp +#define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n)) +#endif +#ifndef os_strncpy +#define os_strncpy(d, s, n) strncpy((d), (s), (n)) +#endif +#ifndef os_strrchr +//hard cold +#define os_strrchr(s, c) NULL +#endif +#ifndef os_strstr +#define os_strstr(h, n) strstr((h), (n)) +#endif + +#ifndef os_snprintf +#ifdef _MSC_VER +#define os_snprintf _snprintf +#else +#define os_snprintf vsnprintf +#endif +#endif + +/** + * os_strlcpy - Copy a string with size bound and NUL-termination + * @dest: Destination + * @src: Source + * @siz: Size of the target buffer + * Returns: Total length of the target string (length of src) (not including + * NUL-termination) + * + * This function matches in behavior with the strlcpy(3) function in OpenBSD. + */ +size_t os_strlcpy(char *dest, const char *src, size_t siz); + +void *_xmalloc(size_t n); +void _xfree(void *ptr); +void *_xrealloc(void *ptr, size_t n); + +#ifdef __cplusplus +} +#endif + +#endif /* OS_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/port/os_xtensa.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/port/os_xtensa.c new file mode 100644 index 000000000000..7d1665d81868 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/port/os_xtensa.c @@ -0,0 +1,67 @@ +/* + * wpa_supplicant/hostapd / Internal implementation of OS specific functions + * Copyright (c) 2005-2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + * + * This file is an example of operating system specific wrapper functions. + * This version implements many of the functions internally, so it can be used + * to fill in missing functions from the target system C libraries. + * + * Some of the functions are using standard C library calls in order to keep + * this file in working condition to allow the functions to be tested on a + * Linux target. Please note that OS_NO_C_LIB_DEFINES needs to be defined for + * this file to work correctly. Note that these implementations are only + * examples and are not optimized for speed. + */ + +#include "crypto/common.h" +#include "os.h" +#include +#include +#include +#include "esp_system.h" + +#ifndef RIOT_VERSION + +int os_get_time(struct os_time *t) +{ + return gettimeofday((struct timeval*) t, NULL); +} + +unsigned long os_random(void) +{ + return esp_random(); +} + +unsigned long r_rand(void) __attribute__((alias("os_random"))); + + +int os_get_random(unsigned char *buf, size_t len) +{ + unsigned int i, j; + unsigned long tmp; + + for (i = 0; i < ((len + 3) & ~3) / 4; i++) { + tmp = r_rand(); + + for (j = 0; j < 4; j++) { + if ((i * 4 + j) < len) { + buf[i * 4 + j] = (uint8_t)(tmp >> (j * 8)); + } else { + break; + } + } + } + + return 0; +} + +#endif diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/Makefile b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/Makefile new file mode 100644 index 000000000000..5763af65ed61 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/Makefile @@ -0,0 +1,21 @@ +MODULE=esp_idf_wpa_supplicant_crypto + +include $(RIOTBASE)/Makefile.base + +# we have to do it in that way to avoid that $(RIOTBASE)/sys/include/crypto +# is found first +INCLUDES = -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/wpa_supplicant/include +INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/wpa_supplicant/port/include +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/wpa_supplicant/include +INCLUDES += -I$(ESP8266_RTOS_SDK_DIR)/components/wpa_supplicant/port/include +CFLAGS += -D__ets__ -DESPRESSIF_USE -DESP_PLATFORM=1 +CFLAGS += -Wno-strict-aliasing + +include $(RIOTCPU)/$(CPU)/Makefile.include + +INCLUDES += -I$(RIOTBASE)/core/include +INCLUDES += -I$(RIOTBASE)/sys/include +INCLUDES += -I$(RIOTCPU)/$(CPU)/vendor/esp-idf/log/include +INCLUDES += -I$(RIOTCPU)/$(CPU)/include +INCLUDES += -I$(RIOTBOARD)/$(BOARD)/include + diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-cbc.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-cbc.c new file mode 100644 index 000000000000..929e8d426d18 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-cbc.c @@ -0,0 +1,88 @@ +/* + * AES-128 CBC + * + * Copyright (c) 2003-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/aes.h" +#include "crypto/aes_wrap.h" + +/** + * aes_128_cbc_encrypt - AES-128 CBC encryption + * @key: Encryption key + * @iv: Encryption IV for CBC mode (16 bytes) + * @data: Data to encrypt in-place + * @data_len: Length of data in bytes (must be divisible by 16) + * Returns: 0 on success, -1 on failure + */ +int +wpa_aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) +{ + void *ctx; + u8 cbc[AES_BLOCK_SIZE]; + u8 *pos = data; + int i, j, blocks; + + ctx = wpa_aes_encrypt_init(key, 16); + if (ctx == NULL) + return -1; + os_memcpy(cbc, iv, AES_BLOCK_SIZE); + + blocks = data_len / AES_BLOCK_SIZE; + for (i = 0; i < blocks; i++) { + for (j = 0; j < AES_BLOCK_SIZE; j++) + cbc[j] ^= pos[j]; + wpa_aes_encrypt(ctx, cbc, cbc); + os_memcpy(pos, cbc, AES_BLOCK_SIZE); + pos += AES_BLOCK_SIZE; + } + wpa_aes_encrypt_deinit(ctx); + return 0; +} + + +/** + * aes_128_cbc_decrypt - AES-128 CBC decryption + * @key: Decryption key + * @iv: Decryption IV for CBC mode (16 bytes) + * @data: Data to decrypt in-place + * @data_len: Length of data in bytes (must be divisible by 16) + * Returns: 0 on success, -1 on failure + */ +int +wpa_aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) +{ + void *ctx; + u8 cbc[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE]; + u8 *pos = data; + int i, j, blocks; + + ctx = wpa_aes_decrypt_init(key, 16); + if (ctx == NULL) + return -1; + os_memcpy(cbc, iv, AES_BLOCK_SIZE); + + blocks = data_len / AES_BLOCK_SIZE; + for (i = 0; i < blocks; i++) { + os_memcpy(tmp, pos, AES_BLOCK_SIZE); + wpa_aes_decrypt(ctx, pos, pos); + for (j = 0; j < AES_BLOCK_SIZE; j++) + pos[j] ^= cbc[j]; + os_memcpy(cbc, tmp, AES_BLOCK_SIZE); + pos += AES_BLOCK_SIZE; + } + wpa_aes_decrypt_deinit(ctx); + return 0; +} diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-internal-dec.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-internal-dec.c new file mode 100644 index 000000000000..1351e3758781 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-internal-dec.c @@ -0,0 +1,172 @@ +/* + * AES (Rijndael) cipher - decrypt + * + * Modifications to public domain implementation: + * - support only 128-bit keys + * - cleanup + * - use C pre-processor to make it easier to change S table access + * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at + * cost of reduced throughput (quite small difference on Pentium 4, + * 10-25% when using -O1 or -O2 optimization) + * + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/crypto.h" +#include "crypto/aes_i.h" + + + +//static unsigned char aes_priv_buf[AES_PRIV_SIZE]; + +/** + * Expand the cipher key into the decryption key schedule. + * + * @return the number of rounds for the given cipher key size. + */ +static int wpa_rijndaelKeySetupDec(u32 rk[], const u8 cipherKey[], int keyBits) +{ + int Nr, i, j; + u32 temp; + + /* expand the cipher key: */ + Nr = wpa_rijndaelKeySetupEnc(rk, cipherKey, keyBits); + if (Nr < 0) + return Nr; + /* invert the order of the round keys: */ + for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) { + temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; + temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; + temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; + temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; + } + /* apply the inverse MixColumn transform to all round keys but the + * first and the last: */ + for (i = 1; i < Nr; i++) { + rk += 4; + for (j = 0; j < 4; j++) { + rk[j] = TD0_(TE4((rk[j] >> 24) )) ^ + TD1_(TE4((rk[j] >> 16) & 0xff)) ^ + TD2_(TE4((rk[j] >> 8) & 0xff)) ^ + TD3_(TE4((rk[j] ) & 0xff)); + } + } + + return Nr; +} + +void * wpa_aes_decrypt_init(const u8 *key, size_t len) +{ + u32 *rk; + int res; + rk = os_malloc(AES_PRIV_SIZE); + if (rk == NULL) + return NULL; + res = wpa_rijndaelKeySetupDec(rk, key, len * 8); + if (res < 0) { + os_free(rk); + return NULL; + } + rk[AES_PRIV_NR_POS] = res; + return rk; +} + +static void wpa_rijndaelDecrypt(const u32 rk[/*44*/], int Nr, const u8 ct[16], + u8 pt[16]) +{ + u32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(ct ) ^ rk[0]; + s1 = GETU32(ct + 4) ^ rk[1]; + s2 = GETU32(ct + 8) ^ rk[2]; + s3 = GETU32(ct + 12) ^ rk[3]; + +#define ROUND(i,d,s) \ +d##0 = TD0(s##0) ^ TD1(s##3) ^ TD2(s##2) ^ TD3(s##1) ^ rk[4 * i]; \ +d##1 = TD0(s##1) ^ TD1(s##0) ^ TD2(s##3) ^ TD3(s##2) ^ rk[4 * i + 1]; \ +d##2 = TD0(s##2) ^ TD1(s##1) ^ TD2(s##0) ^ TD3(s##3) ^ rk[4 * i + 2]; \ +d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3] + +#ifdef FULL_UNROLL + + ROUND(1,t,s); + ROUND(2,s,t); + ROUND(3,t,s); + ROUND(4,s,t); + ROUND(5,t,s); + ROUND(6,s,t); + ROUND(7,t,s); + ROUND(8,s,t); + ROUND(9,t,s); + if (Nr > 10) { + ROUND(10,s,t); + ROUND(11,t,s); + if (Nr > 12) { + ROUND(12,s,t); + ROUND(13,t,s); + } + } + + rk += Nr << 2; + +#else /* !FULL_UNROLL */ + + /* Nr - 1 full rounds: */ + r = Nr >> 1; + for (;;) { + ROUND(1,t,s); + rk += 8; + if (--r == 0) + break; + ROUND(0,s,t); + } + +#endif /* ?FULL_UNROLL */ + +#undef ROUND + + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = TD41(t0) ^ TD42(t3) ^ TD43(t2) ^ TD44(t1) ^ rk[0]; + PUTU32(pt , s0); + s1 = TD41(t1) ^ TD42(t0) ^ TD43(t3) ^ TD44(t2) ^ rk[1]; + PUTU32(pt + 4, s1); + s2 = TD41(t2) ^ TD42(t1) ^ TD43(t0) ^ TD44(t3) ^ rk[2]; + PUTU32(pt + 8, s2); + s3 = TD41(t3) ^ TD42(t2) ^ TD43(t1) ^ TD44(t0) ^ rk[3]; + PUTU32(pt + 12, s3); +} + +void wpa_aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) +{ + u32 *rk = ctx; + wpa_rijndaelDecrypt(ctx, rk[AES_PRIV_NR_POS], crypt, plain); +} + + +void wpa_aes_decrypt_deinit(void *ctx) +{ + os_memset(ctx, 0, AES_PRIV_SIZE); + os_free(ctx); +} diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-internal-enc.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-internal-enc.c new file mode 100644 index 000000000000..14ad0ab8b45c --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-internal-enc.c @@ -0,0 +1,134 @@ +/* + * AES (Rijndael) cipher - encrypt + * + * Modifications to public domain implementation: + * - support only 128-bit keys + * - cleanup + * - use C pre-processor to make it easier to change S table access + * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at + * cost of reduced throughput (quite small difference on Pentium 4, + * 10-25% when using -O1 or -O2 optimization) + * + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" +#include "crypto/common.h" +#include "crypto/crypto.h" +#include "crypto/aes_i.h" + +#include "os.h" + +void wpa_rijndaelEncrypt(const u32 rk[], int Nr, const u8 pt[16], u8 ct[16]) +{ + u32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(pt ) ^ rk[0]; + s1 = GETU32(pt + 4) ^ rk[1]; + s2 = GETU32(pt + 8) ^ rk[2]; + s3 = GETU32(pt + 12) ^ rk[3]; + +#define ROUND(i,d,s) \ +d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \ +d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \ +d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \ +d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3] + +#ifdef FULL_UNROLL + + ROUND(1,t,s); + ROUND(2,s,t); + ROUND(3,t,s); + ROUND(4,s,t); + ROUND(5,t,s); + ROUND(6,s,t); + ROUND(7,t,s); + ROUND(8,s,t); + ROUND(9,t,s); + if (Nr > 10) { + ROUND(10,s,t); + ROUND(11,t,s); + if (Nr > 12) { + ROUND(12,s,t); + ROUND(13,t,s); + } + } + + rk += Nr << 2; + +#else /* !FULL_UNROLL */ + + /* Nr - 1 full rounds: */ + r = Nr >> 1; + for (;;) { + ROUND(1,t,s); + rk += 8; + if (--r == 0) + break; + ROUND(0,s,t); + } + +#endif /* ?FULL_UNROLL */ + +#undef ROUND + + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0]; + PUTU32(ct , s0); + s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1]; + PUTU32(ct + 4, s1); + s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2]; + PUTU32(ct + 8, s2); + s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3]; + PUTU32(ct + 12, s3); +} + + +void * wpa_aes_encrypt_init(const u8 *key, size_t len) +{ + u32 *rk; + int res; + rk = os_malloc(AES_PRIV_SIZE); + if (rk == NULL) + return NULL; + res = wpa_rijndaelKeySetupEnc(rk, key, len * 8); + if (res < 0) { + os_free(rk); + return NULL; + } + rk[AES_PRIV_NR_POS] = res; + return rk; +} + + +void wpa_aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) +{ + u32 *rk = ctx; + wpa_rijndaelEncrypt(ctx, rk[AES_PRIV_NR_POS], plain, crypt); +} + + +void wpa_aes_encrypt_deinit(void *ctx) +{ + os_memset(ctx, 0, AES_PRIV_SIZE); + os_free(ctx); +} diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-internal.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-internal.c new file mode 100644 index 000000000000..9fec550b7aae --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-internal.c @@ -0,0 +1,857 @@ +/* + * AES (Rijndael) cipher + * + * Modifications to public domain implementation: + * - support only 128-bit keys + * - cleanup + * - use C pre-processor to make it easier to change S table access + * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at + * cost of reduced throughput (quite small difference on Pentium 4, + * 10-25% when using -O1 or -O2 optimization) + * + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ +#ifdef RIOT_VERSION +#pragma weak rijndaelKeySetupEnc +#endif + +#include "crypto/includes.h" + +//#include "wpa/common.h" +#include "crypto/common.h" +#include "crypto/crypto.h" +#include "crypto/aes_i.h" + +/* + * rijndael-alg-fst.c + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define AES_SMALL_TABLES + +/* +Te0[x] = S [x].[02, 01, 01, 03]; +Te1[x] = S [x].[03, 02, 01, 01]; +Te2[x] = S [x].[01, 03, 02, 01]; +Te3[x] = S [x].[01, 01, 03, 02]; +Te4[x] = S [x].[01, 01, 01, 01]; + +Td0[x] = Si[x].[0e, 09, 0d, 0b]; +Td1[x] = Si[x].[0b, 0e, 09, 0d]; +Td2[x] = Si[x].[0d, 0b, 0e, 09]; +Td3[x] = Si[x].[09, 0d, 0b, 0e]; +Td4[x] = Si[x].[01, 01, 01, 01]; +*/ + +const u32 Te0[256] /* ICACHE_RODATA_ATTR */ = { + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}; +#ifndef AES_SMALL_TABLES +const u32 Te1[256] /* ICACHE_RODATA_ATTR */ = { + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, + 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, + 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, + 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, + 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, + 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, + 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, + 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, + 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, + 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, + 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, + 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, + 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, + 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, + 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, + 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, + 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, + 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, + 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, + 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, + 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, + 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, + 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, + 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, + 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, + 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, + 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, + 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, + 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, + 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, + 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, + 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, + 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, + 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, + 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, + 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, + 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, + 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, + 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, + 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, + 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, + 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, + 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, + 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, + 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, + 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, + 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, + 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, + 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, + 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, + 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, + 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, +}; +const u32 Te2[256] /* ICACHE_RODATA_ATTR */ = { + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, + 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, + 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, + 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, + 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, + 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, + 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, + 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, + 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, + 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, + 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, + 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, + 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, + 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, + 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, + 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, + 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, + 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, + 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, + 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, + 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, + 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, + 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, + 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, + 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, + 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, + 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, + 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, + 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, + 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, + 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, + 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, + 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, + 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, + 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, + 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, + 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, + 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, + 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, + 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, + 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, + 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, + 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, + 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, + 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, + 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, + 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, + 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, + 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, + 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, + 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, + 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, +}; +const u32 Te3[256] /* ICACHE_RODATA_ATTR */ = { + + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, + 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, + 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, + 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, + 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, + 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, + 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, + 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, + 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, + 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, + 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, + 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, + 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, + 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, + 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, + 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, + 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, + 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, + 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, + 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, + 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, + 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, + 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, + 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, + 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, + 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, + 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, + 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, + 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, + 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, + 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, + 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, + 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, + 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, + 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, + 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, + 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, + 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, + 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, + 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, + 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, + 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, + 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, + 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, + 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, + 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, + 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, + 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, + 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, + 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, + 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, + 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, +}; +const u32 Te4[256] /* ICACHE_RODATA_ATTR */ = { + 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, + 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, + 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, + 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, + 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, + 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, + 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, + 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, + 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, + 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, + 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, + 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, + 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, + 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, + 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, + 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, + 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, + 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, + 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, + 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, + 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, + 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, + 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, + 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, + 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, + 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, + 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, + 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, + 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, + 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, + 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, + 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, + 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, + 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, + 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, + 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, + 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, + 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, + 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, + 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, + 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, + 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, + 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, + 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, + 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, + 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, + 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, + 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, + 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, + 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, + 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, + 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, + 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, + 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, + 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, + 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, + 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, + 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, + 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, + 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, + 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, + 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, + 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, + 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, +}; +#endif /* AES_SMALL_TABLES */ +const u32 Td0[256] /* ICACHE_RODATA_ATTR */ = { + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, + 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, + 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, + 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, + 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, + 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, + 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, + 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, + 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, + 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, + 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, + 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, + 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, + 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, + 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, + 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, + 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, + 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, + 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, + 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, + 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, + 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, + 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, + 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, + 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, + 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, + 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, + 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, + 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, + 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, + 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, + 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, + 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, + 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, + 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, + 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, + 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, + 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, + 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, + 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, + 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, + 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, + 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, + 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, + 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, + 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, + 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, + 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, + 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, + 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, + 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, + 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, +}; +#ifndef AES_SMALL_TABLES +const u32 Td1[256] /* ICACHE_RODATA_ATTR */ = { + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, + 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, + 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, + 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, + 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, + 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, + 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, + 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, + 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, + 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, + 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, + 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, + 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, + 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, + 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, + 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, + 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, + 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, + 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, + 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, + 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, + 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, + 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, + 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, + 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, + 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, + 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, + 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, + 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, + 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, + 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, + 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, + 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, + 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, + 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, + 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, + 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, + 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, + 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, + 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, + 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, + 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, + 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, + 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, + 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, + 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, + 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, + 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, + 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, + 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, + 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, + 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, + 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, + 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, + 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, + 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, + 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, + 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, +}; +const u32 Td2[256] /* ICACHE_RODATA_ATTR */ = { + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, + 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, + 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, + 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, + 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, + 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, + 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, + 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, + 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, + 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, + 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, + 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, + 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, + 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, + 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, + 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, + 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, + 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, + 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, + 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, + 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, + 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, + 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, + 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, + 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, + 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, + 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, + 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, + 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, + 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, + 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, + 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, + 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, + 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, + 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, + 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, + 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, + 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, + 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, + 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, + 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, + 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, + 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, + 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, + 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, + 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, + 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, + 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, + 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, + 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, + 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, + 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, + 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, + 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, + 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, + 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, + 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, + 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, +}; +const u32 Td3[256] /* ICACHE_RODATA_ATTR */ = { + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, + 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, + 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, + 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, + 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, + 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, + 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, + 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, + 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, + 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, + 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, + 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, + 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, + 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, + 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, + 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, + 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, + 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, + 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, + 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, + 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, + 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, + 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, + 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, + 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, + 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, + 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, + 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, + 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, + 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, + 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, + 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, + 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, + 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, + 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, + 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, + 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, + 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, + 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, + 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, + 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, + 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, + 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, + 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, + 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, + 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, + 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, + 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, + 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, + 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, + 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, + 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, + 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, + 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, + 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, + 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, + 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, + 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, +}; +const u32 Td4[256] /* ICACHE_RODATA_ATTR */ = { + 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, + 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, + 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, + 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, + 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, + 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, + 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, + 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, + 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, + 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, + 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, + 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, + 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, + 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, + 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, + 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, + 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, + 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, + 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, + 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, + 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, + 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, + 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, + 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, + 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, + 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, + 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, + 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, + 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, + 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, + 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, + 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, + 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, + 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, + 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, + 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, + 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, + 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, + 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, + 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, + 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, + 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, + 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, + 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, + 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, + 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, + 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, + 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, + 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, + 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, + 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, + 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, + 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, + 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, + 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, + 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, + 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, + 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, + 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, + 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, + 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, + 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, + 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, + 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, +}; +const u32 rcon[] /* ICACHE_RODATA_ATTR */ = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; +#else /* AES_SMALL_TABLES */ +const u8 Td4s[256] /* ICACHE_RODATA_ATTR */ = { + 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, + 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, + 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, + 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, + 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, + 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, + 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, + 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, + 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, + 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, + 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, + 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, + 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, + 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, + 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, + 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, + 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, + 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, + 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, + 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, + 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, + 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, + 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, + 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, + 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, + 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, + 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, + 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, + 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, + 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, + 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, + 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, +}; +const u8 rcons[] /* ICACHE_RODATA_ATTR */ = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 + /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; +#endif /* AES_SMALL_TABLES */ +/** + * Expand the cipher key into the encryption key schedule. + * + * @return the number of rounds for the given cipher key size. + */ +int wpa_rijndaelKeySetupEnc(u32 rk[], const u8 cipherKey[], int keyBits) +{ + int i; + u32 temp; + + rk[0] = GETU32(cipherKey ); + rk[1] = GETU32(cipherKey + 4); + rk[2] = GETU32(cipherKey + 8); + rk[3] = GETU32(cipherKey + 12); + + if (keyBits == 128) { + for (i = 0; i < 10; i++) { + temp = rk[3]; + rk[4] = rk[0] ^ TE421(temp) ^ TE432(temp) ^ + TE443(temp) ^ TE414(temp) ^ RCON(i); + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + rk += 4; + } + return 10; + } + + rk[4] = GETU32(cipherKey + 16); + rk[5] = GETU32(cipherKey + 20); + + if (keyBits == 192) { + for (i = 0; i < 8; i++) { + temp = rk[5]; + rk[6] = rk[0] ^ TE421(temp) ^ TE432(temp) ^ + TE443(temp) ^ TE414(temp) ^ RCON(i); + rk[7] = rk[1] ^ rk[6]; + rk[8] = rk[2] ^ rk[7]; + rk[9] = rk[3] ^ rk[8]; + if (i == 7) + return 12; + rk[10] = rk[4] ^ rk[9]; + rk[11] = rk[5] ^ rk[10]; + rk += 6; + } + } + + rk[6] = GETU32(cipherKey + 24); + rk[7] = GETU32(cipherKey + 28); + + if (keyBits == 256) { + for (i = 0; i < 7; i++) { + temp = rk[7]; + rk[8] = rk[0] ^ TE421(temp) ^ TE432(temp) ^ + TE443(temp) ^ TE414(temp) ^ RCON(i); + rk[9] = rk[1] ^ rk[8]; + rk[10] = rk[2] ^ rk[9]; + rk[11] = rk[3] ^ rk[10]; + if (i == 6) + return 14; + temp = rk[11]; + rk[12] = rk[4] ^ TE411(temp) ^ TE422(temp) ^ + TE433(temp) ^ TE444(temp); + rk[13] = rk[5] ^ rk[12]; + rk[14] = rk[6] ^ rk[13]; + rk[15] = rk[7] ^ rk[14]; + rk += 8; + } + } + + return -1; +} diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-unwrap.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-unwrap.c new file mode 100644 index 000000000000..29767caebd8a --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-unwrap.c @@ -0,0 +1,80 @@ +/* + * AES key unwrap (128-bit KEK, RFC3394) + * + * Copyright (c) 2003-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/aes.h" +#include "crypto/aes_wrap.h" + +/** + * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) + * @kek: Key encryption key (KEK) + * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 + * bytes + * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits + * @plain: Plaintext key, n * 64 bits + * Returns: 0 on success, -1 on failure (e.g., integrity verification failed) + */ +int +wpa_aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain) +{ + u8 a[8], *r, b[16]; + int i, j; + void *ctx; + + /* 1) Initialize variables. */ + os_memcpy(a, cipher, 8); + r = plain; + os_memcpy(r, cipher + 8, 8 * n); + + ctx = wpa_aes_decrypt_init(kek, 16); + if (ctx == NULL) + return -1; + + /* 2) Compute intermediate values. + * For j = 5 to 0 + * For i = n to 1 + * B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i + * A = MSB(64, B) + * R[i] = LSB(64, B) + */ + for (j = 5; j >= 0; j--) { + r = plain + (n - 1) * 8; + for (i = n; i >= 1; i--) { + os_memcpy(b, a, 8); + b[7] ^= n * j + i; + + os_memcpy(b + 8, r, 8); + wpa_aes_decrypt(ctx, b, b); + os_memcpy(a, b, 8); + os_memcpy(r, b + 8, 8); + r -= 8; + } + } + wpa_aes_decrypt_deinit(ctx); + + /* 3) Output results. + * + * These are already in @plain due to the location of temporary + * variables. Just verify that the IV matches with the expected value. + */ + for (i = 0; i < 8; i++) { + if (a[i] != 0xa6) + return -1; + } + + return 0; +} diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-wrap.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-wrap.c new file mode 100644 index 000000000000..756967af1b4a --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/aes-wrap.c @@ -0,0 +1,70 @@ +/* + * AES Key Wrap Algorithm (128-bit KEK) (RFC3394) + * + * Copyright (c) 2003-2007, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/aes.h" +#include "crypto/aes_wrap.h" + +/** + * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) + * @kek: 16-octet Key encryption key (KEK) + * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 + * bytes + * @plain: Plaintext key to be wrapped, n * 64 bits + * @cipher: Wrapped key, (n + 1) * 64 bits + * Returns: 0 on success, -1 on failure + */ +int wpa_aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) +{ + u8 *a, *r, b[16]; + int i, j; + void *ctx; + + a = cipher; + r = cipher + 8; + + /* 1) Initialize variables. */ + os_memset(a, 0xa6, 8); + os_memcpy(r, plain, 8 * n); + + ctx = wpa_aes_encrypt_init(kek, 16); + if (ctx == NULL) + return -1; + + /* 2) Calculate intermediate values. + * For j = 0 to 5 + * For i=1 to n + * B = AES(K, A | R[i]) + * A = MSB(64, B) ^ t where t = (n*j)+i + * R[i] = LSB(64, B) + */ + for (j = 0; j <= 5; j++) { + r = cipher + 8; + for (i = 1; i <= n; i++) { + os_memcpy(b, a, 8); + os_memcpy(b + 8, r, 8); + wpa_aes_encrypt(ctx, b, b); + os_memcpy(a, b, 8); + a[7] ^= n * j + i; + os_memcpy(r, b + 8, 8); + r += 8; + } + } + wpa_aes_encrypt_deinit(ctx); + + /* 3) Output the results. + * + * These are already in @cipher due to the location of temporary + * variables. + */ + + return 0; +} diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/bignum.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/bignum.c new file mode 100644 index 000000000000..7b8446c3baee --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/bignum.c @@ -0,0 +1,244 @@ +/* + * Big number math + * Copyright (c) 2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" +#include "crypto/common.h" +#include "wpa/wpabuf.h" +#include "wpa/wpa_debug.h" +#include "bignum.h" + +#define CONFIG_INTERNAL_LIBTOMMATH +#ifdef CONFIG_INTERNAL_LIBTOMMATH +#include "libtommath.h" +#else /* CONFIG_INTERNAL_LIBTOMMATH */ +#include +#endif /* CONFIG_INTERNAL_LIBTOMMATH */ + + +/* + * The current version is just a wrapper for LibTomMath library, so + * struct bignum is just typecast to mp_int. + */ + +/** + * bignum_init - Allocate memory for bignum + * Returns: Pointer to allocated bignum or %NULL on failure + */ +struct bignum * +bignum_init(void) +{ + struct bignum *n = (struct bignum *)os_zalloc(sizeof(mp_int)); + if (n == NULL) + return NULL; + if (mp_init((mp_int *) n) != MP_OKAY) { + os_free(n); + n = NULL; + } + return n; +} + + +/** + * bignum_deinit - Free bignum + * @n: Bignum from bignum_init() + */ +void +bignum_deinit(struct bignum *n) +{ + if (n) { + mp_clear((mp_int *) n); + os_free(n); + } +} + + +/** + * bignum_get_unsigned_bin - Get length of bignum as an unsigned binary buffer + * @n: Bignum from bignum_init() + * Returns: Length of n if written to a binary buffer + */ +size_t +bignum_get_unsigned_bin_len(struct bignum *n) +{ + return mp_unsigned_bin_size((mp_int *) n); +} + + +/** + * bignum_get_unsigned_bin - Set binary buffer to unsigned bignum + * @n: Bignum from bignum_init() + * @buf: Buffer for the binary number + * @len: Length of the buffer, can be %NULL if buffer is known to be long + * enough. Set to used buffer length on success if not %NULL. + * Returns: 0 on success, -1 on failure + */ +int +bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len) +{ + size_t need = mp_unsigned_bin_size((mp_int *) n); + if (len && need > *len) { + *len = need; + return -1; + } + if (mp_to_unsigned_bin((mp_int *) n, buf) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + if (len) + *len = need; + return 0; +} + + +/** + * bignum_set_unsigned_bin - Set bignum based on unsigned binary buffer + * @n: Bignum from bignum_init(); to be set to the given value + * @buf: Buffer with unsigned binary value + * @len: Length of buf in octets + * Returns: 0 on success, -1 on failure + */ +int +bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len) +{ + if (mp_read_unsigned_bin((mp_int *) n, (u8 *) buf, len) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_cmp - Signed comparison + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * Returns: 0 on success, -1 on failure + */ +int +bignum_cmp(const struct bignum *a, const struct bignum *b) +{ + return mp_cmp((mp_int *) a, (mp_int *) b); +} + + +/** + * bignum_cmd_d - Compare bignum to standard integer + * @a: Bignum from bignum_init() + * @b: Small integer + * Returns: 0 on success, -1 on failure + */ +int +bignum_cmp_d(const struct bignum *a, unsigned long b) +{ + return mp_cmp_d((mp_int *) a, b); +} + + +/** + * bignum_add - c = a + b + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * @c: Bignum from bignum_init(); used to store the result of a + b + * Returns: 0 on success, -1 on failure + */ +int +bignum_add(const struct bignum *a, const struct bignum *b, + struct bignum *c) +{ + if (mp_add((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_sub - c = a - b + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * @c: Bignum from bignum_init(); used to store the result of a - b + * Returns: 0 on success, -1 on failure + */ +int +bignum_sub(const struct bignum *a, const struct bignum *b, + struct bignum *c) +{ + if (mp_sub((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_mul - c = a * b + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * @c: Bignum from bignum_init(); used to store the result of a * b + * Returns: 0 on success, -1 on failure + */ +int +bignum_mul(const struct bignum *a, const struct bignum *b, + struct bignum *c) +{ + if (mp_mul((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_mulmod - d = a * b (mod c) + * @a: Bignum from bignum_init() + * @b: Bignum from bignum_init() + * @c: Bignum from bignum_init(); modulus + * @d: Bignum from bignum_init(); used to store the result of a * b (mod c) + * Returns: 0 on success, -1 on failure + */ +int +bignum_mulmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d) +{ + if (mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d) + != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} + + +/** + * bignum_exptmod - Modular exponentiation: d = a^b (mod c) + * @a: Bignum from bignum_init(); base + * @b: Bignum from bignum_init(); exponent + * @c: Bignum from bignum_init(); modulus + * @d: Bignum from bignum_init(); used to store the result of a^b (mod c) + * Returns: 0 on success, -1 on failure + */ +int +bignum_exptmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d) +{ + if (mp_exptmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d) + != MP_OKAY) { + wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__); + return -1; + } + return 0; +} diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/bignum.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/bignum.h new file mode 100644 index 000000000000..f25e26783a0a --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/bignum.h @@ -0,0 +1,38 @@ +/* + * Big number math + * Copyright (c) 2006, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#ifndef BIGNUM_H +#define BIGNUM_H + +struct bignum; + +struct bignum * bignum_init(void); +void bignum_deinit(struct bignum *n); +size_t bignum_get_unsigned_bin_len(struct bignum *n); +int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len); +int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len); +int bignum_cmp(const struct bignum *a, const struct bignum *b); +int bignum_cmp_d(const struct bignum *a, unsigned long b); +int bignum_add(const struct bignum *a, const struct bignum *b, + struct bignum *c); +int bignum_sub(const struct bignum *a, const struct bignum *b, + struct bignum *c); +int bignum_mul(const struct bignum *a, const struct bignum *b, + struct bignum *c); +int bignum_mulmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d); +int bignum_exptmod(const struct bignum *a, const struct bignum *b, + const struct bignum *c, struct bignum *d); + +#endif /* BIGNUM_H */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/crypto_internal-modexp.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/crypto_internal-modexp.c new file mode 100644 index 000000000000..ea978570057a --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/crypto_internal-modexp.c @@ -0,0 +1,56 @@ +/* + * Crypto wrapper for internal crypto implementation - modexp + * Copyright (c) 2006-2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "bignum.h" +#include "crypto/crypto.h" + + +int +crypto_mod_exp(const u8 *base, size_t base_len, + const u8 *power, size_t power_len, + const u8 *modulus, size_t modulus_len, + u8 *result, size_t *result_len) +{ + struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result; + int ret = -1; + + bn_base = bignum_init(); + bn_exp = bignum_init(); + bn_modulus = bignum_init(); + bn_result = bignum_init(); + + if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL || + bn_result == NULL) + goto error; + + if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 || + bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 || + bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0) + goto error; + + if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0) + goto error; + + ret = bignum_get_unsigned_bin(bn_result, result, result_len); + +error: + bignum_deinit(bn_base); + bignum_deinit(bn_exp); + bignum_deinit(bn_modulus); + bignum_deinit(bn_result); + return ret; +} diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/dh_group5.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/dh_group5.c new file mode 100644 index 000000000000..6c4f9512b240 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/dh_group5.c @@ -0,0 +1,43 @@ +/* + * Diffie-Hellman group 5 operations + * Copyright (c) 2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/dh_groups.h" +#include "crypto/dh_group5.h" + + +void * +wpa_dh5_init(struct wpabuf **priv, struct wpabuf **publ) +{ + *publ = wpa_dh_init(wpa_dh_groups_get(5), priv); + if (*publ == 0) + return NULL; + return (void *) 1; +} + + +struct wpabuf * +wpa_dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, + const struct wpabuf *own_private) +{ + return wpa_dh_derive_shared(peer_public, own_private, wpa_dh_groups_get(5)); +} + + +void +wpa_dh5_free(void *ctx) +{ +} diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/dh_groups.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/dh_groups.c new file mode 100644 index 000000000000..d963513adf52 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/dh_groups.c @@ -0,0 +1,641 @@ +/* + * Diffie-Hellman groups + * Copyright (c) 2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/crypto.h" +#include "crypto/random.h" +#include "crypto/dh_groups.h" +#include "wpa/wpabuf.h" +#include "wpa/wpa_debug.h" + +extern int crypto_mod_exp(const u8 *base, size_t base_len, + const u8 *power, size_t power_len, + const u8 *modulus, size_t modulus_len, + u8 *result, size_t *result_len); + +#ifdef ALL_DH_GROUPS + +/* RFC 4306, B.1. Group 1 - 768 Bit MODP + * Generator: 2 + * Prime: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 } + */ +static const u8 dh_group1_generator[1] = { 0x02 }; +static const u8 dh_group1_prime[96] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x3A, 0x36, 0x20, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/* RFC 4306, B.2. Group 2 - 1024 Bit MODP + * Generator: 2 + * Prime: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } + */ +static const u8 dh_group2_generator[1] = { 0x02 }; +static const u8 dh_group2_prime[128] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +#endif /* ALL_DH_GROUPS */ + +/* RFC 3526, 2. Group 5 - 1536 Bit MODP + * Generator: 2 + * Prime: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 } + */ +static const u8 dh_group5_generator[1] = { 0x02 }; +static const u8 dh_group5_prime[192] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, + 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, + 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +#ifdef ALL_DH_GROUPS + +/* RFC 3526, 3. Group 14 - 2048 Bit MODP + * Generator: 2 + * Prime: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 } + */ +static const u8 dh_group14_generator[1] = { 0x02 }; +static const u8 dh_group14_prime[256] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, + 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, + 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, + 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, + 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, + 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, + 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, + 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/* RFC 3526, 4. Group 15 - 3072 Bit MODP + * Generator: 2 + * Prime: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 } + */ +static const u8 dh_group15_generator[1] = { 0x02 }; +static const u8 dh_group15_prime[384] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, + 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, + 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, + 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, + 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, + 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, + 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, + 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, + 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, + 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, + 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, + 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, + 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, + 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, + 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, + 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, + 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, + 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, + 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, + 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, + 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, + 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, + 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, + 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/* RFC 3526, 5. Group 16 - 4096 Bit MODP + * Generator: 2 + * Prime: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 } + */ +static const u8 dh_group16_generator[1] = { 0x02 }; +static const u8 dh_group16_prime[512] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, + 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, + 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, + 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, + 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, + 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, + 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, + 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, + 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, + 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, + 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, + 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, + 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, + 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, + 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, + 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, + 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, + 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, + 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, + 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, + 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, + 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, + 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, + 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, + 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, + 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, + 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, + 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, + 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, + 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, + 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, + 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, + 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, + 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, + 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, + 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, + 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, + 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, + 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, + 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/* RFC 3526, 6. Group 17 - 6144 Bit MODP + * Generator: 2 + * Prime: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 } + */ +static const u8 dh_group17_generator[1] = { 0x02 }; +static const u8 dh_group17_prime[768] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, + 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, + 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, + 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, + 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, + 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, + 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, + 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, + 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, + 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, + 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, + 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, + 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, + 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, + 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, + 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, + 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, + 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, + 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, + 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, + 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, + 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, + 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, + 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, + 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, + 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, + 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, + 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, + 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, + 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, + 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, + 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, + 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, + 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, + 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, + 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, + 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, + 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, + 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, + 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92, + 0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26, + 0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE, + 0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD, + 0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E, + 0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE, + 0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, + 0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18, + 0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED, + 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B, + 0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B, + 0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42, + 0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF, + 0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, + 0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03, + 0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6, + 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82, + 0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E, + 0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3, + 0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE, + 0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5, + 0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA, + 0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8, + 0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0, + 0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28, + 0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76, + 0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0, + 0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C, + 0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32, + 0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68, + 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE, + 0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6, + 0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xCC, 0x40, 0x24, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/* RFC 3526, 7. Group 18 - 8192 Bit MODP + * Generator: 2 + * Prime: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 } + */ +static const u8 dh_group18_generator[1] = { 0x02 }; +static const u8 dh_group18_prime[1024] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, + 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, + 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, + 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, + 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, + 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, + 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, + 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, + 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, + 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, + 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, + 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, + 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, + 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, + 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, + 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, + 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, + 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, + 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, + 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, + 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, + 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, + 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, + 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, + 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, + 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, + 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, + 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, + 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, + 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, + 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, + 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, + 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, + 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, + 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, + 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, + 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, + 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, + 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, + 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92, + 0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26, + 0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE, + 0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD, + 0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E, + 0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE, + 0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, + 0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18, + 0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED, + 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B, + 0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B, + 0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42, + 0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF, + 0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, + 0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03, + 0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6, + 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82, + 0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E, + 0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3, + 0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE, + 0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5, + 0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA, + 0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8, + 0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0, + 0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28, + 0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76, + 0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0, + 0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C, + 0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32, + 0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68, + 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE, + 0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6, + 0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xBE, 0x11, 0x59, + 0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4, + 0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C, + 0xD8, 0xBE, 0xC4, 0xD0, 0x73, 0xB9, 0x31, 0xBA, + 0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00, + 0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED, + 0x25, 0x76, 0xF6, 0x93, 0x6B, 0xA4, 0x24, 0x66, + 0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68, + 0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78, + 0x23, 0x8F, 0x16, 0xCB, 0xE3, 0x9D, 0x65, 0x2D, + 0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9, + 0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07, + 0x13, 0xEB, 0x57, 0xA8, 0x1A, 0x23, 0xF0, 0xC7, + 0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B, + 0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD, + 0xFA, 0x9D, 0x4B, 0x7F, 0xA2, 0xC0, 0x87, 0xE8, + 0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A, + 0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6, + 0x6D, 0x2A, 0x13, 0xF8, 0x3F, 0x44, 0xF8, 0x2D, + 0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36, + 0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1, + 0x64, 0xF3, 0x1C, 0xC5, 0x08, 0x46, 0x85, 0x1D, + 0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1, + 0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73, + 0xFA, 0xF3, 0x6B, 0xC3, 0x1E, 0xCF, 0xA2, 0x68, + 0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92, + 0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7, + 0x88, 0x9A, 0x00, 0x2E, 0xD5, 0xEE, 0x38, 0x2B, + 0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47, + 0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA, + 0x9E, 0x30, 0x50, 0xE2, 0x76, 0x56, 0x94, 0xDF, + 0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71, + 0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +#endif /* ALL_DH_GROUPS */ + + +#define DH_GROUP(id) \ +{ id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \ +dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime) } + + +static struct dh_group dh_groups[] = { + DH_GROUP(5), +#ifdef ALL_DH_GROUPS + DH_GROUP(1), + DH_GROUP(2), + DH_GROUP(14), + DH_GROUP(15), + DH_GROUP(16), + DH_GROUP(17), + DH_GROUP(18) +#endif /* ALL_DH_GROUPS */ +}; + +#define NUM_DH_GROUPS (sizeof(dh_groups) / sizeof(dh_groups[0])) + + +const struct dh_group * +wpa_dh_groups_get(int id) +{ + size_t i; + + for (i = 0; i < NUM_DH_GROUPS; i++) { + if (dh_groups[i].id == id) + return &dh_groups[i]; + } + return NULL; +} + +/** + * dh_init - Initialize Diffie-Hellman handshake + * @dh: Selected Diffie-Hellman group + * @priv: Pointer for returning Diffie-Hellman private key + * Returns: Diffie-Hellman public value + */ +struct wpabuf * +wpa_dh_init(const struct dh_group *dh, struct wpabuf **priv) +{ + struct wpabuf *pv; + size_t pv_len; + + if (dh == NULL) + return NULL; + + wpabuf_free(*priv); + *priv = wpabuf_alloc(dh->prime_len); + if (*priv == NULL) + return NULL; + + if (random_get_bytes(wpabuf_put(*priv, dh->prime_len), dh->prime_len)) + { + wpabuf_free(*priv); + *priv = NULL; + return NULL; + } + + if (os_memcmp(wpabuf_head(*priv), dh->prime, dh->prime_len) > 0) { + /* Make sure private value is smaller than prime */ + *(wpabuf_mhead_u8(*priv)) = 0; + } + wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv); + + pv_len = dh->prime_len; + pv = wpabuf_alloc(pv_len); + if (pv == NULL) + return NULL; + if (crypto_mod_exp(dh->generator, dh->generator_len, + wpabuf_head(*priv), wpabuf_len(*priv), + dh->prime, dh->prime_len, wpabuf_mhead(pv), + &pv_len) < 0) { + wpabuf_free(pv); + wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); + return NULL; + } + wpabuf_put(pv, pv_len); + wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv); + + return pv; +} + + +/** + * dh_derive_shared - Derive shared Diffie-Hellman key + * @peer_public: Diffie-Hellman public value from peer + * @own_private: Diffie-Hellman private key from dh_init() + * @dh: Selected Diffie-Hellman group + * Returns: Diffie-Hellman shared key + */ +struct wpabuf * +wpa_dh_derive_shared(const struct wpabuf *peer_public, + const struct wpabuf *own_private, + const struct dh_group *dh) +{ + struct wpabuf *shared; + size_t shared_len; + + if (dh == NULL || peer_public == NULL || own_private == NULL) + return NULL; + + shared_len = dh->prime_len; + shared = wpabuf_alloc(shared_len); + if (shared == NULL) + return NULL; + if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public), + wpabuf_head(own_private), wpabuf_len(own_private), + dh->prime, dh->prime_len, + wpabuf_mhead(shared), &shared_len) < 0) { + wpabuf_free(shared); + wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed"); + return NULL; + } + wpabuf_put(shared, shared_len); + wpa_hexdump_buf_key(MSG_DEBUG, "DH: shared key", shared); + + return shared; +} diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/libtommath.h b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/libtommath.h new file mode 100644 index 000000000000..2a42aa07cebc --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/libtommath.h @@ -0,0 +1,3444 @@ +/* + * Minimal code for RSA support from LibTomMath 0.41 + * http://libtom.org/ + * http://libtom.org/files/ltm-0.41.tar.bz2 + * This library was released in public domain by Tom St Denis. + * + * The combination in this file may not use all of the optimized algorithms + * from LibTomMath and may be considerable slower than the LibTomMath with its + * default settings. The main purpose of having this version here is to make it + * easier to build bignum.c wrapper without having to install and build an + * external library. + * + * If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this + * libtommath.c file instead of using the external LibTomMath library. + */ +//#include "c_types.h" +#include "os.h" +#include "stdarg.h" + +#if CONFIG_LTM_FAST +#define LTM_FAST +#endif + +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +#define BN_MP_INVMOD_C +#define BN_S_MP_EXPTMOD_C /* Note: #undef in tommath_superclass.h; this would + * require BN_MP_EXPTMOD_FAST_C instead */ +#define BN_S_MP_MUL_DIGS_C +#define BN_MP_INVMOD_SLOW_C +#define BN_S_MP_SQR_C +#define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this + * would require other than mp_reduce */ + +#ifdef LTM_FAST + +/* Use faster div at the cost of about 1 kB */ +#define BN_MP_MUL_D_C + +/* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */ +#define BN_MP_EXPTMOD_FAST_C +#define BN_MP_MONTGOMERY_SETUP_C +#define BN_FAST_MP_MONTGOMERY_REDUCE_C +#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C +#define BN_MP_MUL_2_C + +/* Include faster sqr at the cost of about 0.5 kB in code */ +#define BN_FAST_S_MP_SQR_C + +#else /* LTM_FAST */ + +#define BN_MP_DIV_SMALL +#define BN_MP_INIT_MULTI_C +#define BN_MP_CLEAR_MULTI_C +#define BN_MP_ABS_C +#endif /* LTM_FAST */ + +/* Current uses do not require support for negative exponent in exptmod, so we + * can save about 1.5 kB in leaving out invmod. */ +#define LTM_NO_NEG_EXP + +/* from tommath.h */ + +#ifndef MIN + #define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + +#ifndef MAX + #define MAX(x,y) ((x)>(y)?(x):(y)) +#endif + +#define OPT_CAST(x) (x *) + +typedef unsigned long mp_digit; +typedef u64 mp_word; + +#define DIGIT_BIT 28 +#define MP_28BIT + + +#define XMALLOC _xmalloc +#define XFREE _xfree +#define XREALLOC _xrealloc + + +#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1)) + +#define MP_LT -1 /* less than */ +#define MP_EQ 0 /* equal to */ +#define MP_GT 1 /* greater than */ + +#define MP_ZPOS 0 /* positive integer */ +#define MP_NEG 1 /* negative */ + +#define MP_OKAY 0 /* ok result */ +#define MP_MEM -2 /* out of mem */ +#define MP_VAL -3 /* invalid input */ + +#define MP_YES 1 /* yes response */ +#define MP_NO 0 /* no response */ + +typedef int mp_err; + +/* define this to use lower memory usage routines (exptmods mostly) */ +#define MP_LOW_MEM + +/* default precision */ +#ifndef MP_PREC + #ifndef MP_LOW_MEM + #define MP_PREC 32 /* default digits of precision */ + #else + #define MP_PREC 8 /* default digits of precision */ + #endif +#endif + +/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */ +#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1)) + +/* the infamous mp_int structure */ +typedef struct { + int used, alloc, sign; + mp_digit *dp; +} mp_int; + + +/* ---> Basic Manipulations <--- */ +#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO) +#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO) +#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO) + + +/* prototypes for copied functions */ +#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) +static int s_mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode); +static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs); +static int s_mp_sqr(mp_int * a, mp_int * b); +static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs); + +static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs); + +#ifdef BN_MP_INIT_MULTI_C +static int mp_init_multi(mp_int *mp, ...); +#endif +#ifdef BN_MP_CLEAR_MULTI_C +static void mp_clear_multi(mp_int *mp, ...); +#endif +static int mp_lshd(mp_int * a, int b); +static void mp_set(mp_int * a, mp_digit b); +static void mp_clamp(mp_int * a); +static void mp_exch(mp_int * a, mp_int * b); +static void mp_rshd(mp_int * a, int b); +static void mp_zero(mp_int * a); +static int mp_mod_2d(mp_int * a, int b, mp_int * c); +static int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d); +static int mp_init_copy(mp_int * a, mp_int * b); +static int mp_mul_2d(mp_int * a, int b, mp_int * c); +#ifndef LTM_NO_NEG_EXP +static int mp_div_2(mp_int * a, mp_int * b); +static int mp_invmod(mp_int * a, mp_int * b, mp_int * c); +static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c); +#endif /* LTM_NO_NEG_EXP */ +static int mp_copy(mp_int * a, mp_int * b); +static int mp_count_bits(mp_int * a); +static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d); +static int mp_mod(mp_int * a, mp_int * b, mp_int * c); +static int mp_grow(mp_int * a, int size); +static int mp_cmp_mag(mp_int * a, mp_int * b); +#ifdef BN_MP_ABS_C +static int mp_abs(mp_int * a, mp_int * b); +#endif +static int mp_sqr(mp_int * a, mp_int * b); +static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d); +static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d); +static int mp_2expt(mp_int * a, int b); +static int mp_reduce_setup(mp_int * a, mp_int * b); +static int mp_reduce(mp_int * x, mp_int * m, mp_int * mu); +static int mp_init_size(mp_int * a, int size); +#ifdef BN_MP_EXPTMOD_FAST_C +static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode); +#endif /* BN_MP_EXPTMOD_FAST_C */ +#ifdef BN_FAST_S_MP_SQR_C +static int fast_s_mp_sqr (mp_int * a, mp_int * b); +#endif /* BN_FAST_S_MP_SQR_C */ +#ifdef BN_MP_MUL_D_C +static int mp_mul_d (mp_int * a, mp_digit b, mp_int * c); +#endif /* BN_MP_MUL_D_C */ + + + +/* functions from bn_.c */ + + +/* reverse an array, used for radix code */ +static void +bn_reverse (unsigned char *s, int len) +{ + int ix, iy; + unsigned char t; + + ix = 0; + iy = len - 1; + while (ix < iy) { + t = s[ix]; + s[ix] = s[iy]; + s[iy] = t; + ++ix; + --iy; + } +} + + +/* low level addition, based on HAC pp.594, Algorithm 14.7 */ +static int +s_mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int *x; + int olduse, res, min, max; + + /* find sizes, we let |a| <= |b| which means we have to sort + * them. "x" will point to the input with the most digits + */ + if (a->used > b->used) { + min = b->used; + max = a->used; + x = a; + } else { + min = a->used; + max = b->used; + x = b; + } + + /* init result */ + if (c->alloc < max + 1) { + if ((res = mp_grow (c, max + 1)) != MP_OKAY) { + return res; + } + } + + /* get old used digit count and set new one */ + olduse = c->used; + c->used = max + 1; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + + /* first input */ + tmpa = a->dp; + + /* second input */ + tmpb = b->dp; + + /* destination */ + tmpc = c->dp; + + /* zero the carry */ + u = 0; + for (i = 0; i < min; i++) { + /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ + *tmpc = *tmpa++ + *tmpb++ + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, that is in A+B + * if A or B has more digits add those in + */ + if (min != max) { + for (; i < max; i++) { + /* T[i] = X[i] + U */ + *tmpc = x->dp[i] + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + } + + /* add carry */ + *tmpc++ = u; + + /* clear digits above oldused */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + + +/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ +static int +s_mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int olduse, res, min, max; + + /* find sizes */ + min = b->used; + max = a->used; + + /* init result */ + if (c->alloc < max) { + if ((res = mp_grow (c, max)) != MP_OKAY) { + return res; + } + } + olduse = c->used; + c->used = max; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + tmpa = a->dp; + tmpb = b->dp; + tmpc = c->dp; + + /* set carry to zero */ + u = 0; + for (i = 0; i < min; i++) { + /* T[i] = A[i] - B[i] - U */ + *tmpc = *tmpa++ - *tmpb++ - u; + + /* U = carry bit of T[i] + * Note this saves performing an AND operation since + * if a carry does occur it will propagate all the way to the + * MSB. As a result a single shift is enough to get the carry + */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, e.g. if A has more digits than B */ + for (; i < max; i++) { + /* T[i] = A[i] - U */ + *tmpc = *tmpa++ - u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* clear digits above used (since we may not have grown result above) */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + + +/* init a new mp_int */ +static int +mp_init (mp_int * a) +{ + int i; + + /* allocate memory required and clear it */ + a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the digits to zero */ + for (i = 0; i < MP_PREC; i++) { + a->dp[i] = 0; + } + + /* set the used to zero, allocated digits to the default precision + * and sign to positive */ + a->used = 0; + a->alloc = MP_PREC; + a->sign = MP_ZPOS; + + return MP_OKAY; +} + + +/* clear one (frees) */ +static void +mp_clear (mp_int * a) +{ + int i; + + /* only do anything if a hasn't been freed previously */ + if (a->dp != NULL) { + /* first zero the digits */ + for (i = 0; i < a->used; i++) { + a->dp[i] = 0; + } + + /* free ram */ + XFREE(a->dp); + + /* reset members to make debugging easier */ + a->dp = NULL; + a->alloc = a->used = 0; + a->sign = MP_ZPOS; + } +} + + +/* high level addition (handles signs) */ +static int +mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + /* get sign of both inputs */ + sa = a->sign; + sb = b->sign; + + /* handle two cases, not four */ + if (sa == sb) { + /* both positive or both negative */ + /* add their magnitudes, copy the sign */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* one positive, the other negative */ + /* subtract the one with the greater magnitude from */ + /* the one of the lesser magnitude. The result gets */ + /* the sign of the one with the greater magnitude. */ + if (mp_cmp_mag (a, b) == MP_LT) { + c->sign = sb; + res = s_mp_sub (b, a, c); + } else { + c->sign = sa; + res = s_mp_sub (a, b, c); + } + } + return res; +} + + +/* high level subtraction (handles signs) */ +static int +mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + sa = a->sign; + sb = b->sign; + + if (sa != sb) { + /* subtract a negative from a positive, OR */ + /* subtract a positive from a negative. */ + /* In either case, ADD their magnitudes, */ + /* and use the sign of the first number. */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* subtract a positive from a positive, OR */ + /* subtract a negative from a negative. */ + /* First, take the difference between their */ + /* magnitudes, then... */ + if (mp_cmp_mag (a, b) != MP_LT) { + /* Copy the sign from the first */ + c->sign = sa; + /* The first has a larger or equal magnitude */ + res = s_mp_sub (a, b, c); + } else { + /* The result has the *opposite* sign from */ + /* the first number. */ + c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; + /* The second has a larger magnitude */ + res = s_mp_sub (b, a, c); + } + } + return res; +} + + +/* high level multiplication (handles sign) */ +static int +mp_mul (mp_int * a, mp_int * b, mp_int * c) +{ + int res, neg; + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + + /* use Toom-Cook? */ +#ifdef BN_MP_TOOM_MUL_C + if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) { + res = mp_toom_mul(a, b, c); + } else +#endif +#ifdef BN_MP_KARATSUBA_MUL_C + /* use Karatsuba? */ + if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) { + res = mp_karatsuba_mul (a, b, c); + } else +#endif + { + /* can we use the fast multiplier? + * + * The fast multiplier can be used if the output will + * have less than MP_WARRAY digits and the number of + * digits won't affect carry propagation + */ +#ifdef BN_FAST_S_MP_MUL_DIGS_C + int digs = a->used + b->used + 1; + + if ((digs < MP_WARRAY) && + MIN(a->used, b->used) <= + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + res = fast_s_mp_mul_digs (a, b, c, digs); + } else +#endif +#ifdef BN_S_MP_MUL_DIGS_C + res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */ +#else +#error mp_mul could fail + res = MP_VAL; +#endif + + } + c->sign = (c->used > 0) ? neg : MP_ZPOS; + return res; +} + + +/* d = a * b (mod c) */ +static int +mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_mul (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + + +/* c = a mod b, 0 <= c < b */ +static int +mp_mod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int t; + int res; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + if (t.sign != b->sign) { + res = mp_add (b, &t, c); + } else { + res = MP_OKAY; + mp_exch (&t, c); + } + + mp_clear (&t); + return res; +} + + +/* this is a shell function that calls either the normal or Montgomery + * exptmod functions. Originally the call to the montgomery code was + * embedded in the normal function but that wasted a lot of stack space + * for nothing (since 99% of the time the Montgomery code would be called) + */ +static int +mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +{ + int dr; + + /* modulus P must be positive */ + if (P->sign == MP_NEG) { + return MP_VAL; + } + + /* if exponent X is negative we have to recurse */ + if (X->sign == MP_NEG) { +#ifdef LTM_NO_NEG_EXP + return MP_VAL; +#else /* LTM_NO_NEG_EXP */ +#ifdef BN_MP_INVMOD_C + mp_int tmpG, tmpX; + int err; + + /* first compute 1/G mod P */ + if ((err = mp_init(&tmpG)) != MP_OKAY) { + return err; + } + if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + + /* now get |X| */ + if ((err = mp_init(&tmpX)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + /* and now compute (1/G)**|X| instead of G**X [X < 0] */ + err = mp_exptmod(&tmpG, &tmpX, P, Y); + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; +#else +#error mp_exptmod would always fail + /* no invmod */ + return MP_VAL; +#endif +#endif /* LTM_NO_NEG_EXP */ + } + +/* modified diminished radix reduction */ +#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C) + if (mp_reduce_is_2k_l(P) == MP_YES) { + return s_mp_exptmod(G, X, P, Y, 1); + } +#endif + +#ifdef BN_MP_DR_IS_MODULUS_C + /* is it a DR modulus? */ + dr = mp_dr_is_modulus(P); +#else + /* default to no */ + dr = 0; +#endif + +#ifdef BN_MP_REDUCE_IS_2K_C + /* if not, is it a unrestricted DR modulus? */ + if (dr == 0) { + dr = mp_reduce_is_2k(P) << 1; + } +#endif + + /* if the modulus is odd or dr != 0 use the montgomery method */ +#ifdef BN_MP_EXPTMOD_FAST_C + if (mp_isodd (P) == 1 || dr != 0) { + return mp_exptmod_fast (G, X, P, Y, dr); + } else { +#endif +#ifdef BN_S_MP_EXPTMOD_C + (void) dr; + /* otherwise use the generic Barrett reduction technique */ + return s_mp_exptmod (G, X, P, Y, 0); +#else +#error mp_exptmod could fail + /* no exptmod for evens */ + return MP_VAL; +#endif +#ifdef BN_MP_EXPTMOD_FAST_C + } +#endif +} + + +/* compare two ints (signed)*/ +static int +mp_cmp (mp_int * a, mp_int * b) +{ + /* compare based on sign */ + if (a->sign != b->sign) { + if (a->sign == MP_NEG) { + return MP_LT; + } else { + return MP_GT; + } + } + + /* compare digits */ + if (a->sign == MP_NEG) { + /* if negative compare opposite direction */ + return mp_cmp_mag(b, a); + } else { + return mp_cmp_mag(a, b); + } +} + + +/* compare a digit */ +static int +mp_cmp_d(mp_int * a, mp_digit b) +{ + /* compare based on sign */ + if (a->sign == MP_NEG) { + return MP_LT; + } + + /* compare based on magnitude */ + if (a->used > 1) { + return MP_GT; + } + + /* compare the only digit of a to b */ + if (a->dp[0] > b) { + return MP_GT; + } else if (a->dp[0] < b) { + return MP_LT; + } else { + return MP_EQ; + } +} + + +#ifndef LTM_NO_NEG_EXP +/* hac 14.61, pp608 */ +static int +mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + +#ifdef BN_FAST_MP_INVMOD_C + /* if the modulus is odd we can use a faster routine instead */ + if (mp_isodd (b) == 1) { + return fast_mp_invmod (a, b, c); + } +#endif + +#ifdef BN_MP_INVMOD_SLOW_C + return mp_invmod_slow(a, b, c); +#endif + +#ifndef BN_FAST_MP_INVMOD_C +#ifndef BN_MP_INVMOD_SLOW_C +#error mp_invmod would always fail +#endif +#endif + return MP_VAL; +} +#endif /* LTM_NO_NEG_EXP */ + + +/* get the size for an unsigned equivalent */ +static int +mp_unsigned_bin_size (mp_int * a) +{ + int size = mp_count_bits (a); + return (size / 8 + ((size & 7) != 0 ? 1 : 0)); +} + + +#ifndef LTM_NO_NEG_EXP +/* hac 14.61, pp608 */ +static int +mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, A, B, C, D; + int res; + + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + + /* init temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, + &A, &B, &C, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x = a, y = b */ + if ((res = mp_mod(a, b, &x)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (b, &y)) != MP_OKAY) { + goto LBL_ERR; + } + + /* 2. [modified] if x,y are both even then return an error! */ + if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { + res = MP_VAL; + goto LBL_ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto LBL_ERR; + } + mp_set (&A, 1); + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto LBL_ERR; + } + /* 4.2 if A or B is odd then */ + if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) { + /* A = (A+y)/2, B = (B-x)/2 */ + if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* A = A/2, B = B/2 */ + if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto LBL_ERR; + } + /* 5.2 if C or D is odd then */ + if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) { + /* C = (C+y)/2, D = (D-x)/2 */ + if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* C = C/2, D = D/2 */ + if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 6. if u >= v then */ + if (mp_cmp (&u, &v) != MP_LT) { + /* u = u - v, A = A - C, B = B - D */ + if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } else { + /* v - v - u, C = C - A, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) + goto top; + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto LBL_ERR; + } + + /* if its too low */ + while (mp_cmp_d(&C, 0) == MP_LT) { + if ((res = mp_add(&C, b, &C)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* too big */ + while (mp_cmp_mag(&C, b) != MP_LT) { + if ((res = mp_sub(&C, b, &C)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* C is now the inverse */ + mp_exch (&C, c); + res = MP_OKAY; +LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); + return res; +} +#endif /* LTM_NO_NEG_EXP */ + + +/* compare maginitude of two ints (unsigned) */ +static int +mp_cmp_mag (mp_int * a, mp_int * b) +{ + int n; + mp_digit *tmpa, *tmpb; + + /* compare based on # of non-zero digits */ + if (a->used > b->used) { + return MP_GT; + } + + if (a->used < b->used) { + return MP_LT; + } + + /* alias for a */ + tmpa = a->dp + (a->used - 1); + + /* alias for b */ + tmpb = b->dp + (a->used - 1); + + /* compare based on digits */ + for (n = 0; n < a->used; ++n, --tmpa, --tmpb) { + if (*tmpa > *tmpb) { + return MP_GT; + } + + if (*tmpa < *tmpb) { + return MP_LT; + } + } + return MP_EQ; +} + + +/* reads a unsigned char array, assumes the msb is stored first [big endian] */ +static int +mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c) +{ + int res; + + /* make sure there are at least two digits */ + if (a->alloc < 2) { + if ((res = mp_grow(a, 2)) != MP_OKAY) { + return res; + } + } + + /* zero the int */ + mp_zero (a); + + /* read the bytes in */ + while (c-- > 0) { + if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { + return res; + } + +#ifndef MP_8BIT + a->dp[0] |= *b++; + a->used += 1; +#else + a->dp[0] = (*b & MP_MASK); + a->dp[1] |= ((*b++ >> 7U) & 1); + a->used += 2; +#endif + } + mp_clamp (a); + return MP_OKAY; +} + + +/* store in unsigned [big endian] format */ +static int +mp_to_unsigned_bin (mp_int * a, unsigned char *b) +{ + int x, res; + mp_int t; + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + x = 0; + while (mp_iszero (&t) == 0) { +#ifndef MP_8BIT + b[x++] = (unsigned char) (t.dp[0] & 255); +#else + b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7)); +#endif + if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + bn_reverse (b, x); + mp_clear (&t); + return MP_OKAY; +} + + +/* shift right by a certain bit count (store quotient in c, optional remainder in d) */ +static int +mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) +{ + mp_digit D, r, rr; + int x, res; + mp_int t; + + + /* if the shift count is <= 0 then we do no work */ + if (b <= 0) { + res = mp_copy (a, c); + if (d != NULL) { + mp_zero (d); + } + return res; + } + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + /* get the remainder */ + if (d != NULL) { + if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + mp_rshd (c, b / DIGIT_BIT); + } + + /* shift any bit count < DIGIT_BIT */ + D = (mp_digit) (b % DIGIT_BIT); + if (D != 0) { + register mp_digit *tmpc, mask, shift; + + /* mask */ + mask = (((mp_digit)1) << D) - 1; + + /* shift for lsb */ + shift = DIGIT_BIT - D; + + /* alias */ + tmpc = c->dp + (c->used - 1); + + /* carry */ + r = 0; + for (x = c->used - 1; x >= 0; x--) { + /* get the lower bits of this word in a temp */ + rr = *tmpc & mask; + + /* shift the current word and mix in the carry bits from the previous word */ + *tmpc = (*tmpc >> D) | (r << shift); + --tmpc; + + /* set the carry to the carry bits of the current word found above */ + r = rr; + } + } + mp_clamp (c); + if (d != NULL) { + mp_exch (&t, d); + } + mp_clear (&t); + return MP_OKAY; +} + + +static int +mp_init_copy (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_init (a)) != MP_OKAY) { + return res; + } + return mp_copy (b, a); +} + + +/* set to zero */ +static void +mp_zero (mp_int * a) +{ + int n; + mp_digit *tmp; + + a->sign = MP_ZPOS; + a->used = 0; + + tmp = a->dp; + for (n = 0; n < a->alloc; n++) { + *tmp++ = 0; + } +} + + +/* copy, b = a */ +static int +mp_copy (mp_int * a, mp_int * b) +{ + int res, n; + + /* if dst == src do nothing */ + if (a == b) { + return MP_OKAY; + } + + /* grow dest */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + /* zero b and copy the parameters over */ + { + register mp_digit *tmpa, *tmpb; + + /* pointer aliases */ + + /* source */ + tmpa = a->dp; + + /* destination */ + tmpb = b->dp; + + /* copy all the digits */ + for (n = 0; n < a->used; n++) { + *tmpb++ = *tmpa++; + } + + /* clear high digits */ + for (; n < b->used; n++) { + *tmpb++ = 0; + } + } + + /* copy used count and sign */ + b->used = a->used; + b->sign = a->sign; + return MP_OKAY; +} + + +/* shift right a certain amount of digits */ +static void +mp_rshd (mp_int * a, int b) +{ + int x; + + /* if b <= 0 then ignore it */ + if (b <= 0) { + return; + } + + /* if b > used then simply zero it and return */ + if (a->used <= b) { + mp_zero (a); + return; + } + + { + register mp_digit *bottom, *top; + + /* shift the digits down */ + + /* bottom */ + bottom = a->dp; + + /* top [offset into digits] */ + top = a->dp + b; + + /* this is implemented as a sliding window where + * the window is b-digits long and digits from + * the top of the window are copied to the bottom + * + * e.g. + + b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> + /\ | ----> + \-------------------/ ----> + */ + for (x = 0; x < (a->used - b); x++) { + *bottom++ = *top++; + } + + /* zero the top digits */ + for (; x < a->used; x++) { + *bottom++ = 0; + } + } + + /* remove excess digits */ + a->used -= b; +} + + +/* swap the elements of two integers, for cases where you can't simply swap the + * mp_int pointers around + */ +static void +mp_exch (mp_int * a, mp_int * b) +{ + mp_int t; + + t = *a; + *a = *b; + *b = t; +} + + +/* trim unused digits + * + * This is used to ensure that leading zero digits are + * trimed and the leading "used" digit will be non-zero + * Typically very fast. Also fixes the sign if there + * are no more leading digits + */ +static void +mp_clamp (mp_int * a) +{ + /* decrease used while the most significant digit is + * zero. + */ + while (a->used > 0 && a->dp[a->used - 1] == 0) { + --(a->used); + } + + /* reset the sign flag if used == 0 */ + if (a->used == 0) { + a->sign = MP_ZPOS; + } +} + + +/* grow as required */ +static int +mp_grow (mp_int * a, int size) +{ + int i; + mp_digit *tmp; + + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + /* ensure there are always at least MP_PREC digits extra on top */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* reallocate the array a->dp + * + * We store the return in a temporary variable + * in case the operation failed we don't want + * to overwrite the dp member of a. + */ + tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size); + if (tmp == NULL) { + /* reallocation failed but "a" is still valid [can be freed] */ + return MP_MEM; + } + + /* reallocation succeeded so set a->dp */ + a->dp = tmp; + + /* zero excess digits */ + i = a->alloc; + a->alloc = size; + for (; i < a->alloc; i++) { + a->dp[i] = 0; + } + } + return MP_OKAY; +} + + +#ifdef BN_MP_ABS_C +/* b = |a| + * + * Simple function copies the input and fixes the sign to positive + */ +static int +mp_abs (mp_int * a, mp_int * b) +{ + int res; + + /* copy a to b */ + if (a != b) { + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + } + + /* force the sign of b to positive */ + b->sign = MP_ZPOS; + + return MP_OKAY; +} +#endif + + +/* set to a digit */ +static void +mp_set (mp_int * a, mp_digit b) +{ + mp_zero (a); + a->dp[0] = b & MP_MASK; + a->used = (a->dp[0] != 0) ? 1 : 0; +} + + +#ifndef LTM_NO_NEG_EXP +/* b = a/2 */ +static int +mp_div_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* copy */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* source alias */ + tmpa = a->dp + b->used - 1; + + /* dest alias */ + tmpb = b->dp + b->used - 1; + + /* carry */ + r = 0; + for (x = b->used - 1; x >= 0; x--) { + /* get the carry for the next iteration */ + rr = *tmpa & 1; + + /* shift the current digit, add in carry and store */ + *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); + + /* forward carry to next iteration */ + r = rr; + } + + /* zero excess digits */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + mp_clamp (b); + return MP_OKAY; +} +#endif /* LTM_NO_NEG_EXP */ + + +/* shift left by a certain bit count */ +static int +mp_mul_2d (mp_int * a, int b, mp_int * c) +{ + mp_digit d; + int res; + + /* copy */ + if (a != c) { + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + } + + if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) { + if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { + return res; + } + } + + /* shift any bit count < DIGIT_BIT */ + d = (mp_digit) (b % DIGIT_BIT); + if (d != 0) { + register mp_digit *tmpc, shift, mask, r, rr; + register int x; + + /* bitmask for carries */ + mask = (((mp_digit)1) << d) - 1; + + /* shift for msbs */ + shift = DIGIT_BIT - d; + + /* alias */ + tmpc = c->dp; + + /* carry */ + r = 0; + for (x = 0; x < c->used; x++) { + /* get the higher bits of the current word */ + rr = (*tmpc >> shift) & mask; + + /* shift the current word and OR in the carry */ + *tmpc = ((*tmpc << d) | r) & MP_MASK; + ++tmpc; + + /* set the carry to the carry bits of the current word */ + r = rr; + } + + /* set final carry */ + if (r != 0) { + c->dp[(c->used)++] = r; + } + } + mp_clamp (c); + return MP_OKAY; +} + + +#ifdef BN_MP_INIT_MULTI_C +static int +mp_init_multi(mp_int *mp, ...) +{ + mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ + int n = 0; /* Number of ok inits */ + mp_int* cur_arg = mp; + va_list args; + + va_start(args, mp); /* init args to next argument from caller */ + while (cur_arg != NULL) { + if (mp_init(cur_arg) != MP_OKAY) { + /* Oops - error! Back-track and mp_clear what we already + succeeded in init-ing, then return error. + */ + va_list clean_args; + + /* end the current list */ + va_end(args); + + /* now start cleaning up */ + cur_arg = mp; + va_start(clean_args, mp); + while (n--) { + mp_clear(cur_arg); + cur_arg = va_arg(clean_args, mp_int*); + } + va_end(clean_args); + res = MP_MEM; + break; + } + n++; + cur_arg = va_arg(args, mp_int*); + } + va_end(args); + return res; /* Assumed ok, if error flagged above. */ +} +#endif + + +#ifdef BN_MP_CLEAR_MULTI_C +static void +mp_clear_multi(mp_int *mp, ...) +{ + mp_int* next_mp = mp; + va_list args; + va_start(args, mp); + while (next_mp != NULL) { + mp_clear(next_mp); + next_mp = va_arg(args, mp_int*); + } + va_end(args); +} +#endif + + +/* shift left a certain amount of digits */ +static int +mp_lshd (mp_int * a, int b) +{ + int x, res; + + /* if its less than zero return */ + if (b <= 0) { + return MP_OKAY; + } + + /* grow to fit the new digits */ + if (a->alloc < a->used + b) { + if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { + return res; + } + } + + { + register mp_digit *top, *bottom; + + /* increment the used by the shift amount then copy upwards */ + a->used += b; + + /* top */ + top = a->dp + a->used - 1; + + /* base */ + bottom = a->dp + a->used - 1 - b; + + /* much like mp_rshd this is implemented using a sliding window + * except the window goes the otherway around. Copying from + * the bottom to the top. see bn_mp_rshd.c for more info. + */ + for (x = a->used - 1; x >= b; x--) { + *top-- = *bottom--; + } + + /* zero the lower digits */ + top = a->dp; + for (x = 0; x < b; x++) { + *top++ = 0; + } + } + return MP_OKAY; +} + + +/* returns the number of bits in an int */ +static int +mp_count_bits (mp_int * a) +{ + int r; + mp_digit q; + + /* shortcut */ + if (a->used == 0) { + return 0; + } + + /* get number of digits and add that */ + r = (a->used - 1) * DIGIT_BIT; + + /* take the last digit and count the bits in it */ + q = a->dp[a->used - 1]; + while (q > ((mp_digit) 0)) { + ++r; + q >>= ((mp_digit) 1); + } + return r; +} + + +/* calc a value mod 2**b */ +static int +mp_mod_2d (mp_int * a, int b, mp_int * c) +{ + int x, res; + + /* if b is <= 0 then zero the int */ + if (b <= 0) { + mp_zero (c); + return MP_OKAY; + } + + /* if the modulus is larger than the value than return */ + if (b >= (int) (a->used * DIGIT_BIT)) { + res = mp_copy (a, c); + return res; + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + + /* zero digits above the last digit of the modulus */ + for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { + c->dp[x] = 0; + } + /* clear the digit that is not completely outside/inside the modulus */ + c->dp[b / DIGIT_BIT] &= + (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); + mp_clamp (c); + return MP_OKAY; +} + + +#ifdef BN_MP_DIV_SMALL + +/* slower bit-bang division... also smaller */ +static int +mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + mp_int ta, tb, tq, q; + int res, n, n2; + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + /* init our temps */ + if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) { + return res; + } + + + mp_set(&tq, 1); + n = mp_count_bits(a) - mp_count_bits(b); + if (((res = mp_abs(a, &ta)) != MP_OKAY) || + ((res = mp_abs(b, &tb)) != MP_OKAY) || + ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) || + ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) { + goto LBL_ERR; + } + + while (n-- >= 0) { + if (mp_cmp(&tb, &ta) != MP_GT) { + if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) || + ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) { + goto LBL_ERR; + } + } + if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) || + ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) { + goto LBL_ERR; + } + } + + /* now q == quotient and ta == remainder */ + n = a->sign; + n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG); + if (c != NULL) { + mp_exch(c, &q); + c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2; + } + if (d != NULL) { + mp_exch(d, &ta); + d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n; + } +LBL_ERR: + mp_clear_multi(&ta, &tb, &tq, &q, NULL); + return res; +} + +#else + +/* integer signed division. + * c*b + d == a [e.g. a/b, c=quotient, d=remainder] + * HAC pp.598 Algorithm 14.20 + * + * Note that the description in HAC is horribly + * incomplete. For example, it doesn't consider + * the case where digits are removed from 'x' in + * the inner loop. It also doesn't consider the + * case that y has fewer than three digits, etc.. + * + * The overall algorithm is as described as + * 14.20 from HAC but fixed to treat these cases. +*/ +static int +mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + mp_int q, x, y, t1, t2; + int res, n, t, i, norm, neg; + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { + return res; + } + q.used = a->used + 2; + + if ((res = mp_init (&t1)) != MP_OKAY) { + goto LBL_Q; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + goto LBL_T1; + } + + if ((res = mp_init_copy (&x, a)) != MP_OKAY) { + goto LBL_T2; + } + + if ((res = mp_init_copy (&y, b)) != MP_OKAY) { + goto LBL_X; + } + + /* fix the sign */ + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + x.sign = y.sign = MP_ZPOS; + + /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ + norm = mp_count_bits(&y) % DIGIT_BIT; + if (norm < (int)(DIGIT_BIT-1)) { + norm = (DIGIT_BIT-1) - norm; + if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) { + goto LBL_Y; + } + } else { + norm = 0; + } + + /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ + n = x.used - 1; + t = y.used - 1; + + /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ + if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */ + goto LBL_Y; + } + + while (mp_cmp (&x, &y) != MP_LT) { + ++(q.dp[n - t]); + if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) { + goto LBL_Y; + } + } + + /* reset y by shifting it back down */ + mp_rshd (&y, n - t); + + /* step 3. for i from n down to (t + 1) */ + for (i = n; i >= (t + 1); i--) { + if (i > x.used) { + continue; + } + + /* step 3.1 if xi == yt then set q{i-t-1} to b-1, + * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ + if (x.dp[i] == y.dp[t]) { + q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1); + } else { + mp_word tmp; + tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); + tmp |= ((mp_word) x.dp[i - 1]); + tmp /= ((mp_word) y.dp[t]); + if (tmp > (mp_word) MP_MASK) + tmp = MP_MASK; + q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); + } + + /* while (q{i-t-1} * (yt * b + y{t-1})) > + xi * b**2 + xi-1 * b + xi-2 + + do q{i-t-1} -= 1; + */ + q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK; + do { + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; + + /* find left hand */ + mp_zero (&t1); + t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; + t1.dp[1] = y.dp[t]; + t1.used = 2; + if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto LBL_Y; + } + + /* find right hand */ + t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; + t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; + t2.dp[2] = x.dp[i]; + t2.used = 3; + } while (mp_cmp_mag(&t1, &t2) == MP_GT); + + /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ + if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto LBL_Y; + } + + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto LBL_Y; + } + + if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) { + goto LBL_Y; + } + + /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ + if (x.sign == MP_NEG) { + if ((res = mp_copy (&y, &t1)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) { + goto LBL_Y; + } + + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; + } + } + + /* now q is the quotient and x is the remainder + * [which we have to normalize] + */ + + /* get sign before writing to c */ + x.sign = x.used == 0 ? MP_ZPOS : a->sign; + + if (c != NULL) { + mp_clamp (&q); + mp_exch (&q, c); + c->sign = neg; + } + + if (d != NULL) { + mp_div_2d (&x, norm, &x, NULL); + mp_exch (&x, d); + } + + res = MP_OKAY; + +LBL_Y:mp_clear (&y); +LBL_X:mp_clear (&x); +LBL_T2:mp_clear (&t2); +LBL_T1:mp_clear (&t1); +LBL_Q:mp_clear (&q); + return res; +} + +#endif + + +#ifdef MP_LOW_MEM + #define TAB_SIZE 32 +#else + #define TAB_SIZE 256 +#endif + +static int +s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[TAB_SIZE], res, mu; + mp_digit buf; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + int (*redux)(mp_int*,mp_int*,mp_int*); + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* create mu, used for Barrett reduction */ + if ((err = mp_init (&mu)) != MP_OKAY) { + goto LBL_M; + } + + if (redmode == 0) { + if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) { + goto LBL_MU; + } + redux = mp_reduce; + } else { + if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + redux = mp_reduce_2k_l; + } + + /* create M table + * + * The M table contains powers of the base, + * e.g. M[x] = G**x mod P + * + * The first half of the table is not + * computed though accept for M[0] and M[1] + */ + if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { + goto LBL_MU; + } + + /* compute the value at M[1<<(winsize-1)] by squaring + * M[1] (winsize-1) times + */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_MU; + } + + for (x = 0; x < (winsize - 1); x++) { + /* square it */ + if ((err = mp_sqr (&M[1 << (winsize - 1)], + &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_MU; + } + + /* reduce modulo P */ + if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + } + + /* create upper table, that is M[x] = M[x-1] * M[1] (mod P) + * for x = (2**(winsize - 1) + 1) to (2**winsize - 1) + */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto LBL_MU; + } + if ((err = redux (&M[x], P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto LBL_MU; + } + mp_set (&res, 1); + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits */ + if (digidx == -1) { + break; + } + /* read next digit and reset the bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int) DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + } + } + } + + mp_exch (&res, Y); + err = MP_OKAY; +LBL_RES:mp_clear (&res); +LBL_MU:mp_clear (&mu); +LBL_M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} + + +/* computes b = a*a */ +static int +mp_sqr (mp_int * a, mp_int * b) +{ + int res; + +#ifdef BN_MP_TOOM_SQR_C + /* use Toom-Cook? */ + if (a->used >= TOOM_SQR_CUTOFF) { + res = mp_toom_sqr(a, b); + /* Karatsuba? */ + } else +#endif +#ifdef BN_MP_KARATSUBA_SQR_C +if (a->used >= KARATSUBA_SQR_CUTOFF) { + res = mp_karatsuba_sqr (a, b); + } else +#endif + { +#ifdef BN_FAST_S_MP_SQR_C + /* can we use the fast comba multiplier? */ + if ((a->used * 2 + 1) < MP_WARRAY && + a->used < + (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) { + res = fast_s_mp_sqr (a, b); + } else +#endif +#ifdef BN_S_MP_SQR_C + res = s_mp_sqr (a, b); +#else +#error mp_sqr could fail + res = MP_VAL; +#endif + } + b->sign = MP_ZPOS; + return res; +} + + +/* reduces a modulo n where n is of the form 2**p - d + This differs from reduce_2k since "d" can be larger + than a single digit. +*/ +static int +mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d) +{ + mp_int q; + int p, res; + + if ((res = mp_init(&q)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto ERR; + } + + /* q = q * d */ + if ((res = mp_mul(&q, d, &q)) != MP_OKAY) { + goto ERR; + } + + /* a = a + q */ + if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + s_mp_sub(a, n, a); + goto top; + } + +ERR: + mp_clear(&q); + return res; +} + + +/* determines the setup value */ +static int +mp_reduce_2k_setup_l(mp_int *a, mp_int *d) +{ + int res; + mp_int tmp; + + if ((res = mp_init(&tmp)) != MP_OKAY) { + return res; + } + + if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) { + goto ERR; + } + + if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear(&tmp); + return res; +} + + +/* computes a = 2**b + * + * Simple algorithm which zeroes the int, grows it then just sets one bit + * as required. + */ +static int +mp_2expt (mp_int * a, int b) +{ + int res; + + /* zero a as per default */ + mp_zero (a); + + /* grow a to accommodate the single bit */ + if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + + /* set the used count of where the bit will go */ + a->used = b / DIGIT_BIT + 1; + + /* put the single bit in its place */ + a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT); + + return MP_OKAY; +} + + +/* pre-calculate the value required for Barrett reduction + * For a given modulus "b" it calulates the value required in "a" + */ +static int +mp_reduce_setup (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { + return res; + } + return mp_div (a, b, a, NULL); +} + + +/* reduces x mod m, assumes 0 < x < m**2, mu is + * precomputed via mp_reduce_setup. + * From HAC pp.604 Algorithm 14.42 + */ +static int +mp_reduce (mp_int * x, mp_int * m, mp_int * mu) +{ + mp_int q; + int res, um = m->used; + + /* q = x */ + if ((res = mp_init_copy (&q, x)) != MP_OKAY) { + return res; + } + + /* q1 = x / b**(k-1) */ + mp_rshd (&q, um - 1); + + /* according to HAC this optimization is ok */ + if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) { + if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { + goto CLEANUP; + } + } else { +#ifdef BN_S_MP_MUL_HIGH_DIGS_C + if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } +#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C) + if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } +#else + { +#error mp_reduce would always fail + res = MP_VAL; + goto CLEANUP; + } +#endif + } + + /* q3 = q2 / b**(k+1) */ + mp_rshd (&q, um + 1); + + /* x = x mod b**(k+1), quick (no division) */ + if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { + goto CLEANUP; + } + + /* q = q * m mod b**(k+1), quick (no division) */ + if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + + /* x = x - q */ + if ((res = mp_sub (x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + + /* If x < 0, add b**(k+1) to it */ + if (mp_cmp_d (x, 0) == MP_LT) { + mp_set (&q, 1); + if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + if ((res = mp_add (x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + } + + /* Back off if it's too big */ + while (mp_cmp (x, m) != MP_LT) { + if ((res = s_mp_sub (x, m, x)) != MP_OKAY) { + goto CLEANUP; + } + } + +CLEANUP: + mp_clear (&q); + + return res; +} + + +/* multiplies |a| * |b| and only computes up to digs digits of result + * HAC pp. 595, Algorithm 14.12 Modified so you can control how + * many digits of output are created. + */ +static int +s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (((digs) < MP_WARRAY) && + MIN (a->used, b->used) < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, digs)) != MP_OKAY) { + return res; + } + t.used = digs; + + /* compute the digits of the product directly */ + pa = a->used; + for (ix = 0; ix < pa; ix++) { + /* set the carry to zero */ + u = 0; + + /* limit ourselves to making digs digits of output */ + pb = MIN (b->used, digs - ix); + + /* setup some aliases */ + /* copy of the digit from a used within the nested loop */ + tmpx = a->dp[ix]; + + /* an alias for the destination shifted ix places */ + tmpt = t.dp + ix; + + /* an alias for the digits of b */ + tmpy = b->dp; + + /* compute the columns of the output and propagate the carry */ + for (iy = 0; iy < pb; iy++) { + /* compute the column as a mp_word */ + r = ((mp_word)*tmpt) + + ((mp_word)tmpx) * ((mp_word)*tmpy++) + + ((mp_word) u); + + /* the new column is the lower part of the result */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry word from the result */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + /* set carry if it is placed below digs */ + if (ix + iy < digs) { + *tmpt = u; + } + } + + mp_clamp (&t); + mp_exch (&t, c); + + mp_clear (&t); + return MP_OKAY; +} + + +/* Fast (comba) multiplier + * + * This is the fast column-array [comba] multiplier. It is + * designed to compute the columns of the product first + * then handle the carries afterwards. This has the effect + * of making the nested loops that compute the columns very + * simple and schedulable on super-scalar processors. + * + * This has been modified to produce a variable number of + * digits of output so if say only a half-product is required + * you don't have to compute the upper half (a feature + * required for fast Barrett reduction). + * + * Based on Algorithm 14.12 on pp.595 of HAC. + * + */ +static int +fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY]; + register mp_word _W; + + /* grow the destination as required */ + if (c->alloc < digs) { + if ((res = mp_grow (c, digs)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + pa = MIN(digs, a->used + b->used); + + /* clear the carry */ + _W = 0; + for (ix = 0; ix < pa; ix++) { + int tx, ty; + int iy; + mp_digit *tmpx, *tmpy; + + /* get offsets into the two bignums */ + ty = MIN(b->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = b->dp + ty; + + /* this is the number of times the loop will iterrate, essentially + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(a->used-tx, ty+1); + + /* execute loop */ + for (iz = 0; iz < iy; ++iz) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + + } + + /* store term */ + W[ix] = ((mp_digit)_W) & MP_MASK; + + /* make next carry */ + _W = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + register mp_digit *tmpc; + tmpc = c->dp; + for (ix = 0; ix < pa+1; ix++) { + /* now extract the previous digit [below the carry] */ + *tmpc++ = W[ix]; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + mp_clamp (c); + return MP_OKAY; +} + + +/* init an mp_init for a given size */ +static int +mp_init_size (mp_int * a, int size) +{ + int x; + + /* pad size so there are always extra digits */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* alloc mem */ + a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the members */ + a->used = 0; + a->alloc = size; + a->sign = MP_ZPOS; + + /* zero the digits */ + for (x = 0; x < size; x++) { + a->dp[x] = 0; + } + + return MP_OKAY; +} + + +/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ +static int +s_mp_sqr (mp_int * a, mp_int * b) +{ + mp_int t; + int res, ix, iy, pa; + mp_word r; + mp_digit u, tmpx, *tmpt; + + pa = a->used; + if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) { + return res; + } + + /* default used is maximum possible size */ + t.used = 2*pa + 1; + + for (ix = 0; ix < pa; ix++) { + /* first calculate the digit at 2*ix */ + /* calculate double precision result */ + r = ((mp_word) t.dp[2*ix]) + + ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]); + + /* store lower part in result */ + t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + + /* left hand side of A[ix] * A[iy] */ + tmpx = a->dp[ix]; + + /* alias for where to store the results */ + tmpt = t.dp + (2*ix + 1); + + for (iy = ix + 1; iy < pa; iy++) { + /* first calculate the product */ + r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]); + + /* now calculate the double precision result, note we use + * addition instead of *2 since it's easier to optimize + */ + r = ((mp_word) *tmpt) + r + r + ((mp_word) u); + + /* store lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + /* propagate upwards */ + while (u != ((mp_digit) 0)) { + r = ((mp_word) *tmpt) + ((mp_word) u); + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + } + + mp_clamp (&t); + mp_exch (&t, b); + mp_clear (&t); + return MP_OKAY; +} + + +/* multiplies |a| * |b| and does not compute the lower digs digits + * [meant to get the higher part of the product] + */ +static int +s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ +#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C + if (((a->used + b->used + 1) < MP_WARRAY) + && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_high_digs (a, b, c, digs); + } +#endif + + if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { + return res; + } + t.used = a->used + b->used + 1; + + pa = a->used; + pb = b->used; + for (ix = 0; ix < pa; ix++) { + /* clear the carry */ + u = 0; + + /* left hand side of A[ix] * B[iy] */ + tmpx = a->dp[ix]; + + /* alias to the address of where the digits will be stored */ + tmpt = &(t.dp[digs]); + + /* alias for where to read the right hand side from */ + tmpy = b->dp + (digs - ix); + + for (iy = digs - ix; iy < pb; iy++) { + /* calculate the double precision result */ + r = ((mp_word)*tmpt) + + ((mp_word)tmpx) * ((mp_word)*tmpy++) + + ((mp_word) u); + + /* get the lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* carry the carry */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + *tmpt = u; + } + mp_clamp (&t); + mp_exch (&t, c); + mp_clear (&t); + return MP_OKAY; +} + + +#ifdef BN_MP_MONTGOMERY_SETUP_C +/* setups the montgomery reduction stuff */ +static int +mp_montgomery_setup (mp_int * n, mp_digit * rho) +{ + mp_digit x, b; + +/* fast inversion mod 2**k + * + * Based on the fact that + * + * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n) + * => 2*X*A - X*X*A*A = 1 + * => 2*(1) - (1) = 1 + */ + b = n->dp[0]; + + if ((b & 1) == 0) { + return MP_VAL; + } + + x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */ + x *= 2 - b * x; /* here x*a==1 mod 2**8 */ +#if !defined(MP_8BIT) + x *= 2 - b * x; /* here x*a==1 mod 2**16 */ +#endif +#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) + x *= 2 - b * x; /* here x*a==1 mod 2**32 */ +#endif +#ifdef MP_64BIT + x *= 2 - b * x; /* here x*a==1 mod 2**64 */ +#endif + + /* rho = -1/m mod b */ + *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK; + + return MP_OKAY; +} +#endif + + +#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C +/* computes xR**-1 == x (mod N) via Montgomery Reduction + * + * This is an optimized implementation of montgomery_reduce + * which uses the comba method to quickly calculate the columns of the + * reduction. + * + * Based on Algorithm 14.32 on pp.601 of HAC. +*/ +int +fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +{ + int ix, res, olduse; + mp_word W[MP_WARRAY]; + + /* get old used count */ + olduse = x->used; + + /* grow a as required */ + if (x->alloc < n->used + 1) { + if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) { + return res; + } + } + + /* first we have to get the digits of the input into + * an array of double precision words W[...] + */ + { + register mp_word *_W; + register mp_digit *tmpx; + + /* alias for the W[] array */ + _W = W; + + /* alias for the digits of x*/ + tmpx = x->dp; + + /* copy the digits of a into W[0..a->used-1] */ + for (ix = 0; ix < x->used; ix++) { + *_W++ = *tmpx++; + } + + /* zero the high words of W[a->used..m->used*2] */ + for (; ix < n->used * 2 + 1; ix++) { + *_W++ = 0; + } + } + + /* now we proceed to zero successive digits + * from the least significant upwards + */ + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * m' mod b + * + * We avoid a double precision multiplication (which isn't required) + * by casting the value down to a mp_digit. Note this requires + * that W[ix-1] have the carry cleared (see after the inner loop) + */ + register mp_digit mu; + mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK); + + /* a = a + mu * m * b**i + * + * This is computed in place and on the fly. The multiplication + * by b**i is handled by offseting which columns the results + * are added to. + * + * Note the comba method normally doesn't handle carries in the + * inner loop In this case we fix the carry from the previous + * column since the Montgomery reduction requires digits of the + * result (so far) [see above] to work. This is + * handled by fixing up one carry after the inner loop. The + * carry fixups are done in order so after these loops the + * first m->used words of W[] have the carries fixed + */ + { + register int iy; + register mp_digit *tmpn; + register mp_word *_W; + + /* alias for the digits of the modulus */ + tmpn = n->dp; + + /* Alias for the columns set by an offset of ix */ + _W = W + ix; + + /* inner loop */ + for (iy = 0; iy < n->used; iy++) { + *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++); + } + } + + /* now fix carry for next digit, W[ix+1] */ + W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); + } + + /* now we have to propagate the carries and + * shift the words downward [all those least + * significant digits we zeroed]. + */ + { + register mp_digit *tmpx; + register mp_word *_W, *_W1; + + /* nox fix rest of carries */ + + /* alias for current word */ + _W1 = W + ix; + + /* alias for next word, where the carry goes */ + _W = W + ++ix; + + for (; ix <= n->used * 2 + 1; ix++) { + *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT); + } + + /* copy out, A = A/b**n + * + * The result is A/b**n but instead of converting from an + * array of mp_word to mp_digit than calling mp_rshd + * we just copy them in the right order + */ + + /* alias for destination word */ + tmpx = x->dp; + + /* alias for shifted double precision result */ + _W = W + n->used; + + for (ix = 0; ix < n->used + 1; ix++) { + *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK)); + } + + /* zero oldused digits, if the input a was larger than + * m->used+1 we'll have to clear the digits + */ + for (; ix < olduse; ix++) { + *tmpx++ = 0; + } + } + + /* set the max used and clamp */ + x->used = n->used + 1; + mp_clamp (x); + + /* if A >= m then A = A - m */ + if (mp_cmp_mag (x, n) != MP_LT) { + return s_mp_sub (x, n, x); + } + return MP_OKAY; +} +#endif + + +#ifdef BN_MP_MUL_2_C +/* b = a*2 */ +static int +mp_mul_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* grow to accommodate result */ + if (b->alloc < a->used + 1) { + if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + + { + register mp_digit r, rr, *tmpa, *tmpb; + + /* alias for source */ + tmpa = a->dp; + + /* alias for dest */ + tmpb = b->dp; + + /* carry */ + r = 0; + for (x = 0; x < a->used; x++) { + + /* get what will be the *next* carry bit from the + * MSB of the current digit + */ + rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1)); + + /* now shift up this digit, add in the carry [from the previous] */ + *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; + + /* copy the carry that would be from the source + * digit into the next iteration + */ + r = rr; + } + + /* new leading digit? */ + if (r != 0) { + /* add a MSB which is always 1 at this point */ + *tmpb = 1; + ++(b->used); + } + + /* now zero any excess digits on the destination + * that we didn't write to + */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + return MP_OKAY; +} +#endif + + +#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C +/* + * shifts with subtractions when the result is greater than b. + * + * The method is slightly modified to shift B unconditionally up to just under + * the leading bit of b. This saves a lot of multiple precision shifting. + */ +static int +mp_montgomery_calc_normalization (mp_int * a, mp_int * b) +{ + int x, bits, res; + + /* how many bits of last digit does b use */ + bits = mp_count_bits (b) % DIGIT_BIT; + + if (b->used > 1) { + if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { + return res; + } + } else { + mp_set(a, 1); + bits = 1; + } + + + /* now compute C = A * B mod b */ + for (x = bits - 1; x < (int)DIGIT_BIT; x++) { + if ((res = mp_mul_2 (a, a)) != MP_OKAY) { + return res; + } + if (mp_cmp_mag (a, b) != MP_LT) { + if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { + return res; + } + } + } + + return MP_OKAY; +} +#endif + + +#ifdef BN_MP_EXPTMOD_FAST_C +/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85 + * + * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. + * The value of k changes based on the size of the exponent. + * + * Uses Montgomery or Diminished Radix reduction [whichever appropriate] + */ + +static int +mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[TAB_SIZE], res; + mp_digit buf, mp; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* use a pointer to the reduction algorithm. This allows us to use + * one of many reduction algorithms without modding the guts of + * the code with if statements everywhere. + */ + int (*redux)(mp_int*,mp_int*,mp_digit); + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* determine and setup reduction code */ + if (redmode == 0) { +#ifdef BN_MP_MONTGOMERY_SETUP_C + /* now setup montgomery */ + if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { + goto LBL_M; + } +#else + err = MP_VAL; + goto LBL_M; +#endif + + /* automatically pick the comba one if available (saves quite a few calls/ifs) */ +#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C + if (((P->used * 2 + 1) < MP_WARRAY) && + P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + redux = fast_mp_montgomery_reduce; + } else +#endif + { +#ifdef BN_MP_MONTGOMERY_REDUCE_C + /* use slower baseline Montgomery method */ + redux = mp_montgomery_reduce; +#else + err = MP_VAL; + goto LBL_M; +#endif + } + } else if (redmode == 1) { +#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C) + /* setup DR reduction for moduli of the form B**k - b */ + mp_dr_setup(P, &mp); + redux = mp_dr_reduce; +#else + err = MP_VAL; + goto LBL_M; +#endif + } else { +#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C) + /* setup DR reduction for moduli of the form 2**k - b */ + if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) { + goto LBL_M; + } + redux = mp_reduce_2k; +#else + err = MP_VAL; + goto LBL_M; +#endif + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto LBL_M; + } + + /* create M table + * + + * + * The first half of the table is not computed though accept for M[0] and M[1] + */ + + if (redmode == 0) { +#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C + /* now we need R mod m */ + if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { + goto LBL_RES; + } +#else + err = MP_VAL; + goto LBL_RES; +#endif + + /* now set M[1] to G * R mod m */ + if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { + goto LBL_RES; + } + } else { + mp_set(&res, 1); + if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { + goto LBL_RES; + } + } + + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_RES; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* create upper table */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&M[x], P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits so break */ + if (digidx == -1) { + break; + } + /* read next digit and reset bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int)DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + + /* get next bit of the window */ + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + } + } + + if (redmode == 0) { + /* fixup result if Montgomery reduction is used + * recall that any value in a Montgomery system is + * actually multiplied by R mod n. So we have + * to reduce one more time to cancel out the factor + * of R. + */ + if ((err = redux(&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* swap res with Y */ + mp_exch (&res, Y); + err = MP_OKAY; +LBL_RES:mp_clear (&res); +LBL_M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} +#endif + + +#ifdef BN_FAST_S_MP_SQR_C +/* the jist of squaring... + * you do like mult except the offset of the tmpx [one that + * starts closer to zero] can't equal the offset of tmpy. + * So basically you set up iy like before then you min it with + * (ty-tx) so that it never happens. You double all those + * you add in the inner loop + +After that loop you do the squares and add them in. +*/ + +static int +fast_s_mp_sqr (mp_int * a, mp_int * b) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY], *tmpx; + mp_word W1; + + /* grow the destination as required */ + pa = a->used + a->used; + if (b->alloc < pa) { + if ((res = mp_grow (b, pa)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + W1 = 0; + for (ix = 0; ix < pa; ix++) { + int tx, ty, iy; + mp_word _W; + mp_digit *tmpy; + + /* clear counter */ + _W = 0; + + /* get offsets into the two bignums */ + ty = MIN(a->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = a->dp + ty; + + /* this is the number of times the loop will iterrate, essentially + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(a->used-tx, ty+1); + + /* now for squaring tx can never equal ty + * we halve the distance since they approach at a rate of 2x + * and we have to round because odd cases need to be executed + */ + iy = MIN(iy, (ty-tx+1)>>1); + + /* execute loop */ + for (iz = 0; iz < iy; iz++) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + } + + /* double the inner product and add carry */ + _W = _W + _W + W1; + + /* even columns have the square term in them */ + if ((ix&1) == 0) { + _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]); + } + + /* store it */ + W[ix] = (mp_digit)(_W & MP_MASK); + + /* make next carry */ + W1 = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = b->used; + b->used = a->used+a->used; + + { + mp_digit *tmpb; + tmpb = b->dp; + for (ix = 0; ix < pa; ix++) { + *tmpb++ = W[ix] & MP_MASK; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpb++ = 0; + } + } + mp_clamp (b); + return MP_OKAY; +} +#endif + + +#ifdef BN_MP_MUL_D_C +/* multiply by a digit */ +static int +mp_mul_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_digit u, *tmpa, *tmpc; + mp_word r; + int ix, res, olduse; + + /* make sure c is big enough to hold a*b */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* get the original destinations used count */ + olduse = c->used; + + /* set the sign */ + c->sign = a->sign; + + /* alias for a->dp [source] */ + tmpa = a->dp; + + /* alias for c->dp [dest] */ + tmpc = c->dp; + + /* zero carry */ + u = 0; + + /* compute columns */ + for (ix = 0; ix < a->used; ix++) { + /* compute product and carry sum for this term */ + r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b); + + /* mask off higher bits to get a single digit */ + *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* send carry into next iteration */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + + /* store final carry [if any] and increment ix offset */ + *tmpc++ = u; + ++ix; + + /* now zero digits above the top */ + while (ix++ < olduse) { + *tmpc++ = 0; + } + + /* set used count */ + c->used = a->used + 1; + mp_clamp(c); + + return MP_OKAY; +} +#endif diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/md5-internal.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/md5-internal.c new file mode 100644 index 000000000000..a00ca7b5e9c1 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/md5-internal.c @@ -0,0 +1,298 @@ +/* + * MD5 hash implementation and interface functions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/md5.h" +#include "crypto/md5_i.h" +#include "crypto/crypto.h" + + +static void wpa_MD5Transform(u32 buf[4], u32 const in[16]); + + +typedef struct MD5Context MD5_CTX; + + +/** + * md5_vector - MD5 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 of failure + */ +int +wpa_md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + MD5_CTX ctx; + size_t i; + + wpa_MD5Init(&ctx); + for (i = 0; i < num_elem; i++) + wpa_MD5Update(&ctx, addr[i], len[i]); + wpa_MD5Final(mac, &ctx); + return 0; +} + + +/* ===== start - public domain MD5 implementation ===== */ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#ifndef WORDS_BIGENDIAN +#define byteReverse(buf, len) /* Nothing */ +#else +/* + * Note: this code is harmless on little-endian machines. + */ +static void byteReverse(unsigned char *buf, unsigned longs) +{ + u32 t; + do { + t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(u32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +wpa_MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +wpa_MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) +{ + u32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((u32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + os_memcpy(p, buf, len); + return; + } + os_memcpy(p, buf, t); + byteReverse(ctx->in, 16); + wpa_MD5Transform(ctx->buf, (u32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + os_memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + wpa_MD5Transform(ctx->buf, (u32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + os_memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +wpa_MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + os_memset(p, 0, count); + byteReverse(ctx->in, 16); + wpa_MD5Transform(ctx->buf, (u32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + os_memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + os_memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((u32 *) ctx->in)[14] = ctx->bits[0]; + ((u32 *) ctx->in)[15] = ctx->bits[1]; + + wpa_MD5Transform(ctx->buf, (u32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + os_memcpy(digest, ctx->buf, 16); + os_memset(ctx, 0, sizeof(struct MD5Context)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void +wpa_MD5Transform(u32 buf[4], u32 const in[16]) +{ + register u32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} +/* ===== end - public domain MD5 implementation ===== */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/md5.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/md5.c new file mode 100644 index 000000000000..fd0c70b30083 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/md5.c @@ -0,0 +1,113 @@ +/* + * MD5 hash implementation and interface functions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/md5.h" +#include "crypto/crypto.h" + + +/** + * hmac_md5_vector - HMAC-MD5 over data vector (RFC 2104) + * @key: Key for HMAC operations + * @key_len: Length of the key in bytes + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash (16 bytes) + * Returns: 0 on success, -1 on failure + */ +int +wpa_hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + u8 k_pad[64]; /* padding - key XORd with ipad/opad */ + u8 tk[16]; + const u8 *_addr[6]; + size_t i, _len[6]; + + if (num_elem > 5) { + /* + * Fixed limit on the number of fragments to avoid having to + * allocate memory (which could fail). + */ + return -1; + } + + /* if key is longer than 64 bytes reset it to key = MD5(key) */ + if (key_len > 64) { + if (wpa_md5_vector(1, &key, &key_len, tk)) + return -1; + key = tk; + key_len = 16; + } + + /* the HMAC_MD5 transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected */ + + /* start out by storing key in ipad */ + os_memset(k_pad, 0, sizeof(k_pad)); + os_memcpy(k_pad, key, key_len); + + /* XOR key with ipad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x36; + + /* perform inner MD5 */ + _addr[0] = k_pad; + _len[0] = 64; + for (i = 0; i < num_elem; i++) { + _addr[i + 1] = addr[i]; + _len[i + 1] = len[i]; + } + if (wpa_md5_vector(1 + num_elem, _addr, _len, mac)) + return -1; + + os_memset(k_pad, 0, sizeof(k_pad)); + os_memcpy(k_pad, key, key_len); + /* XOR key with opad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x5c; + + /* perform outer MD5 */ + _addr[0] = k_pad; + _len[0] = 64; + _addr[1] = mac; + _len[1] = MD5_MAC_LEN; + return wpa_md5_vector(2, _addr, _len, mac); +} + + +/** + * hmac_md5 - HMAC-MD5 over data buffer (RFC 2104) + * @key: Key for HMAC operations + * @key_len: Length of the key in bytes + * @data: Pointers to the data area + * @data_len: Length of the data area + * @mac: Buffer for the hash (16 bytes) + * Returns: 0 on success, -1 on failure + */ +int +wpa_hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac) +{ + return wpa_hmac_md5_vector(key, key_len, 1, &data, &data_len, mac); +} diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/rc4.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/rc4.c new file mode 100644 index 000000000000..18b37815692f --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/rc4.c @@ -0,0 +1,61 @@ +/* + * RC4 stream cipher + * Copyright (c) 2002-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/crypto.h" + +#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0) + +int +wpa_rc4_skip(const u8 *key, size_t keylen, size_t skip, + u8 *data, size_t data_len) +{ + u32 i, j, k; + u8 S[256], *pos; + size_t kpos; + + /* Setup RC4 state */ + for (i = 0; i < 256; i++) + S[i] = i; + j = 0; + kpos = 0; + for (i = 0; i < 256; i++) { + j = (j + S[i] + key[kpos]) & 0xff; + kpos++; + if (kpos >= keylen) + kpos = 0; + S_SWAP(i, j); + } + + /* Skip the start of the stream */ + i = j = 0; + for (k = 0; k < skip; k++) { + i = (i + 1) & 0xff; + j = (j + S[i]) & 0xff; + S_SWAP(i, j); + } + + /* Apply RC4 to data */ + pos = data; + for (k = 0; k < data_len; k++) { + i = (i + 1) & 0xff; + j = (j + S[i]) & 0xff; + S_SWAP(i, j); + *pos++ ^= S[(S[i] + S[j]) & 0xff]; + } + + return 0; +} diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/sha1-internal.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/sha1-internal.c new file mode 100644 index 000000000000..d3a94c741061 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/sha1-internal.c @@ -0,0 +1,322 @@ +/* + * SHA1 hash implementation and interface functions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/sha1.h" +#include "crypto/sha1_i.h" +#include "crypto/md5.h" +#include "crypto/crypto.h" + +typedef struct SHA1Context SHA1_CTX; + +void wpa_SHA1Transform(u32 state[5], const unsigned char buffer[64]); + + +/** + * sha1_vector - SHA-1 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 of failure + */ +int +wpa_sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + SHA1_CTX ctx; + size_t i; + + wpa_SHA1Init(&ctx); + for (i = 0; i < num_elem; i++) + wpa_SHA1Update(&ctx, addr[i], len[i]); + wpa_SHA1Final(mac, &ctx); + return 0; +} + + +/* ===== start - public domain SHA1 implementation ===== */ + +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +----------------- +Modified 7/98 +By James H. Brown +Still 100% Public Domain + +Corrected a problem which generated improper hash values on 16 bit machines +Routine SHA1Update changed from + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int +len) +to + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned +long len) + +The 'len' parameter was declared an int which works fine on 32 bit machines. +However, on 16 bit machines an int is too small for the shifts being done +against +it. This caused the hash function to generate incorrect values if len was +greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). + +Since the file IO in main() reads 16K at a time, any file 8K or larger would +be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million +"a"s). + +I also changed the declaration of variables i & j in SHA1Update to +unsigned long from unsigned int for the same reason. + +These changes should make no difference to any 32 bit implementations since +an +int and a long are the same size in those environments. + +-- +I also corrected a few compiler warnings generated by Borland C. +1. Added #include for exit() prototype +2. Removed unused variable 'j' in SHA1Final +3. Changed exit(0) to return(0) at end of main. + +ALL changes I made can be located by searching for comments containing 'JHB' +----------------- +Modified 8/98 +By Steve Reid +Still 100% public domain + +1- Removed #include and used return() instead of exit() +2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) +3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net + +----------------- +Modified 4/01 +By Saul Kravitz +Still 100% PD +Modified to run on Compaq Alpha hardware. + +----------------- +Modified 4/01 +By Jouni Malinen +Minor changes to match the coding style used in Dynamics. + +Modified September 24, 2004 +By Jouni Malinen +Fixed alignment issue in wpa_SHA1Transform when SHA1HANDSOFF is defined. + +*/ + +/* +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* Disable the option, and reduce memory copying */ +#define SHA1HANDSOFF + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#ifndef WORDS_BIGENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \ + (rol(block->l[i], 8) & 0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \ + block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) \ + z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R1(v,w,x,y,z,i) \ + z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R2(v,w,x,y,z,i) \ + z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); +#define R3(v,w,x,y,z,i) \ + z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ + w = rol(w, 30); +#define R4(v,w,x,y,z,i) \ + z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ + w=rol(w, 30); + + +#ifdef VERBOSE /* SAK */ +void wpa_SHAPrintContext(SHA1_CTX *context, char *msg) +{ + printf("%s (%d,%d) %x %x %x %x %x\n", + msg, + context->count[0], context->count[1], + context->state[0], + context->state[1], + context->state[2], + context->state[3], + context->state[4]); +} +#endif + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void +wpa_SHA1Transform(u32 state[5], const unsigned char buffer[64]) +{ + u32 a, b, c, d, e; + typedef union { + unsigned char c[64]; + u32 l[16]; + } CHAR64LONG16; + CHAR64LONG16* block; +#ifdef SHA1HANDSOFF + CHAR64LONG16 workspace; + block = &workspace; + os_memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16 *) buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + /* Wipe variables */ + /* Disable to reduce memory copying */ + //a = b = c = d = e = 0; +#ifdef SHA1HANDSOFF + //os_memset(block, 0, 64); +#endif +} + + +/* SHA1Init - Initialize new context */ + +void +wpa_SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void +wpa_SHA1Update(SHA1_CTX* context, const void *_data, u32 len) +{ + u32 i, j; + const unsigned char *data = _data; + +#ifdef VERBOSE + SHAPrintContext(context, "before"); +#endif + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) + context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + os_memcpy(&context->buffer[j], data, (i = 64-j)); + wpa_SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + wpa_SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + os_memcpy(&context->buffer[j], &data[i], len - i); +#ifdef VERBOSE + SHAPrintContext(context, "after "); +#endif +} + + +/* Add padding and return the message digest. */ + +void +wpa_SHA1Final(unsigned char digest[20], SHA1_CTX* context) +{ + u32 i; + unsigned long index; + unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char) + ((context->count[(i >= 4 ? 0 : 1)] >> + ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + + index = 0x80; + wpa_SHA1Update(context, (unsigned char *)&index, 1); + + while ((context->count[0] & 504) != 448) { + index = 0; + wpa_SHA1Update(context, (unsigned char *)&index, 1); + } + wpa_SHA1Update(context, finalcount, 8); /* Should cause a wpa_SHA1Transform() + */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & + 255); + } + /* Wipe variables */ + /* Disable here to reduce memory copying */ + // i = 0; + // os_memset(context->buffer, 0, 64); + // os_memset(context->state, 0, 20); + // os_memset(context->count, 0, 8); + // os_memset(finalcount, 0, 8); +} + +/* ===== end - public domain SHA1 implementation ===== */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/sha1-pbkdf2.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/sha1-pbkdf2.c new file mode 100644 index 000000000000..84af8a127a8d --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/sha1-pbkdf2.c @@ -0,0 +1,101 @@ +/* + * SHA1-based key derivation function (PBKDF2) for IEEE 802.11i + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" +#include "crypto/common.h" +#include "crypto/sha1.h" +#include "crypto/md5.h" +#include "crypto/crypto.h" + +static int +wpa_pbkdf2_sha1_f(const char *passphrase, const char *ssid, + size_t ssid_len, int iterations, unsigned int count, + u8 *digest) +{ + unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN]; + int i, j; + unsigned char count_buf[4]; + const u8 *addr[2]; + size_t len[2]; + size_t passphrase_len = os_strlen(passphrase); + + addr[0] = (u8 *) ssid; + len[0] = ssid_len; + addr[1] = count_buf; + len[1] = 4; + + /* F(P, S, c, i) = U1 xor U2 xor ... Uc + * U1 = PRF(P, S || i) + * U2 = PRF(P, U1) + * Uc = PRF(P, Uc-1) + */ + + count_buf[0] = (count >> 24) & 0xff; + count_buf[1] = (count >> 16) & 0xff; + count_buf[2] = (count >> 8) & 0xff; + count_buf[3] = count & 0xff; + if (wpa_hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len, + tmp)) + return -1; + os_memcpy(digest, tmp, SHA1_MAC_LEN); + + for (i = 1; i < iterations; i++) { + if (wpa_hmac_sha1((u8 *) passphrase, passphrase_len, tmp, + SHA1_MAC_LEN, tmp2)) + return -1; + os_memcpy(tmp, tmp2, SHA1_MAC_LEN); + for (j = 0; j < SHA1_MAC_LEN; j++) + digest[j] ^= tmp2[j]; + } + + return 0; +} + + +/** + * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i + * @passphrase: ASCII passphrase + * @ssid: SSID + * @ssid_len: SSID length in bytes + * @iterations: Number of iterations to run + * @buf: Buffer for the generated key + * @buflen: Length of the buffer in bytes + * Returns: 0 on success, -1 of failure + * + * This function is used to derive PSK for WPA-PSK. For this protocol, + * iterations is set to 4096 and buflen to 32. This function is described in + * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0. + */ +int +wpa_pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, + int iterations, u8 *buf, size_t buflen) +{ + unsigned int count = 0; + unsigned char *pos = buf; + size_t left = buflen, plen; + unsigned char digest[SHA1_MAC_LEN]; + + while (left > 0) { + count++; + if (wpa_pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations, + count, digest)) + return -1; + plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left; + os_memcpy(pos, digest, plen); + pos += plen; + left -= plen; + } + + return 0; +} diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/sha1.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/sha1.c new file mode 100644 index 000000000000..588d5d79b2ac --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/sha1.c @@ -0,0 +1,165 @@ +/* + * SHA1 hash implementation and interface functions + * Copyright (c) 2003-2005, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/sha1.h" +#include "crypto/crypto.h" + + +/** + * hmac_sha1_vector - HMAC-SHA1 over data vector (RFC 2104) + * @key: Key for HMAC operations + * @key_len: Length of the key in bytes + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash (20 bytes) + * Returns: 0 on success, -1 on failure + */ +int +wpa_hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ + unsigned char tk[20]; + const u8 *_addr[6]; + size_t _len[6], i; + + if (num_elem > 5) { + /* + * Fixed limit on the number of fragments to avoid having to + * allocate memory (which could fail). + */ + return -1; + } + + /* if key is longer than 64 bytes reset it to key = SHA1(key) */ + if (key_len > 64) { + if (wpa_sha1_vector(1, &key, &key_len, tk)) + return -1; + key = tk; + key_len = 20; + } + + /* the HMAC_SHA1 transform looks like: + * + * SHA1(K XOR opad, SHA1(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected */ + + /* start out by storing key in ipad */ + os_memset(k_pad, 0, sizeof(k_pad)); + os_memcpy(k_pad, key, key_len); + /* XOR key with ipad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x36; + + /* perform inner SHA1 */ + _addr[0] = k_pad; + _len[0] = 64; + for (i = 0; i < num_elem; i++) { + _addr[i + 1] = addr[i]; + _len[i + 1] = len[i]; + } + if (wpa_sha1_vector(1 + num_elem, _addr, _len, mac)) + return -1; + + os_memset(k_pad, 0, sizeof(k_pad)); + os_memcpy(k_pad, key, key_len); + /* XOR key with opad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x5c; + + /* perform outer SHA1 */ + _addr[0] = k_pad; + _len[0] = 64; + _addr[1] = mac; + _len[1] = SHA1_MAC_LEN; + return wpa_sha1_vector(2, _addr, _len, mac); +} + + +/** + * hmac_sha1 - HMAC-SHA1 over data buffer (RFC 2104) + * @key: Key for HMAC operations + * @key_len: Length of the key in bytes + * @data: Pointers to the data area + * @data_len: Length of the data area + * @mac: Buffer for the hash (20 bytes) + * Returns: 0 on success, -1 of failure + */ +int +wpa_hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac) +{ + return wpa_hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); +} + +/** + * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1) + * @key: Key for PRF + * @key_len: Length of the key in bytes + * @label: A unique label for each purpose of the PRF + * @data: Extra data to bind into the key + * @data_len: Length of the data + * @buf: Buffer for the generated pseudo-random key + * @buf_len: Number of bytes of key to generate + * Returns: 0 on success, -1 of failure + * + * This function is used to derive new, cryptographically separate keys from a + * given key (e.g., PMK in IEEE 802.11i). + */ +int +wpa_sha1_prf(const u8 *key, size_t key_len, const char *label, + const u8 *data, size_t data_len, u8 *buf, size_t buf_len) +{ + u8 counter = 0; + size_t pos, plen; + u8 hash[SHA1_MAC_LEN]; + size_t label_len = os_strlen(label) + 1; + const unsigned char *addr[3]; + size_t len[3]; + + addr[0] = (u8 *) label; + len[0] = label_len; + addr[1] = data; + len[1] = data_len; + addr[2] = &counter; + len[2] = 1; + + pos = 0; + while (pos < buf_len) { + plen = buf_len - pos; + if (plen >= SHA1_MAC_LEN) { + if (wpa_hmac_sha1_vector(key, key_len, 3, addr, len, + &buf[pos])) + return -1; + pos += SHA1_MAC_LEN; + } else { + if (wpa_hmac_sha1_vector(key, key_len, 3, addr, len, + hash)) + return -1; + os_memcpy(&buf[pos], hash, plen); + break; + } + counter++; + } + + return 0; +} diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/sha256-internal.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/sha256-internal.c new file mode 100644 index 000000000000..9d66b1803f6f --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/sha256-internal.c @@ -0,0 +1,249 @@ +/* + * SHA-256 hash implementation and interface functions + * Copyright (c) 2003-2011, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/sha256.h" +#include "crypto/crypto.h" + +#define SHA256_BLOCK_SIZE 64 + +struct sha256_state { + u64 length; + u32 state[8], curlen; + u8 buf[SHA256_BLOCK_SIZE]; +}; + +static void wpa_sha256_init(struct sha256_state *md); +static int wpa_sha256_process(struct sha256_state *md, const unsigned char *in, + unsigned long inlen); +static int wpa_sha256_done(struct sha256_state *md, unsigned char *out); + + +/** + * sha256_vector - SHA256 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 of failure + */ +int +wpa_sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, + u8 *mac) +{ + struct sha256_state ctx; + size_t i; + + wpa_sha256_init(&ctx); + for (i = 0; i < num_elem; i++) + if (wpa_sha256_process(&ctx, addr[i], len[i])) + return -1; + if (wpa_sha256_done(&ctx, mac)) + return -1; + return 0; +} + + +/* ===== start - public domain SHA256 implementation ===== */ + +/* This is based on SHA256 implementation in LibTomCrypt that was released into + * public domain by Tom St Denis. */ + +/* the K array */ +static const unsigned long K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, + 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, + 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, + 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, + 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, + 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, + 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, + 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, + 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + + +/* Various logical functions */ +#define RORc(x, y) \ +( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \ + ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL) +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S(x, n) RORc((x), (n)) +#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +/* compress 512-bits */ +static int +wpa_sha256_compress(struct sha256_state *md, unsigned char *buf) +{ + u32 S[8], W[64], t0, t1; + u32 t; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) { + S[i] = md->state[i]; + } + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) + W[i] = WPA_GET_BE32(buf + (4 * i)); + + /* fill W[16..63] */ + for (i = 16; i < 64; i++) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + + W[i - 16]; + } + + /* Compress */ +#define RND(a,b,c,d,e,f,g,h,i) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + for (i = 0; i < 64; ++i) { + RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i); + t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; + S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; + } + + /* feedback */ + for (i = 0; i < 8; i++) { + md->state[i] = md->state[i] + S[i]; + } + return 0; +} + + +/* Initialize the hash state */ +static void +wpa_sha256_init(struct sha256_state *md) +{ + md->curlen = 0; + md->length = 0; + md->state[0] = 0x6A09E667UL; + md->state[1] = 0xBB67AE85UL; + md->state[2] = 0x3C6EF372UL; + md->state[3] = 0xA54FF53AUL; + md->state[4] = 0x510E527FUL; + md->state[5] = 0x9B05688CUL; + md->state[6] = 0x1F83D9ABUL; + md->state[7] = 0x5BE0CD19UL; +} + +/** + Process a block of memory though the hash + @param md The hash state + @param in The data to hash + @param inlen The length of the data (octets) + @return CRYPT_OK if successful +*/ +static int +wpa_sha256_process(struct sha256_state *md, const unsigned char *in, + unsigned long inlen) +{ + unsigned long n; + + if (md->curlen >= sizeof(md->buf)) + return -1; + + while (inlen > 0) { + if (md->curlen == 0 && inlen >= SHA256_BLOCK_SIZE) { + if (wpa_sha256_compress(md, (unsigned char *) in) < 0) + return -1; + md->length += SHA256_BLOCK_SIZE * 8; + in += SHA256_BLOCK_SIZE; + inlen -= SHA256_BLOCK_SIZE; + } else { + n = MIN(inlen, (SHA256_BLOCK_SIZE - md->curlen)); + os_memcpy(md->buf + md->curlen, in, n); + md->curlen += n; + in += n; + inlen -= n; + if (md->curlen == SHA256_BLOCK_SIZE) { + if (wpa_sha256_compress(md, md->buf) < 0) + return -1; + md->length += 8 * SHA256_BLOCK_SIZE; + md->curlen = 0; + } + } + } + + return 0; +} + + +/** + Terminate the hash to get the digest + @param md The hash state + @param out [out] The destination of the hash (32 bytes) + @return CRYPT_OK if successful +*/ +static int +wpa_sha256_done(struct sha256_state *md, unsigned char *out) +{ + int i; + + if (md->curlen >= sizeof(md->buf)) + return -1; + + /* increase the length of the message */ + md->length += md->curlen * 8; + + /* append the '1' bit */ + md->buf[md->curlen++] = (unsigned char) 0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->curlen > 56) { + while (md->curlen < SHA256_BLOCK_SIZE) { + md->buf[md->curlen++] = (unsigned char) 0; + } + wpa_sha256_compress(md, md->buf); + md->curlen = 0; + } + + /* pad up to 56 bytes of zeroes */ + while (md->curlen < 56) { + md->buf[md->curlen++] = (unsigned char) 0; + } + + /* store length */ + WPA_PUT_BE64(md->buf + 56, md->length); + wpa_sha256_compress(md, md->buf); + + /* copy output */ + for (i = 0; i < 8; i++) + WPA_PUT_BE32(out + (4 * i), md->state[i]); + + return 0; +} + +/* ===== end - public domain SHA256 implementation ===== */ diff --git a/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/sha256.c b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/sha256.c new file mode 100644 index 000000000000..2b195b261218 --- /dev/null +++ b/cpu/esp8266/vendor/esp-idf/wpa_supplicant/src/crypto/sha256.c @@ -0,0 +1,160 @@ +/* + * SHA-256 hash implementation and interface functions + * Copyright (c) 2003-2007, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "crypto/includes.h" + +#include "crypto/common.h" +#include "crypto/sha256.h" +#include "crypto/crypto.h" + + +/** + * hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104) + * @key: Key for HMAC operations + * @key_len: Length of the key in bytes + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash (32 bytes) + */ +void +wpa_hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ + unsigned char tk[32]; + const u8 *_addr[6]; + size_t _len[6], i; + + if (num_elem > 5) { + /* + * Fixed limit on the number of fragments to avoid having to + * allocate memory (which could fail). + */ + return; + } + + /* if key is longer than 64 bytes reset it to key = SHA256(key) */ + if (key_len > 64) { + wpa_sha256_vector(1, &key, &key_len, tk); + key = tk; + key_len = 32; + } + + /* the HMAC_SHA256 transform looks like: + * + * SHA256(K XOR opad, SHA256(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected */ + + /* start out by storing key in ipad */ + os_memset(k_pad, 0, sizeof(k_pad)); + os_memcpy(k_pad, key, key_len); + /* XOR key with ipad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x36; + + /* perform inner SHA256 */ + _addr[0] = k_pad; + _len[0] = 64; + for (i = 0; i < num_elem; i++) { + _addr[i + 1] = addr[i]; + _len[i + 1] = len[i]; + } + wpa_sha256_vector(1 + num_elem, _addr, _len, mac); + + os_memset(k_pad, 0, sizeof(k_pad)); + os_memcpy(k_pad, key, key_len); + /* XOR key with opad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x5c; + + /* perform outer SHA256 */ + _addr[0] = k_pad; + _len[0] = 64; + _addr[1] = mac; + _len[1] = SHA256_MAC_LEN; + wpa_sha256_vector(2, _addr, _len, mac); +} + + +/** + * hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104) + * @key: Key for HMAC operations + * @key_len: Length of the key in bytes + * @data: Pointers to the data area + * @data_len: Length of the data area + * @mac: Buffer for the hash (20 bytes) + */ +void +wpa_hmac_sha256(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *mac) +{ + wpa_hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac); +} + + +/** + * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2) + * @key: Key for PRF + * @key_len: Length of the key in bytes + * @label: A unique label for each purpose of the PRF + * @data: Extra data to bind into the key + * @data_len: Length of the data + * @buf: Buffer for the generated pseudo-random key + * @buf_len: Number of bytes of key to generate + * + * This function is used to derive new, cryptographically separate keys from a + * given key. + */ +void +wpa_sha256_prf(const u8 *key, size_t key_len, const char *label, + const u8 *data, size_t data_len, u8 *buf, size_t buf_len) +{ + u16 counter = 1; + size_t pos, plen; + u8 hash[SHA256_MAC_LEN]; + const u8 *addr[4]; + size_t len[4]; + u8 counter_le[2], length_le[2]; + + addr[0] = counter_le; + len[0] = 2; + addr[1] = (u8 *) label; + len[1] = os_strlen(label); + addr[2] = data; + len[2] = data_len; + addr[3] = length_le; + len[3] = sizeof(length_le); + + WPA_PUT_LE16(length_le, buf_len * 8); + pos = 0; + while (pos < buf_len) { + plen = buf_len - pos; + WPA_PUT_LE16(counter_le, counter); + if (plen >= SHA256_MAC_LEN) { + wpa_hmac_sha256_vector(key, key_len, 4, addr, len, + &buf[pos]); + pos += SHA256_MAC_LEN; + } else { + wpa_hmac_sha256_vector(key, key_len, 4, addr, len, hash); + os_memcpy(&buf[pos], hash, plen); + break; + } + counter++; + } +} diff --git a/cpu/esp8266/vendor/esp/FreeRTOS.h b/cpu/esp8266/vendor/esp/FreeRTOS.h deleted file mode 100644 index 64c2b8225d2c..000000000000 --- a/cpu/esp8266/vendor/esp/FreeRTOS.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2018 Gunar Schorcht - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License v2.1. See the file LICENSE in the top level - * directory for more details. - * - * FreeRTOS to RIOT-OS adaption module - */ - -#ifndef FREERTOS_H -#define FREERTOS_H - -#ifndef DOXYGEN - -#include "stdlib.h" - -#include "mutex.h" -#include "irq.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define SemaphoreHandle_t mutex_t* - -static inline SemaphoreHandle_t xSemaphoreCreateMutex(void) -{ - mutex_t* _tmp = malloc (sizeof(mutex_t)); - mutex_init(_tmp); - return _tmp; -} - -#define xSemaphoreTake(s,to) mutex_lock(s) -#define xSemaphoreGive(s) mutex_unlock(s) - -#define vPortEnterCritical() int _irq_state = irq_disable () -#define vPortExitCritical() irq_restore(_irq_state) - -#ifdef __cplusplus -} -#endif - -#endif // DOXYGEN -#endif /* FREERTOS_H */ diff --git a/cpu/esp8266/vendor/esp/README.md b/cpu/esp8266/vendor/esp/README.md index bf5deb40d3d2..cc57fa847b3f 100644 --- a/cpu/esp8266/vendor/esp/README.md +++ b/cpu/esp8266/vendor/esp/README.md @@ -1,3 +1,3 @@ -All files in this directory are part of [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos.git). They are under the copyright of their respective owners. Please note the copyright notice in these files. +All files in this directory are part of [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos.git). They are under the copyright of their respective owners. All of these files are BSD Licensed as described in the file [LICENSE](https://github.com/SuperHouse/esp-open-rtos/blob/master/LICENSE). diff --git a/cpu/esp8266/vendor/esp/common_macros.h b/cpu/esp8266/vendor/esp/common_macros.h index d14c34639c2b..cca23c921f97 100644 --- a/cpu/esp8266/vendor/esp/common_macros.h +++ b/cpu/esp8266/vendor/esp/common_macros.h @@ -33,7 +33,7 @@ extern "C" { #define UNUSED __attributed((unused)) -#ifndef BIT +#if defined(MCU_ESP8266) && !defined(BIT) #define BIT(X) (1<<(X)) #endif diff --git a/cpu/esp8266/vendor/esp/flashchip.h b/cpu/esp8266/vendor/esp/flashchip.h deleted file mode 100644 index 4aad689d199e..000000000000 --- a/cpu/esp8266/vendor/esp/flashchip.h +++ /dev/null @@ -1,67 +0,0 @@ -/* flashchip.h - * - * sdk_flashchip_t structure used by the SDK and some bootrom routines - * - * This is in a separate include file because it's referenced by several other - * headers which are otherwise independent of each other. - * - * Part of esp-open-rtos - * Copyright (C) 2015 Alex Stewart and Angus Gratton - * BSD Licensed as described in the file LICENSE - */ - -/* -Copyright (C) 2015 Alex Stewart and Angus Gratton -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FLASHCHIP_H -#define FLASHCHIP_H - -#ifndef DOXYGEN - -#ifdef __cplusplus -extern "C" { -#endif - -/* SDK/bootrom uses this structure internally to account for flash size. - - chip_size field is initialised during startup from the flash size - saved in the image header (on the first 8 bytes of SPI flash). - - Other field are initialised to hardcoded values by the SDK. - - ** NOTE: This structure is passed to some bootrom routines and is therefore - fixed. Be very careful if you want to change it that you do not break - things. ** - - Based on RE work by @foogod at - http://esp8266-re.foogod.com/wiki/Flashchip_%28IoT_RTOS_SDK_0.9.9%29 -*/ -typedef struct { - uint32_t device_id; - uint32_t chip_size; /* in bytes */ - uint32_t block_size; /* in bytes */ - uint32_t sector_size; /* in bytes */ - uint32_t page_size; /* in bytes */ - uint32_t status_mask; -} sdk_flashchip_t; - -extern sdk_flashchip_t sdk_flashchip; - -#ifdef __cplusplus -} -#endif - -#endif // DOXYGEN -#endif /* FLASHCHIP_H */ diff --git a/cpu/esp8266/vendor/esp/phy_info.c b/cpu/esp8266/vendor/esp/phy_info.c deleted file mode 100644 index d474b2b8e1c8..000000000000 --- a/cpu/esp8266/vendor/esp/phy_info.c +++ /dev/null @@ -1,200 +0,0 @@ -/* Routines to allow custom access to the Internal Espressif - SDK PHY datastructures. - - Matches espressif/phy_internal.h - - Part of esp-open-rtos. Copyright (C) 2016 Angus Gratton, - BSD Licensed as described in the file LICENSE. - */ - -/* -Copyright (C) 2016 Angus Gratton -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef MODULE_ESP_SDK -#ifdef RIOT_VERSION -#include -#include "c_types.h" -#include "esp/common_macros.h" -#include "esp/flashchip.h" -#include "esp/phy_info.h" -#include "spi_flash.h" -#include "sdk/rom.h" - -#define sdk_spi_flash_read spi_flash_read -#define sdk_spi_flash_write spi_flash_write - -#else -#include -#include -#include -#endif -#include - -static const sdk_phy_info_t IROM default_phy_info = { - ._reserved00 = { 0x05, 0x00, 0x04, 0x02, 0x05 }, - .version = 5, - ._reserved06 = { 0x05, 0x02, 0x05, 0x00, 0x04, 0x05, 0x05, 0x04, - 0x05, 0x05, 0x04,-0x02,-0x03,-0x01,-0x10,-0x10, - -0x10,-0x20,-0x20, -0x20}, - .spur_freq_primary = 225, - .spur_freq_divisor = 10, - .spur_freq_en_h = 0xFF, - .spur_freq_en_l = 0xFF, - - ._reserved1e = { 0xf8, 0, 0xf8, 0xf8 }, - - .target_power = { 82, 78, 74, 68, 64, 56 }, - .target_power_index_mcs = { 0, 0, 1, 1, 2, 3, 4, 5 }, - - .crystal_freq = CRYSTAL_FREQ_26M, - - .sdio_config = SDIO_CONFIG_AUTO, - - .bt_coexist_config = BT_COEXIST_CONFIG_NONE, - .bt_coexist_protocol = BT_COEXIST_PROTOCOL_WIFI_ONLY, - - .dual_ant_config = DUAL_ANT_CONFIG_NONE, - - ._reserved34 = 0x02, - - .crystal_sleep = CRYSTAL_SLEEP_OFF, - - .spur_freq_2_primary = 225, - .spur_freq_2_divisor = 10, - .spur_freq_2_en_h = 0x00, - .spur_freq_2_en_l = 0x00, - .spur_freq_cfg_msb = 0x00, - .spur_freq_2_cfg_msb = 0x00, - .spur_freq_3_cfg = 0x0000, - .spur_freq_4_cfg = 0x0000, - - ._reserved4a = { 0x01, 0x93, 0x43, 0x00 }, - - .low_power_en = false, - .lp_atten_stage01 = LP_ATTEN_STAGE01_23DB, - .lp_atten_bb = 0, - - .pwr_ind_11b_en = false, - .pwr_ind_11b_0 = 0, - .pwr_ind_11b_1 = 0, - - /* Nominal 3.3V VCC. NOTE: This value is 0 in the - esp-open-rtos SDK default config sector, and may be unused - by that version of the SDK? - */ - .pa_vdd = 33, - - /* Note: untested with the esp-open-rtos SDK default config sector, may be unused? */ - .freq_correct_mode = FREQ_CORRECT_DISABLE, - .force_freq_offset = 0, - - /* Note: is zero with the esp-open-rtos SDK default config sector, may be unused? */ - .rf_cal_mode = RF_CAL_MODE_SAVED, -}; - -sdk_phy_info_t* default_phy_info_ref = (sdk_phy_info_t*)&default_phy_info; -sdk_phy_info_t* get_default_phy_info_ref(void) -{ - return (sdk_phy_info_t*)&default_phy_info; -} - -void get_default_phy_info(sdk_phy_info_t *info) __attribute__((weak, alias("get_sdk_default_phy_info"))); - -void get_sdk_default_phy_info(sdk_phy_info_t *info) -{ - memcpy(info, &default_phy_info, sizeof(sdk_phy_info_t)); -} - -void read_saved_phy_info(sdk_phy_info_t *info) -{ - sdk_spi_flash_read(sdk_flashchip.chip_size - sdk_flashchip.sector_size * 4, (uint32_t *)info, sizeof(sdk_phy_info_t)); -} - -void write_saved_phy_info(const sdk_phy_info_t *info) -{ - sdk_spi_flash_write(sdk_flashchip.chip_size - sdk_flashchip.sector_size * 4, (uint32_t *)info, sizeof(sdk_phy_info_t)); -} - -void dump_phy_info(const sdk_phy_info_t *info, bool raw) -{ - printf("version=%d\n", info->version); - printf("spur_freq = %.3f (%d/%d)\n", - (float)info->spur_freq_primary / info->spur_freq_divisor, - info->spur_freq_primary, - info->spur_freq_divisor); - printf("spur_freq_en = 0x%02x 0x%02x\n", info->spur_freq_en_h, - info->spur_freq_en_l); - printf("target_power\n"); - for(int i = 0; i < 6; i++) { - printf(" %d: %.2fdB (raw 0x%02x)\n", i, - info->target_power[i]/4.0, - info->target_power[i]); - } - printf("target_power_index_mcs:"); - for(int i = 0; i < 8; i++) { - printf(" %d%c", info->target_power_index_mcs[i], - i == 7 ? '\n' : ','); - } - - printf("crystal_freq: %s (raw %d)\n", - (info->crystal_freq == CRYSTAL_FREQ_40M ? "40MHz" : - (info->crystal_freq == CRYSTAL_FREQ_26M ? "26MHz" : - (info->crystal_freq == CRYSTAL_FREQ_24M ? "24MHz" : "???"))), - info->crystal_freq); - - printf("sdio_config: %d\n", info->sdio_config); - printf("bt_coexist config: %d protocol: 0x%02x\n", - info->bt_coexist_config, info->bt_coexist_protocol); - printf("dual_ant_config: %d\n", info->dual_ant_config); - - printf("crystal_sleep: %d\n", info->crystal_sleep); - - printf("spur_freq_2 = %.3f (%d/%d)\n", - (float)info->spur_freq_2_primary / info->spur_freq_2_divisor, - info->spur_freq_2_primary, - info->spur_freq_2_divisor); - printf("spur_freq_2_en = 0x%02x 0x%02x\n", info->spur_freq_2_en_h, - info->spur_freq_2_en_l); - - printf("spur_freq_cfg_msb = 0x%02x\n", info->spur_freq_cfg_msb); - printf("spur_freq_2_)cfg_msb = 0x%02x\n", info->spur_freq_2_cfg_msb); - printf("spur_freq_3_cfg = 0x%04x\n", info->spur_freq_3_cfg); - printf("spur_freq_4_cfg = 0x%04x\n", info->spur_freq_4_cfg); - - printf("low_power_en = %d\n", info->low_power_en); - printf("lp_atten_stage01 = 0x%02x\n", info->lp_atten_stage01); - printf("lp_atten_bb = %.2f (raw 0x%02x)\n", info->lp_atten_bb / 4.0, - info->lp_atten_bb); - - printf("pa_vdd = %d\n", info->pa_vdd); - - printf("freq_correct_mode = 0x%02x\n", info->freq_correct_mode); - printf("force_freq_offset = %d\n", info->force_freq_offset); - printf("rf_cal_mode = 0x%02x\n", info->rf_cal_mode); - - if(raw) { - printf("Raw values:"); - uint8_t *p = (uint8_t *)info; - for(unsigned int i = 0; i < sizeof(sdk_phy_info_t); i ++) { - if(i % 8 == 0) { - printf("\n0x%02x:", i); - } - printf(" %02x", p[i]); - } - printf("\n\n"); - } -} - -#endif diff --git a/cpu/esp8266/vendor/esp/phy_info.h b/cpu/esp8266/vendor/esp/phy_info.h deleted file mode 100644 index d069befd0675..000000000000 --- a/cpu/esp8266/vendor/esp/phy_info.h +++ /dev/null @@ -1,509 +0,0 @@ -/** Internal Espressif SDK "PHY info" data structure - - The data structure (sdk_phy_info_t) is used to configure the - ESP8266 PHY layer via the SDK. The fields here are not written - directly to hardware, the SDK code (mostly in libphy) parses this - structure and configures the hardware. - - The structure loaded at reset time from a flash configuration - sector (see read_saved_phy_info()) (Espressif's SDK sources this - from a file "esp_init_data_default.bin"). If no valid structure is - found in the flash config sector then the SDK loads default values - (see get_default_phy_info()). It is possible to implement a custom - get_default_phy_info() to change the PHY default settings (see the - 'version' field below). - - @note It is possible that the SDK will quietly write a new - configuration sector to flash itself following internal - calibration, etc. However this does not seem to happen, you need to - flash it explicitly if you want it stored there. - - @note Most of what is below is unconfirmed, except where a @note - says that it has been confirmed to work as expected. Please - consider submitting notes if you find behaviour here that works or - doesn't work as expected. - - Information on the meaning/offset of fields comes from Espressif's - flash download tool, which uses an Excel spreadsheet (in the - init_data directory of the ZIP file) to configure and a Python - script to convert an esp_init_data_custom.bin file to flash: - http://bbs.espressif.com/viewtopic.php?f=5&t=433 - - Many fields remain undocumented (& disassembly of libphy suggests - that some documented fields supported undocumented values.) - - A few additional notes about the phy_info fields can be found - in the ESP Arduino ESP8266 phy_init_data structure (however most of - that content is verbatim from Espressif's spreadsheet): - https://github.com/esp8266/Arduino/blob/master/cores/esp8266/core_esp8266_phy.c#L29 - - Part of esp-open-rtos. Copyright (C) 2016 Angus Gratton, - BSD Licensed as described in the file LICENSE. - */ - -/* -Copyright (C) 2016 Angus Gratton -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef PHY_INFO_H -#define PHY_INFO_H - -#ifndef DOXYGEN - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* CRYSTAL_FREQ_xx values as used by sdk_phy_info_t.crystal_freq */ -#define CRYSTAL_FREQ_40M 0 -#define CRYSTAL_FREQ_26M 1 -#define CRYSTAL_FREQ_24M 2 - -/* SDIO_CONFIG_xx values as used by sdk_phy_info_t.sdio_config */ -#define SDIO_CONFIG_AUTO 0 /* Uses pin strapping to determine */ -#define SDIO_CONFIG_SDIOV1_1 /* Data output on negative edge */ -#define SDIO_CONFIG_SDIOV2_0 /* data output on positive edge */ - -/* BT_COEXIST_CONFIG_xx values as used by sdk_phy_info_t.bt_coexist */ -/* No bluetooth */ -#define BT_COEXIST_CONFIG_NONE 0 -/* Coexistence configuration A: - GPIO 0 - WLAN_ACTIVE - GPIO 14 - BT_ACTIVE - GPIO 13 - BT_PRIORITY - GPIO 3 - ANT_SEL_BT -*/ -#define BT_COEXIST_CONFIG_A 1 -/* No coexistence, but Bluetooth enabled? - Unsure how this works? - */ -#define BT_COEXIST_CONFIG_PRESENT 2 -/* Coexistence configuration B: - GPIO 0 - WLAN_ACTIVE - GPIO 14 - BT_PRIORITY - GPIO 13 - BT_ACTIVE - GPIO 3 - ANT_SEL_BT -*/ -#define BT_COEXIST_CONFIG_B 3 - -/* BT_COEXIST_PROTOCOL_xx values for coexistence protocol, - field sdk_phy_info_t.bt_coexist_protocol - */ -#define BT_COEXIST_PROTOCOL_WIFI_ONLY 0 -#define BT_COEXIST_PROTOCOL_BT_ONLY 1 - -/* Coexistence is enabled, Bluetooth has its own antenna */ -#define BT_COEXIST_PROTOCOL_FLAG_SEPARATE_ANT 2 -/* Coexistence is enabled, Bluetooth shares WiFi antenna */ -#define BT_COEXIST_PROTOCOL_FLAG_SHARE_ANT 4 - -/* Coexistence is enabled, use only BT_ACTIVE signal */ -#define BT_COEXIST_PROTOCOL_FLAG_BT_ACTIVE_ONLY 0 -/* Coexistence is enabled, use both BT_ACTIVE and BT_PRIORITY signals */ -#define BT_COEXIST_PROTOCOL_FLAG_BT_ACTIVE_PRIORITY 1 - -/* DUAL_ANT_CONFIG_xx values for dual antenna config, - field sdk_phy_info_t.dual_ant_config - - (Not really clear how this feature works, if at all.) -*/ -#define DUAL_ANT_CONFIG_NONE 0 -/* antenna diversity for WiFi, use GPIO0 + U0RXD (?) */ -#define DUAL_ANT_CONFIG_DUAL 1 -/* TX/RX switch for external PA & LNA: GPIO 0 high, GPIO 3 low during TX */ -#define DUAL_ANT_CONFIG_TX_GPIO0_HIGH_GPIO3_LOW -/* TX/RX switch for external PA & LNA: GPIO 0 low, GPIO 3 high during TX */ -#define DUAL_ANT_CONFIG_TX_GPIO0_LOW_GPIO3_HIGH - - -/* CRYSTAL_SLEEP_xx values used for sdk_phy_info_t.crystal_sleep - */ -#define CRYSTAL_SLEEP_OFF 0 -#define CRYSTAL_SLEEP_ON 1 -#define CRYSTAL_SLEEP_GPIO16 2 -#define CRYSTAL_SLEEP_GPIO2 3 - -/* RF Stage 0 & 1 attenuation constants. Use for sdk_phy_info_t.lp_atten_stage01 - - @note These values have been tested and are confirmed to work as - expected by measuring RSSI w/ rt73 USB adapter in monitor mode - (some values also checked on spectrum analyzer) - provided - low_power_en is set then the signal is attenuated as per this - setting. - - (It may look like LP_ATTEN_STAGE01_11_5DB is out of order, but - according to monitor mode captures this is the correct ordering of - these constants.) - - Setting the numeric values in between these constants appears to - also attenuate the signal, but not necessarily by the amount you'd - expect. -*/ -#define LP_ATTEN_STAGE01_0DB 0x0f /* 0dB */ -#define LP_ATTEN_STAGE01_2_5DB 0x0e /* -2.5dB */ -#define LP_ATTEN_STAGE01_6DB 0x0d /* -6dB */ -#define LP_ATTEN_STAGE01_8_5DB 0x09 /* -8.5dB */ -#define LP_ATTEN_STAGE01_11_5DB 0x0c /* -11.5dB */ -#define LP_ATTEN_STAGE01_14DB 0x08 /* -14dB */ -#define LP_ATTEN_STAGE01_17_5DB 0x04 /* -17.5dB */ -#define LP_ATTEN_STAGE01_23DB 0x00 /* -23dB */ - -/* Constant for sdk_phy_info_t.pa_vdd */ -#define PA_VDD_MEASURE_VCC 0xFF - -/* Bitmask flags for sdk_phy_info_t.freq_correct_mode */ - -/* Set this flag to disable frequency offset correction */ -#define FREQ_CORRECT_DISABLE 0 - -/* Set this flag to enable frequency offset correction */ -#define FREQ_CORRECT_ENABLE BIT(0) - -/* Set = Baseband PLL frequency is 160MHz (can only apply +ve offset) - * Unset = Baseband PLL frequency is 168MHz (can apply +ve/-ve offset */ -#define FREQ_CORRECT_BB_160M BIT(1) - -/* Set = use force_freq_offset field to correct, Unset = automatically - measure & correct offset -*/ -#define FREQ_CORRECT_FORCE BIT(2) - - -/* RF_CAL_MODE_xx fields used for sdk_phy_info_t.rf_cal_mode - */ -/* Use saved RF CAL data from flash, only. RF init takes 2ms. */ -#define RF_CAL_MODE_SAVED 0 -/* Calibrate TX power control only, use saved RF CAL data for others. - RF init takes 20ms. */ -#define RF_CAL_MODE_TXPOWER_ONLY 1 -/* Unclear if/how this mode is different to 2? */ -#define RF_CAL_MODE_SAVED_2 2 -/* Run full RF CAL routine. RF init takes approx 200ms. */ -#define RF_CAL_MODE_FULL 3 - -/* Data structure that maps to the phy_info configuration block */ -typedef struct __attribute__((packed)) { - uint8_t _reserved00[0x05]; /* 0x00 - 0x04 */ - - /* This "version" field was set to 5 in the SDK phy_info, - and the original SDK startup code checks it is 5 and then loads - default PHY configuration otherwise. - - esp-open-rtos will load phy_info from get_default_phy_info() if - the value stored in flash has a different value to the value - returned in get_default_phy_info(). This means you can - increment the version return by get_default_phy_info() (to any - value but 0xFF), and know that the new defaults will replace - any older stored values. - - @notes It's not clear whether this is actually a version field - (the other 24 bytes here have equally arbitrary numbers in - them.) Changing the "version" to other values does not seem to - effect WiFi performance at all, neither does zeroing out the - first 5 reserved bytes in _reserved00. However zeroing bytes in - the _reserved06 region will break WiFi entirely. - */ - uint8_t version; /* 0x05 */ - int8_t _reserved06[0x14]; /* 0x06 - 0x19 */ - - /* spur_freq = spur_freq_primary / spur_freq_divisor */ - uint8_t spur_freq_primary; /* 0x1a */ - uint8_t spur_freq_divisor; /* 0x1b */ - - /* Bitmask to enable spur_freq for each channel - Appears to be a big endian short word? - */ - uint8_t spur_freq_en_h; /* 0x1c */ - uint8_t spur_freq_en_l; /* 0x1d */ - - uint8_t _reserved1e[4]; /* 0x1e - 0x21 */ - - /* Each value is a target power level. - Units are 1/4 dBm ie value 64 = 16dBm. - - SDK defaults to using these transmit powers: - 20.5dBm, 19.5dBm, 18.5dBm, 17dBm, 16dBm, 14dBm - - @note Adjusting these values is confirmed to reduce - transmit power accordingly. - */ - uint8_t target_power[6]; /* 0x22 - 0x27 */ - - /* Maps 8 MCS (modulation & coding schemes) types for 802.11b, g & - * n to a target_power level index (0-5), set above. - - This mapping of MCS slot to MCS type is derived from the - spreadsheet and also a table sent by Espressif, but is untested - and may be SDK version dependendent (especially any 802.11n - rates). However the general relationship is confirmed to hold - (higher MCS index = higher bit rate). - - MCS 0: 1Mbps/2Mbps/5.5Mbps/11Mbps (802.11b) / 6Mbps/9Mbps (802.11g) - default target_power 0 (default 20.5dBm) - (see also pwr_ind_11b_en) - - MCS 1: 12Mbps (802.11g) - default target_power 0 (default 20.5dBm) - - MCS 2: 18Mbps (802.11g) - default target_power 1 (19.5dBm) - - MCS 3: 24Mbps (802.11g) - default target_power 1 (19.5dBm) - - MCS 4: 36Mbps (802.11g) - default target_power 2 (18.5dBm) - - MCS 5: 48Mbps (802.11g) - default target_power 3 (17dBm) - - MCS 6: 54Mbps (802.11g) - default target_power 4 (16dBm) - - MCS 7: 65Mbps (802.11n) - unclear if ever used? - default target_power 5 (14dBm) - */ - uint8_t target_power_index_mcs[8]; /* 0x28 - 0x2f */ - - /* One of CRYSTAL_FREQ_40M / CRYSTAL_FREQ_26M / CRYSTAL_FREQ_24M - - The crystal configured here is the input to the PLL setting - calculations which are used to derive the CPU & APB peripheral - clock frequency, and probably the WiFi PLLs (unconfirmed.) - */ - uint8_t crystal_freq; /* 0x30 */ - - uint8_t _unused31; /* 0x31: Possibly high byte of crystal freq? */ - - /* One of SDIO_CONFIG_AUTO, SDIO_CONFIG_SDIOV1_1, SDIO_CONFIG_SDIOV2_0 */ - uint8_t sdio_config; /* 0x32 */ - - /* BT coexistence pin configuration. - - One of BT_COEXIST_CONFIG_NONE, BT_COEXIST_CONFIG_A, - BT_COEXIST_CONFIG_PRESENT, BT_COEXIST_CONFIG_B - */ - uint8_t bt_coexist_config; /* 0x33 */ - - /* BT coexistence pin protocol. - - If no coexistence: - Either BT_COEXIST_PROTOCOL_WIFI_ONLY, or - BT_COEXIST_PROTOCOL_BT_ONLY. - - If coexistence: - Combine one of - BT_COEXIST_PROTOCOL_FLAG_SEPARATE_ANT or - BT_COEXIST_PROTOCOL_FLAG_SHARE_ANT - with one of - BT_COEXIST_PROTOCOL_FLAG_BT_ACTIVE_ONLY or - BT_COEXIST_PROTOCOL_FLAG_BT_ACTIVE_BT_PRIORITY - */ - uint8_t bt_coexist_protocol; /* 0x34 */ - - /* Dual antenna configuration - - One of DUAL_ANT_CONFIG_NONE, DUAL_ANT_CONFIG_DUAL, - DUAL_ANT_CONFIG_TX_GPIO0_HIGH_GPIO3_LOW, - DUAL_ANT_CONFIG_TX_GPIO0_LOW_GPIO3_HIGH - */ - uint8_t dual_ant_config; /* 0x35 */ - - uint8_t _reserved34; /* 0x36 */ - - /* For sharing crystal clock with other devices: - one of CRYSTAL_SLEEP_OFF, CRYSTAL_SLEEP_ON, - CRYSTAL_SLEEP_GPIO16, CRYSTAL_SLEEP_GPIO2 - */ - uint8_t crystal_sleep; /* 0x37 */ - - uint8_t _unused38[8]; - - /* spur_freq_2 = spur_freq_2_primary / spur_freq_2_divisor */ - uint8_t spur_freq_2_primary; /* 0x40 */ - uint8_t spur_freq_2_divisor; /* 0x41 */ - - /* Bitmask to enable spur_freq_2 for each channel? - Appears to be a big endian short word? - */ - uint8_t spur_freq_2_en_h; /* 0x42 */ - uint8_t spur_freq_2_en_l; /* 0x43 */ - - /* Not really clear what these do */ - uint8_t spur_freq_cfg_msb; /* 0x44 */ - uint8_t spur_freq_2_cfg_msb; /* 0x45 */ - uint16_t spur_freq_3_cfg; /* 0x46 - 0x47 */ - uint16_t spur_freq_4_cfg; /* 0x48 - 0x49 */ - - uint8_t _reserved4a[4]; /* 0x4a - 0x4d */ - - uint8_t _unused78[15]; /* 0x4e - 0x5c */ - - /* Flag to enable low power mode */ - uint8_t low_power_en; /* 0x5d */ - - /* Low Power attenuation of RF gain stages 0 & 1 - - Attenuates transmit power if/when low_power_en is set. - - Use one of the constants LP_ATTEN_STAGE01_0DB, - LP_ATTEN_STAGE01_2_5DB, LP_ATTEN_STAGE01_6DB, - LP_ATTEN_STAGE01_8_5DB, LP_ATTEN_STAGE01_11_5DB, - LP_ATTEN_STAGE01_14DB, LP_ATTEN_STAGE01_17_5DB, - LP_ATTEN_STAGE01_23DB. - */ - uint8_t lp_atten_stage01; /* 0x5e */ - - /* Low Power(?) attenuation of baseband gain - - Units are minus 1/4 dB, ie value 4 == -1dB. - - Maximum value is 24 (0x18) == -6dB - */ - uint8_t lp_atten_bb; /* 0x5f */ - - /* I believe this means, when pwr_ind_11b_en == 0 then the 802.11g - MCS 0 level from target_power_index_mcs are used to - determine 802.11b transmit power level. - - However, when pwr_ind_11b_en == 1 then the index values in - pwr_ind_11b_0 & pwr_ind_11b_1 are used for 802.11b instead. - - This is all unconfirmed, if you can confirm then please update - this comment. - */ - uint8_t pwr_ind_11b_en; /* 0x60 */ - - /* 802.11b low data rate power index (0~5). - Sets the power level index for operation at 1 & 2Mbps - */ - uint8_t pwr_ind_11b_0; /* 0x61 */ - - /* 802.11b high data rate power index (0~5) - Sets the power level index for operation at 5.5 & 11Mbps - */ - uint8_t pwr_ind_11b_1; /* 0x62 */ - - uint8_t _unused63[8]; /* 0x63 - 0x6a */ - - /* Set the voltage of PA_VDD, which appears to be an internal analog - reference voltage(?) - - This field is called vdd33_const in the Arduino phy fields, - and relates to usage of the TOUT pin (ADC pin). - - Set to PA_VDD_MEASURE_VCC (0xFF) and leave TOUT (ADC) pin - floating in order to use the ADC to measure the 3.3V input - voltage. - - Set to value in the range 18-36 (1.8V to 3.6V) to set a - reference voltage(?) when using TOUT pin as an ADC input. I - think this is the reference voltage used to scale the 0-1V - which is allowed on the pin, in order to get an accurate - reading. So it should be set to a value that matches system - VCC... I think! - */ - uint8_t pa_vdd; /* 0x6b */ - - /* Disable RF calibration cycle for this many times */ - uint8_t disable_rfcal_count; /* 0x6c */ - - uint8_t _unused6d[3]; - - /* Flags for frequency correction - - A bitmask combination of any of: FREQ_CORRECT_DISABLE, - FREQ_CORRECT_ENABLE, FREQ_CORRECT_BB_160M, FREQ_CORRECT_FORCE - */ - uint8_t freq_correct_mode; /* 0x70 */ - - /* Force frequency offset adjustment (instead of auto measuring) - units are 1 = 8kHz, full range +/- 1016kHz. - - Only used if FREQ_CORRECT_ENABLE and FREQ_CORRECT_FORCE are - set in freq_correct_mode. - - Unclear whether setting FREQ_CORRECT_BB_160M (which allows only positive offsets) changes the usable range. - */ - int8_t force_freq_offset; /* 0x71 */ - - /* Use stored data in flash for RF calibration. - - This field was previously called rf_cal_use_flash. - - Acceptable values one of RF_CAL_MODE_SAVED, RF_CAL_MODE_TXPOWER_ONLY, RF_CAL_MODE_SAVED_2, RF_CAL_MODE_FULL. - */ - uint8_t rf_cal_mode; /* 0x72 */ - - uint8_t _unused73[13]; -} sdk_phy_info_t; - -/* Some sanity check static assertions. These can probably be - removed after this structure has been better tested. -*/ -_Static_assert(sizeof(sdk_phy_info_t) == 128, "sdk_phy_info_t is wrong size!"); -_Static_assert(offsetof(sdk_phy_info_t, version) == 5, "version at wrong offset"); -_Static_assert(offsetof(sdk_phy_info_t, target_power) == 34, "target_power_qdb at wrong offset"); -_Static_assert(offsetof(sdk_phy_info_t, bt_coexist_protocol) == 52, "bt_coexist_protocol at wrong offset"); -_Static_assert(offsetof(sdk_phy_info_t, spur_freq_2_primary) == 64, "spur_freq_2_primary at wrong offset"); -_Static_assert(offsetof(sdk_phy_info_t, lp_atten_stage01) == 94, "lp_atten_stage01 at wrong offset"); -_Static_assert(offsetof(sdk_phy_info_t, pa_vdd) == 107, "pa_vdd aka vdd33_const at wrong offset"); -_Static_assert(offsetof(sdk_phy_info_t, rf_cal_mode) == 114, "rf_cal_use_flash at wrong offset!"); - -/* Read the default PHY info into the supplied structure. - - This function is weak-aliased to get_sdk_default_phy_info() so you - can replace it with your own if you want to vary the default values - - suggested way to do this is to call get_sdk_default_phy_info() - and then only update the fields you care about. - - The default PHY info is used at startup whenever the version field - in the default sdk_phy_info_t does not match the version field - stored in flash. So you can increment the version field to force a - reset to defaults, regardless of what values are in flash. -*/ -void get_default_phy_info(sdk_phy_info_t *info); - -/* Read the "SDK default" PHY info as used by the Espressif SDK */ -void get_sdk_default_phy_info(sdk_phy_info_t *info); - -/* Read the PHY info currently stored in the SPI flash SDK configuration sector. - - This PHY info is updated by the SDK following RF calibration, etc. - - Note that the saved data may be corrupt - read the 'version' field to verify. -*/ -void read_saved_phy_info(sdk_phy_info_t *info); - -/* Update the saved PHY info in the SPI flash. A reset is necessary to use these values. - - Note that the SDK may clobber these values, so it's recommended you reset ASAP after updating them. -*/ -void write_saved_phy_info(const sdk_phy_info_t *info); - -/* Dump known fields in the phy info structure to stdout, - if 'raw' flag is set then the raw hex values are also dumped. -*/ -void dump_phy_info(const sdk_phy_info_t *info, bool raw); - -#ifdef __cplusplus -} -#endif - -#endif // DOXYGEN -#endif /* PHY_INFO_H */ diff --git a/cpu/esp8266/vendor/esp/rom.h b/cpu/esp8266/vendor/esp/rom.h deleted file mode 100644 index 71721c55a5ff..000000000000 --- a/cpu/esp8266/vendor/esp/rom.h +++ /dev/null @@ -1,57 +0,0 @@ -/* "Boot ROM" function signatures - - Note that a lot of the ROM functions used in the IoT SDK aren't - referenced from the Espressif RTOS SDK, and are probably incompatible. - */ - -/* -Copyright (c) 2015, SuperHouse Automation Pty Ltd -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef ROM_H -#define ROM_H - -#include "esp/types.h" -#include "flashchip.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void Cache_Read_Disable(void); - -/* http://esp8266-re.foogod.com/wiki/Cache_Read_Enable - - Note: when compiling non-OTA we use the ROM version of this - function, but for OTA we use the version in extras/rboot-ota that - maps the correct flash page for OTA support. - */ -void Cache_Read_Enable(uint32_t odd_even, uint32_t mb_count, uint32_t no_idea); - -/* Low-level SPI flash read/write routines */ -int Enable_QMode(sdk_flashchip_t *chip); -int Disable_QMode(sdk_flashchip_t *chip); -int SPI_page_program(sdk_flashchip_t *chip, uint32_t dest_addr, uint32_t *src_addr, uint32_t size); -int SPI_read_data(sdk_flashchip_t *chip, uint32_t src_addr, uint32_t *dest_addr, uint32_t size); -int SPI_write_enable(sdk_flashchip_t *chip); -int SPI_sector_erase(sdk_flashchip_t *chip, uint32_t addr); -int SPI_read_status(sdk_flashchip_t *chip, uint32_t *status); -int SPI_write_status(sdk_flashchip_t *chip, uint32_t status); -int Wait_SPI_Idle(sdk_flashchip_t *chip); - -#ifdef __cplusplus -} -#endif - -#endif /* ROM_H */ diff --git a/cpu/esp8266/vendor/esp/rtcmem_regs.h b/cpu/esp8266/vendor/esp/rtcmem_regs.h deleted file mode 100644 index ca7d0bdd153c..000000000000 --- a/cpu/esp8266/vendor/esp/rtcmem_regs.h +++ /dev/null @@ -1,67 +0,0 @@ -/* esp/rtcmem_regs.h - * - * ESP8266 RTC semi-persistent memory register definitions - * - * Not compatible with ESP SDK register access code. - */ - -/* -Copyright (c) 2015, SuperHouse Automation Pty Ltd -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef RTCMEM_REGS_H -#define RTCMEM_REGS_H - -#include "esp/types.h" -#include "common_macros.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* The RTC memory is a range of 256 words (1 KB) of general-purpose memory - * within the Real Time Clock peripheral. Because it's part of the RTC, it - * continues to be powered (and retains its contents) even when the ESP8266 is - * in its deepest sleep mode (and other RAM is lost). It can therefore be - * useful for keeping data which must be persisted through sleep or a reset. - * - * Note, however, that it is not "battery backed", or flash memory, and thus - * will not keep its contents if power is removed entirely. - */ - -// We could just define these as 'volatile uint32_t *', but doing things this -// way means that the RTCMEM* defines will include array size information, so -// the C compiler can do bounds-checking for static arguments. - -typedef volatile uint32_t rtcmem_array64_t[64]; -typedef volatile uint32_t rtcmem_array128_t[128]; -typedef volatile uint32_t rtcmem_array256_t[256]; - -#define RTCMEM_BASE 0x60001000 - -/* RTCMEM is an array covering the entire semi-persistent memory range */ -#define RTCMEM (*(rtcmem_array256_t *)(RTCMEM_BASE)) - -/* RTCMEM_BACKUP / RTCMEM_SYSTEM / RTCMEM_USER are the same range, divided up - * into chunks by application/use, as defined by Espressif */ - -#define RTCMEM_BACKUP (*(rtcmem_array64_t *)(RTCMEM_BASE)) -#define RTCMEM_SYSTEM (*(rtcmem_array64_t *)(RTCMEM_BASE + 0x100)) -#define RTCMEM_USER (*(rtcmem_array128_t *)(RTCMEM_BASE + 0x200)) - -#ifdef __cplusplus -} -#endif - -#endif /* RTCMEM_REGS_H */ diff --git a/cpu/esp8266/vendor/esp/spi_regs.h b/cpu/esp8266/vendor/esp/spi_regs.h deleted file mode 100644 index 58000fda88e8..000000000000 --- a/cpu/esp8266/vendor/esp/spi_regs.h +++ /dev/null @@ -1,271 +0,0 @@ -/** esp/spi.h - * - * Configuration of SPI registers. - * - * Part of esp-open-rtos - * Copyright (C) 2015 Superhouse Automation Pty Ltd - * BSD Licensed as described in the file LICENSE - */ - -/* -Copyright (c) 2015, SuperHouse Automation Pty Ltd -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef SPI_REGS_H -#define SPI_REGS_H - -#ifndef DOXYGEN - -#ifdef __cplusplus -extern "C" { -#endif - -#include "esp/types.h" -#include "common_macros.h" - -/* Register definitions for the SPI peripherals on the ESP8266. - * - * There are twp SPI devices built into the ESP8266: - * SPI(0) is at 0x60000200 - * SPI(1) is at 0x60000100 - * (note that the device number order is reversed in memory) - * - * Each device is allocated a block of 64 32-bit registers (256 bytes of - * address space) to communicate with application code. - */ - -#define SPI_BASE 0x60000200 -#define SPI(i) (*(struct SPI_REGS *)(0x60000200 - (i)*0x100)) - -#define SPI0_BASE SPI_BASE -#define SPI1_BASE (SPI_BASE - 0x100) - -struct SPI_REGS { - uint32_t volatile CMD; // 0x00 - uint32_t volatile ADDR; // 0x04 - uint32_t volatile CTRL0; // 0x08 - uint32_t volatile CTRL1; // 0x0c - uint32_t volatile RSTATUS; // 0x10 - uint32_t volatile CTRL2; // 0x14 - uint32_t volatile CLOCK; // 0x18 - uint32_t volatile USER0; // 0x1c - uint32_t volatile USER1; // 0x20 - uint32_t volatile USER2; // 0x24 - uint32_t volatile WSTATUS; // 0x28 - uint32_t volatile PIN; // 0x2c - uint32_t volatile SLAVE0; // 0x30 - uint32_t volatile SLAVE1; // 0x34 - uint32_t volatile SLAVE2; // 0x38 - uint32_t volatile SLAVE3; // 0x3c - uint32_t volatile W[16]; // 0x40 - 0x7c - uint32_t volatile _unused[28]; // 0x80 - 0xec - uint32_t volatile EXT0; // 0xf0 - uint32_t volatile EXT1; // 0xf4 - uint32_t volatile EXT2; // 0xf8 - uint32_t volatile EXT3; // 0xfc -}; - -_Static_assert(sizeof(struct SPI_REGS) == 0x100, "SPI_REGS is the wrong size"); - -/* Details for CMD register */ - -#define SPI_CMD_READ BIT(31) -#define SPI_CMD_WRITE_ENABLE BIT(30) -#define SPI_CMD_WRITE_DISABLE BIT(29) -#define SPI_CMD_READ_ID BIT(28) -#define SPI_CMD_READ_SR BIT(27) -#define SPI_CMD_WRITE_SR BIT(26) -#define SPI_CMD_PP BIT(25) -#define SPI_CMD_SE BIT(24) -#define SPI_CMD_BE BIT(23) -#define SPI_CMD_CE BIT(22) -#define SPI_CMD_DP BIT(21) -#define SPI_CMD_RES BIT(20) -#define SPI_CMD_HPM BIT(19) -#define SPI_CMD_USR BIT(18) - -/* Details for CTRL0 register */ - -#define SPI_CTRL0_WR_BIT_ORDER BIT(26) -#define SPI_CTRL0_RD_BIT_ORDER BIT(25) -#define SPI_CTRL0_QIO_MODE BIT(24) -#define SPI_CTRL0_DIO_MODE BIT(23) -#define SPI_CTRL0_QOUT_MODE BIT(20) -#define SPI_CTRL0_DOUT_MODE BIT(14) -#define SPI_CTRL0_FASTRD_MODE BIT(13) -#define SPI_CTRL0_CLOCK_EQU_SYS_CLOCK BIT(12) -#define SPI_CTRL0_CLOCK_NUM_M 0x0000000F -#define SPI_CTRL0_CLOCK_NUM_S 8 -#define SPI_CTRL0_CLOCK_HIGH_M 0x0000000F -#define SPI_CTRL0_CLOCK_HIGH_S 4 -#define SPI_CTRL0_CLOCK_LOW_M 0x0000000F -#define SPI_CTRL0_CLOCK_LOW_S 0 - -/* Mask for the CLOCK_NUM/CLOCK_HIGH/CLOCK_LOW combined, in case one wants - * to set them all as a single value. - */ -#define SPI_CTRL0_CLOCK_M 0x00000FFF -#define SPI_CTRL0_CLOCK_S 0 - -/* Details for CTRL2 register */ - -#define SPI_CTRL2_CS_DELAY_NUM_M 0x0000000F -#define SPI_CTRL2_CS_DELAY_NUM_S 28 -#define SPI_CTRL2_CS_DELAY_MODE_M 0x00000003 -#define SPI_CTRL2_CS_DELAY_MODE_S 26 -#define SPI_CTRL2_MOSI_DELAY_NUM_M 0x00000007 -#define SPI_CTRL2_MOSI_DELAY_NUM_S 23 -#define SPI_CTRL2_MOSI_DELAY_MODE_M 0x00000003 -#define SPI_CTRL2_MOSI_DELAY_MODE_S 21 -#define SPI_CTRL2_MISO_DELAY_NUM_M 0x00000007 -#define SPI_CTRL2_MISO_DELAY_NUM_S 18 -#define SPI_CTRL2_MISO_DELAY_MODE_M 0x00000003 -#define SPI_CTRL2_MISO_DELAY_MODE_S 16 - -/* Details for CLOCK register */ - -#define SPI_CLOCK_EQU_SYS_CLOCK BIT(31) -#define SPI_CLOCK_DIV_PRE_M 0x00001FFF -#define SPI_CLOCK_DIV_PRE_S 18 -#define SPI_CLOCK_COUNT_NUM_M 0x0000003F -#define SPI_CLOCK_COUNT_NUM_S 12 -#define SPI_CLOCK_COUNT_HIGH_M 0x0000003F -#define SPI_CLOCK_COUNT_HIGH_S 6 -#define SPI_CLOCK_COUNT_LOW_M 0x0000003F -#define SPI_CLOCK_COUNT_LOW_S 0 - -/* Mask for the COUNT_NUM/COUNT_HIGH/COUNT_LOW combined, in case one wants - * to set them all as a single value. - */ -#define SPI_CTRL0_COUNT_M 0x0003FFFF -#define SPI_CTRL0_COUNT_S 0 - -/* Details for USER0 register */ - -#define SPI_USER0_COMMAND BIT(31) -#define SPI_USER0_ADDR BIT(30) -#define SPI_USER0_DUMMY BIT(29) -#define SPI_USER0_MISO BIT(28) -#define SPI_USER0_MOSI BIT(27) -#define SPI_USER0_MOSI_HIGHPART BIT(25) -#define SPI_USER0_MISO_HIGHPART BIT(24) -#define SPI_USER0_SIO BIT(16) -#define SPI_USER0_FWRITE_QIO BIT(15) -#define SPI_USER0_FWRITE_DIO BIT(14) -#define SPI_USER0_FWRITE_QUAD BIT(13) -#define SPI_USER0_FWRITE_DUAL BIT(12) -#define SPI_USER0_WR_BYTE_ORDER BIT(11) -#define SPI_USER0_RD_BYTE_ORDER BIT(10) -#define SPI_USER0_CLOCK_OUT_EDGE BIT(7) -#define SPI_USER0_CLOCK_IN_EDGE BIT(6) -#define SPI_USER0_CS_SETUP BIT(5) -#define SPI_USER0_CS_HOLD BIT(4) -#define SPI_USER0_FLASH_MODE BIT(2) -#define SPI_USER0_DUPLEX BIT(0) - -/* Details for USER1 register */ - -#define SPI_USER1_ADDR_BITLEN_M 0x0000003F -#define SPI_USER1_ADDR_BITLEN_S 26 -#define SPI_USER1_MOSI_BITLEN_M 0x000001FF -#define SPI_USER1_MOSI_BITLEN_S 17 -#define SPI_USER1_MISO_BITLEN_M 0x000001FF -#define SPI_USER1_MISO_BITLEN_S 8 -#define SPI_USER1_DUMMY_CYCLELEN_M 0x000000FF -#define SPI_USER1_DUMMY_CYCLELEN_S 0 - -/* Details for USER2 register */ - -#define SPI_USER2_COMMAND_BITLEN_M 0x0000000F -#define SPI_USER2_COMMAND_BITLEN_S 28 -#define SPI_USER2_COMMAND_VALUE_M 0x0000FFFF -#define SPI_USER2_COMMAND_VALUE_S 0 - -/* Details for PIN register */ - -#define SPI_PIN_IDLE_EDGE BIT(29) ///< CPOL -#define SPI_PIN_CS2_DISABLE BIT(2) -#define SPI_PIN_CS1_DISABLE BIT(1) -#define SPI_PIN_CS0_DISABLE BIT(0) - -/* Details for SLAVE0 register */ - -#define SPI_SLAVE0_SYNC_RESET BIT(31) -#define SPI_SLAVE0_MODE BIT(30) -#define SPI_SLAVE0_WR_RD_BUF_EN BIT(29) -#define SPI_SLAVE0_WR_RD_STA_EN BIT(28) -#define SPI_SLAVE0_CMD_DEFINE BIT(27) -#define SPI_SLAVE0_TRANS_COUNT_M 0x0000000F -#define SPI_SLAVE0_TRANS_COUNT_S 23 -#define SPI_SLAVE0_TRANS_DONE_EN BIT(9) -#define SPI_SLAVE0_WR_STA_DONE_EN BIT(8) -#define SPI_SLAVE0_RD_STA_DONE_EN BIT(7) -#define SPI_SLAVE0_WR_BUF_DONE_EN BIT(6) -#define SPI_SLAVE0_RD_BUF_DONE_EN BIT(5) -#define SPI_SLAVE0_INT_EN_M 0x0000001f -#define SPI_SLAVE0_INT_EN_S 5 -#define SPI_SLAVE0_TRANS_DONE BIT(4) -#define SPI_SLAVE0_WR_STA_DONE BIT(3) -#define SPI_SLAVE0_RD_STA_DONE BIT(2) -#define SPI_SLAVE0_WR_BUF_DONE BIT(1) -#define SPI_SLAVE0_RD_BUF_DONE BIT(0) - -/* Details for SLAVE1 register */ - -#define SPI_SLAVE1_STATUS_BITLEN_M 0x0000001F -#define SPI_SLAVE1_STATUS_BITLEN_S 27 -#define SPI_SLAVE1_BUF_BITLEN_M 0x000001FF -#define SPI_SLAVE1_BUF_BITLEN_S 16 -#define SPI_SLAVE1_RD_ADDR_BITLEN_M 0x0000003F -#define SPI_SLAVE1_RD_ADDR_BITLEN_S 10 -#define SPI_SLAVE1_WR_ADDR_BITLEN_M 0x0000003F -#define SPI_SLAVE1_WR_ADDR_BITLEN_S 4 -#define SPI_SLAVE1_WRSTA_DUMMY_ENABLE BIT(3) -#define SPI_SLAVE1_RDSTA_DUMMY_ENABLE BIT(2) -#define SPI_SLAVE1_WRBUF_DUMMY_ENABLE BIT(1) -#define SPI_SLAVE1_RDBUF_DUMMY_ENABLE BIT(0) - -/* Details for SLAVE2 register */ - -#define SPI_SLAVE2_WRBUF_DUMMY_CYCLELEN_M 0x000000FF -#define SPI_SLAVE2_WRBUF_DUMMY_CYCLELEN_S 24 -#define SPI_SLAVE2_RDBUF_DUMMY_CYCLELEN_M 0x000000FF -#define SPI_SLAVE2_RDBUF_DUMMY_CYCLELEN_S 16 -#define SPI_SLAVE2_WRSTR_DUMMY_CYCLELEN_M 0x000000FF -#define SPI_SLAVE2_WRSTR_DUMMY_CYCLELEN_S 8 -#define SPI_SLAVE2_RDSTR_DUMMY_CYCLELEN_M 0x000000FF -#define SPI_SLAVE2_RDSTR_DUMMY_CYCLELEN_S 0 - -/* Details for SLAVE3 register */ - -#define SPI_SLAVE3_WRSTA_CMD_VALUE_M 0x000000FF -#define SPI_SLAVE3_WRSTA_CMD_VALUE_S 24 -#define SPI_SLAVE3_RDSTA_CMD_VALUE_M 0x000000FF -#define SPI_SLAVE3_RDSTA_CMD_VALUE_S 16 -#define SPI_SLAVE3_WRBUF_CMD_VALUE_M 0x000000FF -#define SPI_SLAVE3_WRBUF_CMD_VALUE_S 8 -#define SPI_SLAVE3_RDBUF_CMD_VALUE_M 0x000000FF -#define SPI_SLAVE3_RDBUF_CMD_VALUE_S 0 - -/* Details for EXT3 register */ - -#define SPI_EXT3_INT_HOLD_ENABLE_M 0x00000003 -#define SPI_EXT3_INT_HOLD_ENABLE_S 0 - -#ifdef __cplusplus -} -#endif - -#endif // DOXYGEN -#endif /* SPI_REGS_H */ diff --git a/cpu/esp8266/vendor/esp/spiflash.c b/cpu/esp8266/vendor/esp/spiflash.c deleted file mode 100644 index 20b7d1b87ded..000000000000 --- a/cpu/esp8266/vendor/esp/spiflash.c +++ /dev/null @@ -1,267 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2016 sheinz (https://github.com/sheinz) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifdef RIOT_VERSION -#include "esp/spiflash.h" -#include "esp/flashchip.h" -#include "esp/rom.h" -#include "esp/spi_regs.h" -#include "esp/FreeRTOS.h" -#else -#include "include/spiflash.h" -#include "include/flashchip.h" -#include "include/esp/rom.h" -#include "include/esp/spi_regs.h" -#include -#endif - -#include - -/** - * Note about Wait_SPI_Idle. - * - * Each write/erase flash operation sets BUSY bit in flash status register. - * If attempt to access flash while BUSY bit is set operation will fail. - * Function Wait_SPI_Idle loops until this bit is not cleared. - * - * The approach in the following code is that each write function that is - * accessible from the outside should leave flash in Idle state. - * The read operations doesn't set BUSY bit in a flash. So they do not wait. - * They relay that previous operation is completely finished. - * - * This approach is different from ESP8266 bootrom where Wait_SPI_Idle is - * called where it needed and not. - */ - -#define SPI_WRITE_MAX_SIZE 64 - -// 64 bytes read causes hang -// http://bbs.espressif.com/viewtopic.php?f=6&t=2439 -#define SPI_READ_MAX_SIZE 60 - - -/** - * Low level SPI flash write. Write block of data up to 64 bytes. - */ -static inline void IRAM spi_write_data(sdk_flashchip_t *chip, uint32_t addr, - uint8_t *buf, uint32_t size) -{ - uint32_t words = size >> 2; - if (size & 0b11) { - words++; - } - - Wait_SPI_Idle(chip); // wait for previous write to finish - - SPI(0).ADDR = (addr & 0x00FFFFFF) | (size << 24); - - memcpy((void*)SPI(0).W, buf, words<<2); - - __asm__ volatile("memw"); - - SPI_write_enable(chip); - - SPI(0).CMD = SPI_CMD_PP; - while (SPI(0).CMD) {} -} - -/** - * Write a page of flash. Data block should not cross page boundary. - */ -static bool IRAM spi_write_page(sdk_flashchip_t *flashchip, uint32_t dest_addr, - uint8_t *buf, uint32_t size) -{ - // check if block to write doesn't cross page boundary - if (flashchip->page_size < size + (dest_addr % flashchip->page_size)) { - return false; - } - - if (size < 1) { - return true; - } - - while (size >= SPI_WRITE_MAX_SIZE) { - spi_write_data(flashchip, dest_addr, buf, SPI_WRITE_MAX_SIZE); - - size -= SPI_WRITE_MAX_SIZE; - dest_addr += SPI_WRITE_MAX_SIZE; - buf += SPI_WRITE_MAX_SIZE; - - if (size < 1) { - return true; - } - } - - spi_write_data(flashchip, dest_addr, buf, size); - - return true; -} - -/** - * Split block of data into pages and write pages. - */ -static bool IRAM spi_write(uint32_t addr, uint8_t *dst, uint32_t size) -{ - if (sdk_flashchip.chip_size < (addr + size)) { - return false; - } - - uint32_t write_bytes_to_page = sdk_flashchip.page_size - - (addr % sdk_flashchip.page_size); // TODO: place for optimization - - if (size < write_bytes_to_page) { - if (!spi_write_page(&sdk_flashchip, addr, dst, size)) { - return false; - } - } else { - if (!spi_write_page(&sdk_flashchip, addr, dst, write_bytes_to_page)) { - return false; - } - - uint32_t offset = write_bytes_to_page; - uint32_t pages_to_write = (size - offset) / sdk_flashchip.page_size; - for (uint32_t i = 0; i < pages_to_write; i++) { - if (!spi_write_page(&sdk_flashchip, addr + offset, - dst + offset, sdk_flashchip.page_size)) { - return false; - } - offset += sdk_flashchip.page_size; - } - - if (!spi_write_page(&sdk_flashchip, addr + offset, - dst + offset, size - offset)) { - return false; - } - } - - return true; -} - -bool IRAM spiflash_write(uint32_t addr, uint8_t *buf, uint32_t size) -{ - bool result = false; - - if (buf) { - vPortEnterCritical(); - Cache_Read_Disable(); - - result = spi_write(addr, buf, size); - - // make sure all write operations is finished before exiting - Wait_SPI_Idle(&sdk_flashchip); - - Cache_Read_Enable(0, 0, 1); - vPortExitCritical(); - } - - return result; -} - -/** - * Read SPI flash up to 64 bytes. - */ -static inline void IRAM read_block(sdk_flashchip_t *chip, uint32_t addr, - uint8_t *buf, uint32_t size) -{ - SPI(0).ADDR = (addr & 0x00FFFFFF) | (size << 24); - SPI(0).CMD = SPI_CMD_READ; - - while (SPI(0).CMD) {}; - - __asm__ volatile("memw"); - - memcpy(buf, (const void*)SPI(0).W, size); -} - -/** - * Read SPI flash data. Data region doesn't need to be page aligned. - */ -static inline bool IRAM read_data(sdk_flashchip_t *flashchip, uint32_t addr, - uint8_t *dst, uint32_t size) -{ - if (size < 1) { - return true; - } - - if ((addr + size) > flashchip->chip_size) { - return false; - } - - while (size >= SPI_READ_MAX_SIZE) { - read_block(flashchip, addr, dst, SPI_READ_MAX_SIZE); - dst += SPI_READ_MAX_SIZE; - size -= SPI_READ_MAX_SIZE; - addr += SPI_READ_MAX_SIZE; - } - - if (size > 0) { - read_block(flashchip, addr, dst, size); - } - - return true; -} - -bool IRAM spiflash_read(uint32_t dest_addr, uint8_t *buf, uint32_t size) -{ - bool result = false; - - if (buf) { - vPortEnterCritical(); - Cache_Read_Disable(); - - result = read_data(&sdk_flashchip, dest_addr, buf, size); - - Cache_Read_Enable(0, 0, 1); - vPortExitCritical(); - } - - return result; -} - -bool IRAM spiflash_erase_sector(uint32_t addr) -{ - if ((addr + sdk_flashchip.sector_size) > sdk_flashchip.chip_size) { - return false; - } - - if (addr & 0xFFF) { - return false; - } - - vPortEnterCritical(); - Cache_Read_Disable(); - - SPI_write_enable(&sdk_flashchip); - - SPI(0).ADDR = addr & 0x00FFFFFF; - SPI(0).CMD = SPI_CMD_SE; - while (SPI(0).CMD) {}; - - Wait_SPI_Idle(&sdk_flashchip); - - Cache_Read_Enable(0, 0, 1); - vPortExitCritical(); - - return true; -} diff --git a/cpu/esp8266/vendor/esp/spiflash.h b/cpu/esp8266/vendor/esp/spiflash.h deleted file mode 100644 index bf93f629ddeb..000000000000 --- a/cpu/esp8266/vendor/esp/spiflash.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2016 sheinz (https://github.com/sheinz) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef SPIFLASH_H -#define SPIFLASH_H - -#include -#include -#include "common_macros.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define SPI_FLASH_SECTOR_SIZE 4096 - -/** - * Read data from SPI flash. - * - * @param addr Address to read from. Can be not aligned. - * @param buf Buffer to read to. Doesn't have to be aligned. - * @param size Size of data to read. Buffer size must be >= than data size. - * - * @return true if success, otherwise false - */ -bool IRAM spiflash_read(uint32_t addr, uint8_t *buf, uint32_t size); - -/** - * Write data to SPI flash. - * - * @param addr Address to write to. Can be not aligned. - * @param buf Buffer of data to write to flash. Doesn't have to be aligned. - * @param size Size of data to write. Buffer size must be >= than data size. - * - * @return true if success, otherwise false - */ -bool IRAM spiflash_write(uint32_t addr, uint8_t *buf, uint32_t size); - -/** - * Erase a sector. - * - * @param addr Address of sector to erase. Must be sector aligned. - * - * @return true if success, otherwise false - */ -bool IRAM spiflash_erase_sector(uint32_t addr); - -#ifdef __cplusplus -} -#endif - -#endif /* SPIFLASH_H */ diff --git a/cpu/esp8266/vendor/esp/wdev_regs.h b/cpu/esp8266/vendor/esp/wdev_regs.h deleted file mode 100644 index e832b5e887d8..000000000000 --- a/cpu/esp8266/vendor/esp/wdev_regs.h +++ /dev/null @@ -1,67 +0,0 @@ -/* esp/wdev_regs.h - * - * ESP8266 register definitions for the "wdev" region (0x3FF2xxx) - * - * In the DPORT memory space, alongside DPORT regs. However mostly - * concerned with the WiFi hardware interface. - * - * Not compatible with ESP SDK register access code. - */ - -/* -Copyright (c) 2015, SuperHouse Automation Pty Ltd -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef WDEV_REGS_H -#define WDEV_REGS_H - -#ifndef DOXYGEN - -#include "esp/types.h" -#include "common_macros.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define WDEV_BASE 0x3FF20000 -#define WDEV (*(struct WDEV_REGS *)(WDEV_BASE)) - -/* Note: This memory region is not currently well understood. Pretty much all - * of the definitions here are from reverse-engineering the Espressif SDK code, - * many are just educated guesses, and almost certainly some are misleading or - * wrong. If you can improve on any of this, please contribute! - */ - -struct WDEV_REGS { - uint32_t volatile _unknown0[768]; // 0x0000 - 0x0bfc - uint32_t volatile SYS_TIME; // 0x0c00 - uint32_t volatile _unknown1[144]; // 0x0c04 - 0x0e40 - uint32_t volatile HWRNG; // 0xe44 HW RNG, see http://esp8266-re.foogod.com/wiki/Random_Number_Generator -} __attribute__ (( packed )); - -_Static_assert(sizeof(struct WDEV_REGS) == 0xe48, "WDEV_REGS is the wrong size"); - -/* Extra paranoid check about the HWRNG address, as if this becomes - wrong there will be no obvious symptoms apart from a lack of - entropy. -*/ -_Static_assert(&WDEV.HWRNG == (void*)0x3FF20E44, "HWRNG register is at wrong address"); - -#ifdef __cplusplus -} -#endif - -#endif // DOXYGEN -#endif /* WDEV_REGS_H */ diff --git a/cpu/esp8266/vendor/espressif/README.md b/cpu/esp8266/vendor/espressif/README.md deleted file mode 100644 index 4507ffe49026..000000000000 --- a/cpu/esp8266/vendor/espressif/README.md +++ /dev/null @@ -1 +0,0 @@ -The files in this directory are either from the [ESP8266_NONOS_SDK](https://github.com/espressif/ESP8266_NONOS_SDK.git) or from the [ESP_RTOS_SDK](https://github.com/espressif/ESP8266_RTOS_SDK.git) for ESP8266. All of these files are copyright of Espressif Systems (Shanghai) Pte., Ltd. Please note the copyright notice in these files. diff --git a/cpu/esp8266/vendor/espressif/c_types.h b/cpu/esp8266/vendor/espressif/c_types.h deleted file mode 100644 index c712044bb7b2..000000000000 --- a/cpu/esp8266/vendor/espressif/c_types.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2016 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef C_TYPES_H -#define C_TYPES_H - -/* Following header guards are necessary to avoid conflicts with original */ -/* header in SDK where _C_TYPES_H_ is used */ -#ifndef _C_TYPES_H_ -#define _C_TYPES_H_ - -#ifndef DOXYGEN -#ifndef _DTLS_GLOBAL_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef signed char sint8_t; -typedef signed short sint16_t; -typedef signed long sint32_t; -typedef signed long long sint64_t; -typedef unsigned long long u_int64_t; -typedef float real32_t; -typedef double real64_t; - -typedef unsigned char uint8; -typedef unsigned char u8; -typedef signed char sint8; -typedef signed char int8; -typedef signed char s8; -typedef unsigned short uint16; -typedef unsigned short u16; -typedef signed short sint16; -typedef signed short s16; -typedef unsigned int uint32; -typedef unsigned int u_int; -typedef unsigned int u32; -typedef signed int sint32; -typedef signed int s32; -typedef int int32; -typedef signed long long sint64; -typedef unsigned long long uint64; -typedef unsigned long long u64; -typedef float real32; -typedef double real64; - -#define __le16 u16 - -typedef unsigned int size_t; - -/* #define __packed __attribute__((packed)) */ - -#define LOCAL static - -#ifndef NULL -#define NULL (void *)0 -#endif /* NULL */ - -/* probably should not put STATUS here */ -typedef enum { - OK = 0, - FAIL, - PENDING, - BUSY, - CANCEL, -} STATUS; - -#ifndef BIT -#define BIT(nr) (1UL << (nr)) -#endif - -#define REG_SET_BIT(_r, _b) (*(volatile uint32_t*)(_r) |= (_b)) -#define REG_CLR_BIT(_r, _b) (*(volatile uint32_t*)(_r) &= ~(_b)) - -#define DMEM_ATTR __attribute__((section(".bss"))) -#define SHMEM_ATTR - -#ifdef ICACHE_FLASH -#define ICACHE_FLASH_ATTR __attribute__((section(".irom0.text"))) -#define ICACHE_RODATA_ATTR __attribute__((section(".irom.text"))) -#else -#define ICACHE_FLASH_ATTR -#define ICACHE_RODATA_ATTR -#endif /* ICACHE_FLASH */ - -#define STORE_ATTR __attribute__((aligned(4))) - -#ifndef __cplusplus -#define BOOL bool -#ifndef true -#define true (1) -#endif -#ifndef false -#define false (0) -#endif -#ifndef TRUE -#define TRUE true -#endif -#ifndef FALSE -#define FALSE false -#endif - -#endif /* !__cplusplus */ - -#ifdef __cplusplus -} -#endif - -#endif /* _DTLS_GLOBAL_H_ */ -#endif /* DOXYGEN */ -#endif /* _C_TYPES_H_ */ -#endif /* C_TYPES_H */ diff --git a/cpu/esp8266/vendor/espressif/eagle_soc.h b/cpu/esp8266/vendor/espressif/eagle_soc.h deleted file mode 100644 index fdfe61a07ed1..000000000000 --- a/cpu/esp8266/vendor/espressif/eagle_soc.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2016 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef EAGLE_SOC_H -#define EAGLE_SOC_H - -#ifndef DOXYGEN - -#ifdef __cplusplus -extern "C" { -#endif - -//Register Bits{{ -#define BIT31 0x80000000 -#define BIT30 0x40000000 -#define BIT29 0x20000000 -#define BIT28 0x10000000 -#define BIT27 0x08000000 -#define BIT26 0x04000000 -#define BIT25 0x02000000 -#define BIT24 0x01000000 -#define BIT23 0x00800000 -#define BIT22 0x00400000 -#define BIT21 0x00200000 -#define BIT20 0x00100000 -#define BIT19 0x00080000 -#define BIT18 0x00040000 -#define BIT17 0x00020000 -#define BIT16 0x00010000 -#define BIT15 0x00008000 -#define BIT14 0x00004000 -#define BIT13 0x00002000 -#define BIT12 0x00001000 -#define BIT11 0x00000800 -#define BIT10 0x00000400 -#define BIT9 0x00000200 -#define BIT8 0x00000100 -#define BIT7 0x00000080 -#define BIT6 0x00000040 -#define BIT5 0x00000020 -#define BIT4 0x00000010 -#define BIT3 0x00000008 -#define BIT2 0x00000004 -#define BIT1 0x00000002 -#define BIT0 0x00000001 -//}} - -//Registers Operation {{ -#define ETS_UNCACHED_ADDR(addr) (addr) -#define ETS_CACHED_ADDR(addr) (addr) - - -#define READ_PERI_REG(addr) (*((volatile uint32_t *)ETS_UNCACHED_ADDR(addr))) -#define WRITE_PERI_REG(addr, val) (*((volatile uint32_t *)ETS_UNCACHED_ADDR(addr))) = (uint32_t)(val) -#define CLEAR_PERI_REG_MASK(reg, mask) WRITE_PERI_REG((reg), (READ_PERI_REG(reg)&(~(mask)))) -#define SET_PERI_REG_MASK(reg, mask) WRITE_PERI_REG((reg), (READ_PERI_REG(reg)|(mask))) -#define GET_PERI_REG_BITS(reg, hipos,lowpos) ((READ_PERI_REG(reg)>>(lowpos))&((1<<((hipos)-(lowpos)+1))-1)) -#define SET_PERI_REG_BITS(reg,bit_map,value,shift) (WRITE_PERI_REG((reg),(READ_PERI_REG(reg)&(~((bit_map)<<(shift))))|((value)<<(shift)) )) -//}} - -//Periheral Clock {{ -#define APB_CLK_FREQ 80*1000000 //unit: Hz -#define UART_CLK_FREQ APB_CLK_FREQ -#define TIMER_CLK_FREQ (APB_CLK_FREQ>>8) //divided by 256 -//}} - -//Peripheral device base address define{{ -#define PERIPHS_DPORT_BASEADDR 0x3ff00000 -#define PERIPHS_GPIO_BASEADDR 0x60000300 -#define PERIPHS_TIMER_BASEDDR 0x60000600 -#define PERIPHS_RTC_BASEADDR 0x60000700 -#define PERIPHS_IO_MUX 0x60000800 -//}} - -//Interrupt remap control registers define{{ -#define EDGE_INT_ENABLE_REG (PERIPHS_DPORT_BASEADDR+0x04) -#define TM1_EDGE_INT_ENABLE() SET_PERI_REG_MASK(EDGE_INT_ENABLE_REG, BIT1) -#define TM1_EDGE_INT_DISABLE() CLEAR_PERI_REG_MASK(EDGE_INT_ENABLE_REG, BIT1) -//}} - -//GPIO reg {{ -#define GPIO_REG_READ(reg) READ_PERI_REG(PERIPHS_GPIO_BASEADDR + reg) -#define GPIO_REG_WRITE(reg, val) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + reg, val) -#define GPIO_OUT_ADDRESS 0x00 -#define GPIO_OUT_W1TS_ADDRESS 0x04 -#define GPIO_OUT_W1TC_ADDRESS 0x08 - -#define GPIO_ENABLE_ADDRESS 0x0c -#define GPIO_ENABLE_W1TS_ADDRESS 0x10 -#define GPIO_ENABLE_W1TC_ADDRESS 0x14 -#define GPIO_OUT_W1TC_DATA_MASK 0x0000ffff - -#define GPIO_IN_ADDRESS 0x18 - -#define GPIO_STATUS_ADDRESS 0x1c -#define GPIO_STATUS_W1TS_ADDRESS 0x20 -#define GPIO_STATUS_W1TC_ADDRESS 0x24 -#define GPIO_STATUS_INTERRUPT_MASK 0x0000ffff - -#define GPIO_RTC_CALIB_SYNC PERIPHS_GPIO_BASEADDR+0x6c -#define RTC_CALIB_START BIT31 //first write to zero, then to one to start -#define RTC_PERIOD_NUM_MASK 0x3ff //max 8ms -#define GPIO_RTC_CALIB_VALUE PERIPHS_GPIO_BASEADDR+0x70 -#define RTC_CALIB_RDY_S 31 //after measure, flag to one, when start from zero to one, turn to zero -#define RTC_CALIB_VALUE_MASK 0xfffff - -#define GPIO_PIN0_ADDRESS 0x28 - -#define GPIO_ID_PIN0 0 -#define GPIO_ID_PIN(n) (GPIO_ID_PIN0+(n)) -#define GPIO_LAST_REGISTER_ID GPIO_ID_PIN(15) -#define GPIO_ID_NONE 0xffffffff - -#define GPIO_PIN_COUNT 16 - -#define GPIO_PIN_CONFIG_MSB 12 -#define GPIO_PIN_CONFIG_LSB 11 -#define GPIO_PIN_CONFIG_MASK 0x00001800 -#define GPIO_PIN_CONFIG_GET(x) (((x) & GPIO_PIN_CONFIG_MASK) >> GPIO_PIN_CONFIG_LSB) -#define GPIO_PIN_CONFIG_SET(x) (((x) << GPIO_PIN_CONFIG_LSB) & GPIO_PIN_CONFIG_MASK) - -#define GPIO_WAKEUP_ENABLE 1 -#define GPIO_WAKEUP_DISABLE (~GPIO_WAKEUP_ENABLE) -#define GPIO_PIN_WAKEUP_ENABLE_MSB 10 -#define GPIO_PIN_WAKEUP_ENABLE_LSB 10 -#define GPIO_PIN_WAKEUP_ENABLE_MASK 0x00000400 -#define GPIO_PIN_WAKEUP_ENABLE_GET(x) (((x) & GPIO_PIN_WAKEUP_ENABLE_MASK) >> GPIO_PIN_WAKEUP_ENABLE_LSB) -#define GPIO_PIN_WAKEUP_ENABLE_SET(x) (((x) << GPIO_PIN_WAKEUP_ENABLE_LSB) & GPIO_PIN_WAKEUP_ENABLE_MASK) - -#define GPIO_PIN_INT_TYPE_MASK 0x380 -#define GPIO_PIN_INT_TYPE_MSB 9 -#define GPIO_PIN_INT_TYPE_LSB 7 -#define GPIO_PIN_INT_TYPE_GET(x) (((x) & GPIO_PIN_INT_TYPE_MASK) >> GPIO_PIN_INT_TYPE_LSB) -#define GPIO_PIN_INT_TYPE_SET(x) (((x) << GPIO_PIN_INT_TYPE_LSB) & GPIO_PIN_INT_TYPE_MASK) - -#define GPIO_PAD_DRIVER_ENABLE 1 -#define GPIO_PAD_DRIVER_DISABLE (~GPIO_PAD_DRIVER_ENABLE) -#define GPIO_PIN_PAD_DRIVER_MSB 2 -#define GPIO_PIN_PAD_DRIVER_LSB 2 -#define GPIO_PIN_PAD_DRIVER_MASK 0x00000004 -#define GPIO_PIN_PAD_DRIVER_GET(x) (((x) & GPIO_PIN_PAD_DRIVER_MASK) >> GPIO_PIN_PAD_DRIVER_LSB) -#define GPIO_PIN_PAD_DRIVER_SET(x) (((x) << GPIO_PIN_PAD_DRIVER_LSB) & GPIO_PIN_PAD_DRIVER_MASK) - -#define GPIO_AS_PIN_SOURCE 0 -#define SIGMA_AS_PIN_SOURCE (~GPIO_AS_PIN_SOURCE) -#define GPIO_PIN_SOURCE_MSB 0 -#define GPIO_PIN_SOURCE_LSB 0 -#define GPIO_PIN_SOURCE_MASK 0x00000001 -#define GPIO_PIN_SOURCE_GET(x) (((x) & GPIO_PIN_SOURCE_MASK) >> GPIO_PIN_SOURCE_LSB) -#define GPIO_PIN_SOURCE_SET(x) (((x) << GPIO_PIN_SOURCE_LSB) & GPIO_PIN_SOURCE_MASK) -// }} - -// TIMER reg {{ -#define RTC_REG_READ(addr) READ_PERI_REG(PERIPHS_TIMER_BASEDDR + addr) -#define RTC_REG_WRITE(addr, val) WRITE_PERI_REG(PERIPHS_TIMER_BASEDDR + addr, val) -#define RTC_CLR_REG_MASK(reg, mask) CLEAR_PERI_REG_MASK(PERIPHS_TIMER_BASEDDR +reg, mask) -/* Returns the current time according to the timer timer. */ -#define NOW() RTC_REG_READ(FRC2_COUNT_ADDRESS) - -//load initial_value to timer1 -#define FRC1_LOAD_ADDRESS 0x00 - -//timer1's counter value(count from initial_value to 0) -#define FRC1_COUNT_ADDRESS 0x04 - -#define FRC1_CTRL_ADDRESS 0x08 - -//clear timer1's interrupt when write this address -#define FRC1_INT_ADDRESS 0x0c -#define FRC1_INT_CLR_MASK 0x00000001 - -//timer2's counter value(count from initial_value to 0) -#define FRC2_COUNT_ADDRESS 0x24 -// }} - -//RTC reg {{ -#define REG_RTC_BASE PERIPHS_RTC_BASEADDR - -#define RTC_STORE0 (REG_RTC_BASE + 0x030) -#define RTC_STORE1 (REG_RTC_BASE + 0x034) -#define RTC_STORE2 (REG_RTC_BASE + 0x038) -#define RTC_STORE3 (REG_RTC_BASE + 0x03C) - -#define RTC_GPIO_OUT (REG_RTC_BASE + 0x068) -#define RTC_GPIO_ENABLE (REG_RTC_BASE + 0x074) -#define RTC_GPIO_IN_DATA (REG_RTC_BASE + 0x08C) -#define RTC_GPIO_CONF (REG_RTC_BASE + 0x090) -#define PAD_XPD_DCDC_CONF (REG_RTC_BASE + 0x0A0) -//}} - -//PIN Mux reg {{ -#define PERIPHS_IO_MUX_FUNC 0x13 -#define PERIPHS_IO_MUX_FUNC_S 4 -#define PERIPHS_IO_MUX_PULLUP BIT7 -#define PERIPHS_IO_MUX_PULLUP2 BIT6 -#define PERIPHS_IO_MUX_SLEEP_PULLUP BIT3 -#define PERIPHS_IO_MUX_SLEEP_PULLUP2 BIT2 -#define PERIPHS_IO_MUX_SLEEP_OE BIT1 -#define PERIPHS_IO_MUX_OE BIT0 - -#define PERIPHS_IO_MUX_CONF_U (PERIPHS_IO_MUX + 0x00) -#define SPI0_CLK_EQU_SYS_CLK BIT8 -#define SPI1_CLK_EQU_SYS_CLK BIT9 -#define PERIPHS_IO_MUX_MTDI_U (PERIPHS_IO_MUX + 0x04) -#define FUNC_GPIO12 3 -#define PERIPHS_IO_MUX_MTCK_U (PERIPHS_IO_MUX + 0x08) -#define FUNC_GPIO13 3 -#define PERIPHS_IO_MUX_MTMS_U (PERIPHS_IO_MUX + 0x0C) -#define FUNC_GPIO14 3 -#define PERIPHS_IO_MUX_MTDO_U (PERIPHS_IO_MUX + 0x10) -#define FUNC_GPIO15 3 -#define FUNC_U0RTS 4 -#define PERIPHS_IO_MUX_U0RXD_U (PERIPHS_IO_MUX + 0x14) -#define FUNC_GPIO3 3 -#define PERIPHS_IO_MUX_U0TXD_U (PERIPHS_IO_MUX + 0x18) -#define FUNC_U0TXD 0 -#define FUNC_GPIO1 3 -#define PERIPHS_IO_MUX_SD_CLK_U (PERIPHS_IO_MUX + 0x1c) -#define FUNC_SDCLK 0 -#define FUNC_SPICLK 1 -#define PERIPHS_IO_MUX_SD_DATA0_U (PERIPHS_IO_MUX + 0x20) -#define FUNC_SDDATA0 0 -#define FUNC_SPIQ 1 -#define FUNC_U1TXD 4 -#define PERIPHS_IO_MUX_SD_DATA1_U (PERIPHS_IO_MUX + 0x24) -#define FUNC_SDDATA1 0 -#define FUNC_SPID 1 -#define FUNC_U1RXD 4 -#define FUNC_SDDATA1_U1RXD 7 -#define PERIPHS_IO_MUX_SD_DATA2_U (PERIPHS_IO_MUX + 0x28) -#define FUNC_SDDATA2 0 -#define FUNC_SPIHD 1 -#define FUNC_GPIO9 3 -#define PERIPHS_IO_MUX_SD_DATA3_U (PERIPHS_IO_MUX + 0x2c) -#define FUNC_SDDATA3 0 -#define FUNC_SPIWP 1 -#define FUNC_GPIO10 3 -#define PERIPHS_IO_MUX_SD_CMD_U (PERIPHS_IO_MUX + 0x30) -#define FUNC_SDCMD 0 -#define FUNC_SPICS0 1 -#define PERIPHS_IO_MUX_GPIO0_U (PERIPHS_IO_MUX + 0x34) -#define FUNC_GPIO0 0 -#define PERIPHS_IO_MUX_GPIO2_U (PERIPHS_IO_MUX + 0x38) -#define FUNC_GPIO2 0 -#define FUNC_U1TXD_BK 2 -#define FUNC_U0TXD_BK 4 -#define PERIPHS_IO_MUX_GPIO4_U (PERIPHS_IO_MUX + 0x3C) -#define FUNC_GPIO4 0 -#define PERIPHS_IO_MUX_GPIO5_U (PERIPHS_IO_MUX + 0x40) -#define FUNC_GPIO5 0 - -#define PIN_PULLUP_DIS(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME, PERIPHS_IO_MUX_PULLUP) -#define PIN_PULLUP_EN(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME, PERIPHS_IO_MUX_PULLUP) - -#define PIN_FUNC_SELECT(PIN_NAME, FUNC) do { \ - WRITE_PERI_REG(PIN_NAME, \ - (READ_PERI_REG(PIN_NAME) \ - & (~(PERIPHS_IO_MUX_FUNC< - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef ETS_SYS_H -#define ETS_SYS_H - -/* Following header guards are necessary to avoid conflicts with original */ -/* header in SDK where _ETS_SYS_H is used */ -#ifndef _ETS_SYS_H -#define _ETS_SYS_H - -#ifndef DOXYGEN - -#include "c_types.h" -#include "eagle_soc.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef uint32_t ETSSignal; -typedef uint32_t ETSParam; - -typedef struct ETSEventTag ETSEvent; - -struct ETSEventTag { - ETSSignal sig; - ETSParam par; -}; - -typedef void (*ETSTask)(ETSEvent *e); - -/* timer related */ -typedef uint32_t ETSHandle; -typedef void ETSTimerFunc(void *timer_arg); - -typedef struct _ETSTIMER_ { - struct _ETSTIMER_ *timer_next; - uint32_t timer_expire; - uint32_t timer_period; - ETSTimerFunc *timer_func; - void *timer_arg; -} ETSTimer; - -/* interrupt related */ -#define ETS_SDIO_INUM 1 -#define ETS_SPI_INUM 2 -#define ETS_GPIO_INUM 4 -#define ETS_UART_INUM 5 -#define ETS_UART1_INUM 5 -#define ETS_FRC_TIMER1_INUM 9 /* use edge*/ - -typedef void (* ets_isr_t)(void *); - -void ets_intr_lock(void); -void ets_intr_unlock(void); -void ets_isr_attach(int i, ets_isr_t func, void *arg); - -void NmiTimSetFunc(void (*func)(void)); - -#define ETS_INTR_LOCK() \ - ets_intr_lock() - -#define ETS_INTR_UNLOCK() \ - ets_intr_unlock() - -#define ETS_FRC_TIMER1_INTR_ATTACH(func, arg) \ - ets_isr_attach(ETS_FRC_TIMER1_INUM, (func), (void *)(arg)) - -#define ETS_FRC_TIMER1_NMI_INTR_ATTACH(func) \ - NmiTimSetFunc(func) - -#define ETS_SDIO_INTR_ATTACH(func, arg)\ - ets_isr_attach(ETS_SDIO_INUM, (func), (void *)(arg)) - -#define ETS_GPIO_INTR_ATTACH(func, arg) \ - ets_isr_attach(ETS_GPIO_INUM, (func), (void *)(arg)) - -#define ETS_UART_INTR_ATTACH(func, arg) \ - ets_isr_attach(ETS_UART_INUM, (func), (void *)(arg)) - -#define ETS_SPI_INTR_ATTACH(func, arg) \ - ets_isr_attach(ETS_SPI_INUM, (func), (void *)(arg)) - -#define ETS_INTR_ENABLE(inum) \ - ets_isr_unmask((1< - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef GPIO_H -#define GPIO_H - -#ifndef DOXYGEN - -#ifdef __cplusplus -extern "C" { -#endif - -#define GPIO_PIN_ADDR(i) (GPIO_PIN0_ADDRESS + i*4) - -#define GPIO_ID_IS_PIN_REGISTER(reg_id) \ - ((reg_id >= GPIO_ID_PIN0) && (reg_id <= GPIO_ID_PIN(GPIO_PIN_COUNT-1))) - -#define GPIO_REGID_TO_PINIDX(reg_id) ((reg_id) - GPIO_ID_PIN0) - -typedef enum { - GPIO_PIN_INTR_DISABLE = 0, - GPIO_PIN_INTR_POSEDGE = 1, - GPIO_PIN_INTR_NEGEDGE = 2, - GPIO_PIN_INTR_ANYEDGE = 3, - GPIO_PIN_INTR_LOLEVEL = 4, - GPIO_PIN_INTR_HILEVEL = 5 -} GPIO_INT_TYPE; - -#define GPIO_OUTPUT_SET(gpio_no, bit_value) \ - gpio_output_set((bit_value)<>gpio_no)&BIT0) - -/* GPIO interrupt handler, registered through gpio_intr_handler_register */ -typedef void (* gpio_intr_handler_fn_t)(uint32 intr_mask, void *arg); - - -/* - * Initialize GPIO. This includes reading the GPIO Configuration DataSet - * to initialize "output enables" and pin configurations for each gpio pin. - * Must be called once during startup. - */ -// conflicts with RIOT's gpio.h // void gpio_init(void); - -/* - * Change GPIO pin output by setting, clearing, or disabling pins. - * In general, it is expected that a bit will be set in at most one - * of these masks. If a bit is clear in all masks, the output state - * remains unchanged. - * - * There is no particular ordering guaranteed; so if the order of - * writes is significant, calling code should divide a single call - * into multiple calls. - */ -void gpio_output_set(uint32 set_mask, - uint32 clear_mask, - uint32 enable_mask, - uint32 disable_mask); - -/* - * Sample the value of GPIO input pins and returns a bitmask. - */ -uint32 gpio_input_get(void); - -/* - * Set the specified GPIO register to the specified value. - * This is a very general and powerful interface that is not - * expected to be used during normal operation. It is intended - * mainly for debug, or for unusual requirements. - */ -void gpio_register_set(uint32 reg_id, uint32 value); - -/* Get the current value of the specified GPIO register. */ -uint32 gpio_register_get(uint32 reg_id); - -/* - * Register an application-specific interrupt handler for GPIO pin - * interrupts. Once the interrupt handler is called, it will not - * be called again until after a call to gpio_intr_ack. Any GPIO - * interrupts that occur during the interim are masked. - * - * The application-specific handler is called with a mask of - * pending GPIO interrupts. After processing pin interrupts, the - * application-specific handler may wish to use gpio_intr_pending - * to check for any additional pending interrupts before it returns. - */ -void gpio_intr_handler_register(gpio_intr_handler_fn_t fn, void *arg); - -/* Determine which GPIO interrupts are pending. */ -uint32 gpio_intr_pending(void); - -/* - * Acknowledge GPIO interrupts. - * Intended to be called from the gpio_intr_handler_fn. - */ -void gpio_intr_ack(uint32 ack_mask); - -void gpio_pin_wakeup_enable(uint32 i, GPIO_INT_TYPE intr_state); - -void gpio_pin_wakeup_disable(void); - -void gpio_pin_intr_state_set(uint32 i, GPIO_INT_TYPE intr_state); - -#ifdef __cplusplus -} -#endif - -#endif // DOXYGEN -#endif /* GPIO_H */ diff --git a/cpu/esp8266/vendor/espressif/lwipopts.h b/cpu/esp8266/vendor/espressif/lwipopts.h deleted file mode 100644 index c59152d69e08..000000000000 --- a/cpu/esp8266/vendor/espressif/lwipopts.h +++ /dev/null @@ -1,2067 +0,0 @@ -/** - * @file - * - * lwIP Options Configuration - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels - * - */ -#ifndef __LWIPOPTS_H__ -#define __LWIPOPTS_H__ - -#define ESP_SYSTEM_APP 1 -/* - ----------------------------------------------- - ---------- Platform specific locking ---------- - ----------------------------------------------- -*/ - -/** - * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain - * critical regions during buffer allocation, deallocation and memory - * allocation and deallocation. - */ -#ifndef SYS_LIGHTWEIGHT_PROT -#define SYS_LIGHTWEIGHT_PROT 0 -#endif - -/** - * NO_SYS==1: Provides VERY minimal functionality. Otherwise, - * use lwIP facilities. - */ -#ifndef NO_SYS -#define NO_SYS 1 -#endif - -/** - * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1 - * Mainly for compatibility to old versions. - */ -#ifndef NO_SYS_NO_TIMERS -#define NO_SYS_NO_TIMERS 0 -#endif - -/** - * MEMCPY: override this if you have a faster implementation at hand than the - * one included in your C library - */ -#ifndef MEMCPY -#define MEMCPY(dst,src,len) os_memcpy(dst,src,len) -#endif - -/** - * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a - * call to memcpy() if the length is known at compile time and is small. - */ -#ifndef SMEMCPY -#define SMEMCPY(dst,src,len) os_memcpy(dst,src,len) -#endif - -/* - ------------------------------------ - ---------- Memory options ---------- - ------------------------------------ -*/ -/** - * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library - * instead of the lwip internal allocator. Can save code size if you - * already use it. - */ -#ifndef MEM_LIBC_MALLOC -#define MEM_LIBC_MALLOC 1 -#endif - -/** -* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. -* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution -* speed and usage from interrupts! -*/ -#ifndef MEMP_MEM_MALLOC -#define MEMP_MEM_MALLOC 1 -#endif - -/** - * MEM_ALIGNMENT: should be set to the alignment of the CPU - * 4 byte alignment -> #define MEM_ALIGNMENT 4 - * 2 byte alignment -> #define MEM_ALIGNMENT 2 - */ -#ifndef MEM_ALIGNMENT -#define MEM_ALIGNMENT 4 -#endif - -/** - * MEM_SIZE: the size of the heap memory. If the application will send - * a lot of data that needs to be copied, this should be set high. - */ -#ifndef MEM_SIZE -#define MEM_SIZE 16000 -#endif - -/** - * MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array. - * This can be used to individually change the location of each pool. - * Default is one big array for all pools - */ -#ifndef MEMP_SEPARATE_POOLS -#define MEMP_SEPARATE_POOLS 1 -#endif - -/** - * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable - * amount of bytes before and after each memp element in every pool and fills - * it with a prominent default value. - * MEMP_OVERFLOW_CHECK == 0 no checking - * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed - * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time - * memp_malloc() or memp_free() is called (useful but slow!) - */ -#ifndef MEMP_OVERFLOW_CHECK -#define MEMP_OVERFLOW_CHECK 0 -#endif - -/** - * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make - * sure that there are no cycles in the linked lists. - */ -#ifndef MEMP_SANITY_CHECK -#define MEMP_SANITY_CHECK 1 -#endif - -/** - * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set - * of memory pools of various sizes. When mem_malloc is called, an element of - * the smallest pool that can provide the length needed is returned. - * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. - */ -#ifndef MEM_USE_POOLS -#define MEM_USE_POOLS 0 -#endif - -/** - * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next - * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more - * reliable. */ -#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL -#define MEM_USE_POOLS_TRY_BIGGER_POOL 0 -#endif - -/** - * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h - * that defines additional pools beyond the "standard" ones required - * by lwIP. If you set this to 1, you must have lwippools.h in your - * inlude path somewhere. - */ -#ifndef MEMP_USE_CUSTOM_POOLS -#define MEMP_USE_CUSTOM_POOLS 0 -#endif - -/** - * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from - * interrupt context (or another context that doesn't allow waiting for a - * semaphore). - * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, - * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs - * with each loop so that mem_free can run. - * - * ATTENTION: As you can see from the above description, this leads to dis-/ - * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc - * can need longer. - * - * If you don't want that, at least for NO_SYS=0, you can still use the following - * functions to enqueue a deallocation call which then runs in the tcpip_thread - * context: - * - pbuf_free_callback(p); - * - mem_free_callback(m); - */ -#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT -#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 -#endif - -/* - ------------------------------------------------ - ---------- Internal Memory Pool Sizes ---------- - ------------------------------------------------ -*/ -/** - * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). - * If the application sends a lot of data out of ROM (or other static memory), - * this should be set high. - */ -#ifndef MEMP_NUM_PBUF -#define MEMP_NUM_PBUF 10 -#endif - -/** - * MEMP_NUM_RAW_PCB: Number of raw connection PCBs - * (requires the LWIP_RAW option) - */ -#ifndef MEMP_NUM_RAW_PCB -#define MEMP_NUM_RAW_PCB 4 -#endif - -/** - * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One - * per active UDP "connection". - * (requires the LWIP_UDP option) - */ -#ifndef MEMP_NUM_UDP_PCB -#define MEMP_NUM_UDP_PCB 4 -#endif - -/** - * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. - * (requires the LWIP_TCP option) - */ -#ifndef MEMP_NUM_TCP_PCB -#define MEMP_NUM_TCP_PCB (*(volatile uint32*)0x600011FC) -#endif - -/** - * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. - * (requires the LWIP_TCP option) - */ -#ifndef MEMP_NUM_TCP_PCB_LISTEN -#define MEMP_NUM_TCP_PCB_LISTEN 2 -#endif - -/** - * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. - * (requires the LWIP_TCP option) - */ -#ifndef MEMP_NUM_TCP_SEG -#define MEMP_NUM_TCP_SEG 16 -#endif - -/** - * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for - * reassembly (whole packets, not fragments!) - */ -#ifndef MEMP_NUM_REASSDATA -#define MEMP_NUM_REASSDATA 0 -#endif - -/** - * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent - * (fragments, not whole packets!). - * This is only used with IP_FRAG_USES_STATIC_BUF==0 and - * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs - * where the packet is not yet sent when netif->output returns. - */ -#ifndef MEMP_NUM_FRAG_PBUF -#define MEMP_NUM_FRAG_PBUF 0 -#endif - -/** - * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing - * packets (pbufs) that are waiting for an ARP request (to resolve - * their destination address) to finish. - * (requires the ARP_QUEUEING option) - */ -#ifndef MEMP_NUM_ARP_QUEUE -#define MEMP_NUM_ARP_QUEUE 10 -#endif - -/** - * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces - * can be members et the same time (one per netif - allsystems group -, plus one - * per netif membership). - * (requires the LWIP_IGMP option) - */ -#ifndef MEMP_NUM_IGMP_GROUP -#define MEMP_NUM_IGMP_GROUP 8 -#endif - -/** - * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. - * (requires NO_SYS==0) - */ -#ifndef MEMP_NUM_SYS_TIMEOUT -#define MEMP_NUM_SYS_TIMEOUT 8 -#endif - -/** - * MEMP_NUM_NETBUF: the number of struct netbufs. - * (only needed if you use the sequential API, like api_lib.c) - */ -#ifndef MEMP_NUM_NETBUF -#define MEMP_NUM_NETBUF 0 -#endif - -/** - * MEMP_NUM_NETCONN: the number of struct netconns. - * (only needed if you use the sequential API, like api_lib.c) - */ -#ifndef MEMP_NUM_NETCONN -#define MEMP_NUM_NETCONN 0 -#endif - -/** - * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used - * for callback/timeout API communication. - * (only needed if you use tcpip.c) - */ -#ifndef MEMP_NUM_TCPIP_MSG_API -#define MEMP_NUM_TCPIP_MSG_API 4 -#endif - -/** - * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used - * for incoming packets. - * (only needed if you use tcpip.c) - */ -#ifndef MEMP_NUM_TCPIP_MSG_INPKT -#define MEMP_NUM_TCPIP_MSG_INPKT 4 -#endif - -/** - * MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree. - */ -#ifndef MEMP_NUM_SNMP_NODE -#define MEMP_NUM_SNMP_NODE 0 -#endif - -/** - * MEMP_NUM_SNMP_ROOTNODE: the number of branches in the SNMP tree. - * Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least! - */ -#ifndef MEMP_NUM_SNMP_ROOTNODE -#define MEMP_NUM_SNMP_ROOTNODE 0 -#endif - -/** - * MEMP_NUM_SNMP_VARBIND: the number of concurrent requests (does not have to - * be changed normally) - 2 of these are used per request (1 for input, - * 1 for output) - */ -#ifndef MEMP_NUM_SNMP_VARBIND -#define MEMP_NUM_SNMP_VARBIND 0 -#endif - -/** - * MEMP_NUM_SNMP_VALUE: the number of OID or values concurrently used - * (does not have to be changed normally) - 3 of these are used per request - * (1 for the value read and 2 for OIDs - input and output) - */ -#ifndef MEMP_NUM_SNMP_VALUE -#define MEMP_NUM_SNMP_VALUE 0 -#endif - -/** - * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls - * (before freeing the corresponding memory using lwip_freeaddrinfo()). - */ -#ifndef MEMP_NUM_NETDB -#define MEMP_NUM_NETDB 0 -#endif - -/** - * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list - * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. - */ -#ifndef MEMP_NUM_LOCALHOSTLIST -#define MEMP_NUM_LOCALHOSTLIST 0 -#endif - -/** - * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE - * interfaces (only used with PPPOE_SUPPORT==1) - */ -#ifndef MEMP_NUM_PPPOE_INTERFACES -#define MEMP_NUM_PPPOE_INTERFACES 0 -#endif - -/** - * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. - */ -#ifndef PBUF_POOL_SIZE -#define PBUF_POOL_SIZE 10 -#endif - -/* - --------------------------------- - ---------- ARP options ---------- - --------------------------------- -*/ -/** - * LWIP_ARP==1: Enable ARP functionality. - */ -#ifndef LWIP_ARP -#define LWIP_ARP 1 -#endif - -/** - * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. - */ -#ifndef ARP_TABLE_SIZE -#define ARP_TABLE_SIZE 10 -#endif - -/** - * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address - * resolution. By default, only the most recent packet is queued per IP address. - * This is sufficient for most protocols and mainly reduces TCP connection - * startup time. Set this to 1 if you know your application sends more than one - * packet in a row to an IP address that is not in the ARP cache. - */ -#ifndef ARP_QUEUEING -#define ARP_QUEUEING 1 -#endif - -/** - * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be - * updated with the source MAC and IP addresses supplied in the packet. - * You may want to disable this if you do not trust LAN peers to have the - * correct addresses, or as a limited approach to attempt to handle - * spoofing. If disabled, lwIP will need to make a new ARP request if - * the peer is not already in the ARP table, adding a little latency. - * The peer *is* in the ARP table if it requested our address before. - * Also notice that this slows down input processing of every IP packet! - */ -#ifndef ETHARP_TRUST_IP_MAC -#define ETHARP_TRUST_IP_MAC 1 -#endif - -/** - * ETHARP_SUPPORT_VLAN==1: support receiving ethernet packets with VLAN header. - * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. - * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. - * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. - */ -#ifndef ETHARP_SUPPORT_VLAN -#define ETHARP_SUPPORT_VLAN 0 -#endif - -/** LWIP_ETHERNET==1: enable ethernet support for PPPoE even though ARP - * might be disabled - */ -#ifndef LWIP_ETHERNET -#define LWIP_ETHERNET (LWIP_ARP || PPPOE_SUPPORT) -#endif - -/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure - * alignment of payload after that header. Since the header is 14 bytes long, - * without this padding e.g. addresses in the IP header will not be aligned - * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. - */ -#ifndef ETH_PAD_SIZE -#define ETH_PAD_SIZE 0 -#endif - -/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table - * entries (using etharp_add_static_entry/etharp_remove_static_entry). - */ -#ifndef ETHARP_SUPPORT_STATIC_ENTRIES -#define ETHARP_SUPPORT_STATIC_ENTRIES 0 -#endif - - -/* - -------------------------------- - ---------- IP options ---------- - -------------------------------- -*/ -/** - * IP_FORWARD==1: Enables the ability to forward IP packets across network - * interfaces. If you are going to run lwIP on a device with only one network - * interface, define this to 0. - */ -#ifndef IP_FORWARD -#define IP_FORWARD 0 -#endif - -/** - * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. - * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. - * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). - */ -#ifndef IP_OPTIONS_ALLOWED -#define IP_OPTIONS_ALLOWED 1 -#endif - -/** - * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that - * this option does not affect outgoing packet sizes, which can be controlled - * via IP_FRAG. - */ -#ifndef IP_REASSEMBLY -#define IP_REASSEMBLY 0 -#endif - -/** - * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note - * that this option does not affect incoming packet sizes, which can be - * controlled via IP_REASSEMBLY. - */ -#ifndef IP_FRAG -#define IP_FRAG 0 -#endif - -/** - * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) - * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived - * in this time, the whole packet is discarded. - */ -#ifndef IP_REASS_MAXAGE -#define IP_REASS_MAXAGE 3 -#endif - -/** - * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. - * Since the received pbufs are enqueued, be sure to configure - * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive - * packets even if the maximum amount of fragments is enqueued for reassembly! - */ -#ifndef IP_REASS_MAX_PBUFS -#define IP_REASS_MAX_PBUFS 10 -#endif - -/** - * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP - * fragmentation. Otherwise pbufs are allocated and reference the original - * packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1, - * new PBUF_RAM pbufs are used for fragments). - * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs! - */ -#ifndef IP_FRAG_USES_STATIC_BUF -#define IP_FRAG_USES_STATIC_BUF 1 -#endif - -/** - * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer - * (requires IP_FRAG_USES_STATIC_BUF==1) - */ -#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU) -#define IP_FRAG_MAX_MTU 1500 -#endif - -/** - * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. - */ -#ifndef IP_DEFAULT_TTL -#define IP_DEFAULT_TTL 128 -#endif - -/** - * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast - * filter per pcb on udp and raw send operations. To enable broadcast filter - * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. - */ -#ifndef IP_SOF_BROADCAST -#define IP_SOF_BROADCAST 0 -#endif - -/** - * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast - * filter on recv operations. - */ -#ifndef IP_SOF_BROADCAST_RECV -#define IP_SOF_BROADCAST_RECV 0 -#endif - -/* - ---------------------------------- - ---------- ICMP options ---------- - ---------------------------------- -*/ -/** - * LWIP_ICMP==1: Enable ICMP module inside the IP stack. - * Be careful, disable that make your product non-compliant to RFC1122 - */ -#ifndef LWIP_ICMP -#define LWIP_ICMP 1 -#endif - -/** - * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. - */ -#ifndef ICMP_TTL -#define ICMP_TTL (IP_DEFAULT_TTL) -#endif - -/** - * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) - */ -#ifndef LWIP_BROADCAST_PING -#define LWIP_BROADCAST_PING 0 -#endif - -/** - * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) - */ -#ifndef LWIP_MULTICAST_PING -#define LWIP_MULTICAST_PING 0 -#endif - -/* - --------------------------------- - ---------- RAW options ---------- - --------------------------------- -*/ -/** - * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. - */ -#ifndef LWIP_RAW -#define LWIP_RAW 1 -#endif - -/** - * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. - */ -#ifndef RAW_TTL -#define RAW_TTL (IP_DEFAULT_TTL) -#endif - -/* - ---------------------------------- - ---------- DHCP options ---------- - ---------------------------------- -*/ -/** - * LWIP_DHCP==1: Enable DHCP module. - */ -#ifndef LWIP_DHCP -#define LWIP_DHCP 1 -#endif - -/** - * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. - */ -#ifndef DHCP_DOES_ARP_CHECK -#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP)) -#endif - -/** - * DHCP_MAXRTX: Maximum number of retries of current request. - */ -#ifndef DHCP_MAXRTX -#define DHCP_MAXRTX (*(volatile uint32*)0x600011E0) -#endif - -/* - ------------------------------------ - ---------- AUTOIP options ---------- - ------------------------------------ -*/ -/** - * LWIP_AUTOIP==1: Enable AUTOIP module. - */ -#ifndef LWIP_AUTOIP -#define LWIP_AUTOIP 0 -#endif - -/** - * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on - * the same interface at the same time. - */ -#ifndef LWIP_DHCP_AUTOIP_COOP -#define LWIP_DHCP_AUTOIP_COOP 0 -#endif - -/** - * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes - * that should be sent before falling back on AUTOIP. This can be set - * as low as 1 to get an AutoIP address very quickly, but you should - * be prepared to handle a changing IP address when DHCP overrides - * AutoIP. - */ -#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES -#define LWIP_DHCP_AUTOIP_COOP_TRIES 9 -#endif - -/* - ---------------------------------- - ---------- SNMP options ---------- - ---------------------------------- -*/ -/** - * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP - * transport. - */ -#ifndef LWIP_SNMP -#define LWIP_SNMP 0 -#endif - -/** - * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will - * allow. At least one request buffer is required. - */ -#ifndef SNMP_CONCURRENT_REQUESTS -#define SNMP_CONCURRENT_REQUESTS 0 -#endif - -/** - * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap - * destination is required - */ -#ifndef SNMP_TRAP_DESTINATIONS -#define SNMP_TRAP_DESTINATIONS 0 -#endif - -/** - * SNMP_PRIVATE_MIB: - */ -#ifndef SNMP_PRIVATE_MIB -#define SNMP_PRIVATE_MIB 0 -#endif - -/** - * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not - * a safe action and disabled when SNMP_SAFE_REQUESTS = 1). - * Unsafe requests are disabled by default! - */ -#ifndef SNMP_SAFE_REQUESTS -#define SNMP_SAFE_REQUESTS 0 -#endif - -/** - * The maximum length of strings used. This affects the size of - * MEMP_SNMP_VALUE elements. - */ -#ifndef SNMP_MAX_OCTET_STRING_LEN -#define SNMP_MAX_OCTET_STRING_LEN 127 -#endif - -/** - * The maximum depth of the SNMP tree. - * With private MIBs enabled, this depends on your MIB! - * This affects the size of MEMP_SNMP_VALUE elements. - */ -#ifndef SNMP_MAX_TREE_DEPTH -#define SNMP_MAX_TREE_DEPTH 15 -#endif - -/** - * The size of the MEMP_SNMP_VALUE elements, normally calculated from - * SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH. - */ -#ifndef SNMP_MAX_VALUE_SIZE -#define SNMP_MAX_VALUE_SIZE LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH)) -#endif - -/* - ---------------------------------- - ---------- IGMP options ---------- - ---------------------------------- -*/ -/** - * LWIP_IGMP==1: Turn on IGMP module. - */ -#ifndef LWIP_IGMP -#define LWIP_IGMP 1 -#endif -/* - ---------------------------------- - ---------- MDNS options ---------- - ---------------------------------- -*/ -/** - * LWIP_MDNS==1: Turn on MDNS module. - */ -#ifndef LWIP_MDNS -#define LWIP_MDNS 1 -#endif -/* - ---------------------------------- - ---------- DNS options ----------- - ---------------------------------- -*/ -/** - * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS - * transport. - */ -#ifndef LWIP_DNS -#define LWIP_DNS 1 -#endif - -/** DNS maximum number of entries to maintain locally. */ -#ifndef DNS_TABLE_SIZE -#define DNS_TABLE_SIZE 4 -#endif - -/** DNS maximum host name length supported in the name table. */ -#ifndef DNS_MAX_NAME_LENGTH -#define DNS_MAX_NAME_LENGTH 256 -#endif - -/** The maximum of DNS servers */ -#ifndef DNS_MAX_SERVERS -#define DNS_MAX_SERVERS 2 -#endif - -/** DNS do a name checking between the query and the response. */ -#ifndef DNS_DOES_NAME_CHECK -#define DNS_DOES_NAME_CHECK 1 -#endif - -/** DNS message max. size. Default value is RFC compliant. */ -#ifndef DNS_MSG_SIZE -#define DNS_MSG_SIZE 512 -#endif - -/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, - * you have to define - * #define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}} - * (an array of structs name/address, where address is an u32_t in network - * byte order). - * - * Instead, you can also use an external function: - * #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name) - * that returns the IP address or INADDR_NONE if not found. - */ -#ifndef DNS_LOCAL_HOSTLIST -#define DNS_LOCAL_HOSTLIST 0 -#endif /* DNS_LOCAL_HOSTLIST */ - -/** If this is turned on, the local host-list can be dynamically changed - * at runtime. */ -#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC -#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 -#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - -/* - --------------------------------- - ---------- UDP options ---------- - --------------------------------- -*/ -/** - * LWIP_UDP==1: Turn on UDP. - */ -#ifndef LWIP_UDP -#define LWIP_UDP 1 -#endif - -/** - * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) - */ -#ifndef LWIP_UDPLITE -#define LWIP_UDPLITE 0 -#endif - -/** - * UDP_TTL: Default Time-To-Live value. - */ -#ifndef UDP_TTL -#define UDP_TTL (IP_DEFAULT_TTL) -#endif - -/** - * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. - */ -#ifndef LWIP_NETBUF_RECVINFO -#define LWIP_NETBUF_RECVINFO 0 -#endif - -/* - --------------------------------- - ---------- TCP options ---------- - --------------------------------- -*/ -/** - * LWIP_TCP==1: Turn on TCP. - */ -#ifndef LWIP_TCP -#define LWIP_TCP 1 -#endif - -/** - * TCP_TTL: Default Time-To-Live value. - */ -#ifndef TCP_TTL -#define TCP_TTL (IP_DEFAULT_TTL) -#endif - -/** - * TCP_MAXRTX: Maximum number of retransmissions of data segments. - */ -#ifndef TCP_MAXRTX -#define TCP_MAXRTX (*(volatile uint32*)0x600011E8) -#endif - -/** - * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. - */ -#ifndef TCP_SYNMAXRTX -#define TCP_SYNMAXRTX (*(volatile uint32*)0x600011E4) -#endif - -/** - * TCP_MAXRTO: Maximum retransmission timeout of data segments. - */ -#ifndef TCP_MAXRTO -#define TCP_MAXRTO 10 -#endif - -/** - * TCP_MINRTO: Minimum retransmission timeout of data segments. - */ -#ifndef TCP_MINRTO -#define TCP_MINRTO 2 -#endif - -/** - * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. - * Define to 0 if your device is low on memory. - */ -#ifndef TCP_QUEUE_OOSEQ -#define TCP_QUEUE_OOSEQ 1 -#endif - -#if 1 -/** - * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, - * you might want to increase this.) - * For the receive side, this MSS is advertised to the remote side - * when opening a connection. For the transmit size, this MSS sets - * an upper limit on the MSS advertised by the remote host. - */ -#ifndef TCP_MSS -#define TCP_MSS 1460 -#endif -#endif - -/** - * TCP_WND: The size of a TCP window. This must be at least - * (2 * TCP_MSS) for things to work well - */ -#ifndef TCP_WND -#define TCP_WND (*(volatile uint32*)0x600011F0) -#endif - -/** - * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really - * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which - * reflects the available reassembly buffer size at the remote host) and the - * largest size permitted by the IP layer" (RFC 1122) - * Setting this to 1 enables code that checks TCP_MSS against the MTU of the - * netif used for a connection and limits the MSS if it would be too big otherwise. - */ -#ifndef TCP_CALCULATE_EFF_SEND_MSS -#define TCP_CALCULATE_EFF_SEND_MSS 1 -#endif - - -/** - * TCP_SND_BUF: TCP sender buffer space (bytes). - */ -#ifndef TCP_SND_BUF -#define TCP_SND_BUF 2 * TCP_MSS -#endif - -/** - * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least - * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. - */ -#ifndef TCP_SND_QUEUELEN -#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) -#endif - -/** - * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than - * TCP_SND_BUF. It is the amount of space which must be available in the - * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). - */ -#ifndef TCP_SNDLOWAT -#define TCP_SNDLOWAT ((TCP_SND_BUF)/2) -#endif - -/** - * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater - * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below - * this number, select returns writable (combined with TCP_SNDLOWAT). - */ -#ifndef TCP_SNDQUEUELOWAT -#define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) -#endif - -/** - * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. - */ -#ifndef TCP_LISTEN_BACKLOG -#define TCP_LISTEN_BACKLOG 0 -#endif - -/** - * The maximum allowed backlog for TCP listen netconns. - * This backlog is used unless another is explicitly specified. - * 0xff is the maximum (u8_t). - */ -#ifndef TCP_DEFAULT_LISTEN_BACKLOG -#define TCP_DEFAULT_LISTEN_BACKLOG 0xff -#endif - -/** - * TCP_OVERSIZE: The maximum number of bytes that tcp_write may - * allocate ahead of time in an attempt to create shorter pbuf chains - * for transmission. The meaningful range is 0 to TCP_MSS. Some - * suggested values are: - * - * 0: Disable oversized allocation. Each tcp_write() allocates a new - pbuf (old behaviour). - * 1: Allocate size-aligned pbufs with minimal excess. Use this if your - * scatter-gather DMA requires aligned fragments. - * 128: Limit the pbuf/memory overhead to 20%. - * TCP_MSS: Try to create unfragmented TCP packets. - * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. - */ -#ifndef TCP_OVERSIZE -#define TCP_OVERSIZE TCP_MSS -#endif - -/** - * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. - */ -#ifndef LWIP_TCP_TIMESTAMPS -#define LWIP_TCP_TIMESTAMPS 0 -#endif - -/** - * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an - * explicit window update - */ -#ifndef TCP_WND_UPDATE_THRESHOLD -#define TCP_WND_UPDATE_THRESHOLD (TCP_WND / 4) -#endif - -/** - * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. - * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all - * events (accept, sent, etc) that happen in the system. - * LWIP_CALLBACK_API==1: The PCB callback function is called directly - * for the event. - */ -#ifndef LWIP_EVENT_API -#define LWIP_EVENT_API 0 -#define LWIP_CALLBACK_API 1 -#else -#define LWIP_EVENT_API 1 -#define LWIP_CALLBACK_API 0 -#endif - - -/* - ---------------------------------- - ---------- Pbuf options ---------- - ---------------------------------- -*/ -/** - * PBUF_LINK_HLEN: the number of bytes that should be allocated for a - * link level header. The default is 14, the standard value for - * Ethernet. - */ -#ifndef PBUF_LINK_HLEN -#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) -#endif - -/** - * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is - * designed to accomodate single full size TCP frame in one pbuf, including - * TCP_MSS, IP header, and link header. - */ -#ifndef PBUF_POOL_BUFSIZE -#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) -#endif - -/* - ------------------------------------------------ - ---------- Network Interfaces options ---------- - ------------------------------------------------ -*/ -/** - * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname - * field. - */ -#ifndef LWIP_NETIF_HOSTNAME -#define LWIP_NETIF_HOSTNAME 1 -#endif - -/** - * LWIP_NETIF_API==1: Support netif api (in netifapi.c) - */ -#ifndef LWIP_NETIF_API -#define LWIP_NETIF_API 0 -#endif - -/** - * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface - * changes its up/down status (i.e., due to DHCP IP acquistion) - */ -#ifndef LWIP_NETIF_STATUS_CALLBACK -#define LWIP_NETIF_STATUS_CALLBACK 0 -#endif - -/** - * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface - * whenever the link changes (i.e., link down) - */ -#ifndef LWIP_NETIF_LINK_CALLBACK -#define LWIP_NETIF_LINK_CALLBACK 0 -#endif - -/** - * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table - * indices) in struct netif. TCP and UDP can make use of this to prevent - * scanning the ARP table for every sent packet. While this is faster for big - * ARP tables or many concurrent connections, it might be counterproductive - * if you have a tiny ARP table or if there never are concurrent connections. - */ -#ifndef LWIP_NETIF_HWADDRHINT -#define LWIP_NETIF_HWADDRHINT 0 -#endif - -/** - * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP - * address equal to the netif IP address, looping them back up the stack. - */ -#ifndef LWIP_NETIF_LOOPBACK -#define LWIP_NETIF_LOOPBACK 0 -#endif - -/** - * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback - * sending for each netif (0 = disabled) - */ -#ifndef LWIP_LOOPBACK_MAX_PBUFS -#define LWIP_LOOPBACK_MAX_PBUFS 0 -#endif - -/** - * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in - * the system, as netifs must change how they behave depending on this setting - * for the LWIP_NETIF_LOOPBACK option to work. - * Setting this is needed to avoid reentering non-reentrant functions like - * tcp_input(). - * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a - * multithreaded environment like tcpip.c. In this case, netif->input() - * is called directly. - * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. - * The packets are put on a list and netif_poll() must be called in - * the main application loop. - */ -#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING -#define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) -#endif - -/** - * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data - * to be sent into one single pbuf. This is for compatibility with DMA-enabled - * MACs that do not support scatter-gather. - * Beware that this might involve CPU-memcpy before transmitting that would not - * be needed without this flag! Use this only if you need to! - * - * @todo: TCP and IP-frag do not work with this, yet: - */ -#ifndef LWIP_NETIF_TX_SINGLE_PBUF -#define LWIP_NETIF_TX_SINGLE_PBUF 1 -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ - -/* - ------------------------------------ - ---------- LOOPIF options ---------- - ------------------------------------ -*/ -/** - * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c - */ -#ifndef LWIP_HAVE_LOOPIF -#define LWIP_HAVE_LOOPIF 0 -#endif - -/* - ------------------------------------ - ---------- SLIPIF options ---------- - ------------------------------------ -*/ -/** - * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c - */ -#ifndef LWIP_HAVE_SLIPIF -#define LWIP_HAVE_SLIPIF 0 -#endif - -/* - ------------------------------------ - ---------- Thread options ---------- - ------------------------------------ -*/ -/** - * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. - */ -#ifndef TCPIP_THREAD_NAME -#define TCPIP_THREAD_NAME "tcpip_thread" -#endif - -/** - * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. - * The stack size value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef TCPIP_THREAD_STACKSIZE -#define TCPIP_THREAD_STACKSIZE 0 -#endif - -/** - * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. - * The priority value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef TCPIP_THREAD_PRIO -#define TCPIP_THREAD_PRIO 1 -#endif - -/** - * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages - * The queue size value itself is platform-dependent, but is passed to - * sys_mbox_new() when tcpip_init is called. - */ -#ifndef TCPIP_MBOX_SIZE -#define TCPIP_MBOX_SIZE 0 -#endif - -/** - * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. - */ -#ifndef SLIPIF_THREAD_NAME -#define SLIPIF_THREAD_NAME "slipif_loop" -#endif - -/** - * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. - * The stack size value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef SLIPIF_THREAD_STACKSIZE -#define SLIPIF_THREAD_STACKSIZE 0 -#endif - -/** - * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. - * The priority value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef SLIPIF_THREAD_PRIO -#define SLIPIF_THREAD_PRIO 1 -#endif - -/** - * PPP_THREAD_NAME: The name assigned to the pppInputThread. - */ -#ifndef PPP_THREAD_NAME -#define PPP_THREAD_NAME "pppInputThread" -#endif - -/** - * PPP_THREAD_STACKSIZE: The stack size used by the pppInputThread. - * The stack size value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef PPP_THREAD_STACKSIZE -#define PPP_THREAD_STACKSIZE 0 -#endif - -/** - * PPP_THREAD_PRIO: The priority assigned to the pppInputThread. - * The priority value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef PPP_THREAD_PRIO -#define PPP_THREAD_PRIO 1 -#endif - -/** - * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. - */ -#ifndef DEFAULT_THREAD_NAME -#define DEFAULT_THREAD_NAME "lwIP" -#endif - -/** - * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. - * The stack size value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef DEFAULT_THREAD_STACKSIZE -#define DEFAULT_THREAD_STACKSIZE 0 -#endif - -/** - * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. - * The priority value itself is platform-dependent, but is passed to - * sys_thread_new() when the thread is created. - */ -#ifndef DEFAULT_THREAD_PRIO -#define DEFAULT_THREAD_PRIO 1 -#endif - -/** - * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a - * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed - * to sys_mbox_new() when the recvmbox is created. - */ -#ifndef DEFAULT_RAW_RECVMBOX_SIZE -#define DEFAULT_RAW_RECVMBOX_SIZE 0 -#endif - -/** - * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a - * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed - * to sys_mbox_new() when the recvmbox is created. - */ -#ifndef DEFAULT_UDP_RECVMBOX_SIZE -#define DEFAULT_UDP_RECVMBOX_SIZE 0 -#endif - -/** - * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a - * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed - * to sys_mbox_new() when the recvmbox is created. - */ -#ifndef DEFAULT_TCP_RECVMBOX_SIZE -#define DEFAULT_TCP_RECVMBOX_SIZE 0 -#endif - -/** - * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. - * The queue size value itself is platform-dependent, but is passed to - * sys_mbox_new() when the acceptmbox is created. - */ -#ifndef DEFAULT_ACCEPTMBOX_SIZE -#define DEFAULT_ACCEPTMBOX_SIZE 0 -#endif - -/* - ---------------------------------------------- - ---------- Sequential layer options ---------- - ---------------------------------------------- -*/ -/** - * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!) - * Don't use it if you're not an active lwIP project member - */ -#ifndef LWIP_TCPIP_CORE_LOCKING -#define LWIP_TCPIP_CORE_LOCKING 0 -#endif - -/** - * LWIP_TCPIP_CORE_LOCKING_INPUT: (EXPERIMENTAL!) - * Don't use it if you're not an active lwIP project member - */ -#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT -#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 -#endif - -/** - * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) - */ -#ifndef LWIP_NETCONN -#define LWIP_NETCONN 0 -#endif - -/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout tod create - * timers running in tcpip_thread from another thread. - */ -#ifndef LWIP_TCPIP_TIMEOUT -#define LWIP_TCPIP_TIMEOUT 1 -#endif - -/* - ------------------------------------ - ---------- Socket options ---------- - ------------------------------------ -*/ -/** - * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) - */ -#ifndef LWIP_SOCKET -#define LWIP_SOCKET 0 -#endif - -/** - * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names. - * (only used if you use sockets.c) - */ -#ifndef LWIP_COMPAT_SOCKETS -#define LWIP_COMPAT_SOCKETS 0 -#endif - -/** - * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. - * Disable this option if you use a POSIX operating system that uses the same - * names (read, write & close). (only used if you use sockets.c) - */ -#ifndef LWIP_POSIX_SOCKETS_IO_NAMES -#define LWIP_POSIX_SOCKETS_IO_NAMES 0 -#endif - -/** - * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT - * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set - * in seconds. (does not require sockets.c, and will affect tcp.c) - */ -#ifndef LWIP_TCP_KEEPALIVE -#define LWIP_TCP_KEEPALIVE 1 -#endif - -/** - * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing. - */ -#ifndef LWIP_SO_RCVTIMEO -#define LWIP_SO_RCVTIMEO 0 -#endif - -/** - * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. - */ -#ifndef LWIP_SO_RCVBUF -#define LWIP_SO_RCVBUF 0 -#endif - -/** - * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. - */ -#ifndef RECV_BUFSIZE_DEFAULT -#define RECV_BUFSIZE_DEFAULT INT_MAX -#endif - -/** - * SO_REUSE==1: Enable SO_REUSEADDR option. - */ -#ifndef SO_REUSE -#define SO_REUSE 0 -#endif - -/** - * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets - * to all local matches if SO_REUSEADDR is turned on. - * WARNING: Adds a memcpy for every packet if passing to more than one pcb! - */ -#ifndef SO_REUSE_RXTOALL -#define SO_REUSE_RXTOALL 0 -#endif - -/* - ---------------------------------------- - ---------- Statistics options ---------- - ---------------------------------------- -*/ -/** - * LWIP_STATS==1: Enable statistics collection in lwip_stats. - */ -#ifndef LWIP_STATS -#define LWIP_STATS 0 -#endif - -#if LWIP_STATS - -/** - * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. - */ -#ifndef LWIP_STATS_DISPLAY -#define LWIP_STATS_DISPLAY 0 -#endif - -/** - * LINK_STATS==1: Enable link stats. - */ -#ifndef LINK_STATS -#define LINK_STATS 1 -#endif - -/** - * ETHARP_STATS==1: Enable etharp stats. - */ -#ifndef ETHARP_STATS -#define ETHARP_STATS (LWIP_ARP) -#endif - -/** - * IP_STATS==1: Enable IP stats. - */ -#ifndef IP_STATS -#define IP_STATS 1 -#endif - -/** - * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is - * on if using either frag or reass. - */ -#ifndef IPFRAG_STATS -#define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) -#endif - -/** - * ICMP_STATS==1: Enable ICMP stats. - */ -#ifndef ICMP_STATS -#define ICMP_STATS 1 -#endif - -/** - * IGMP_STATS==1: Enable IGMP stats. - */ -#ifndef IGMP_STATS -#define IGMP_STATS (LWIP_IGMP) -#endif - -/** - * UDP_STATS==1: Enable UDP stats. Default is on if - * UDP enabled, otherwise off. - */ -#ifndef UDP_STATS -#define UDP_STATS (LWIP_UDP) -#endif - -/** - * TCP_STATS==1: Enable TCP stats. Default is on if TCP - * enabled, otherwise off. - */ -#ifndef TCP_STATS -#define TCP_STATS (LWIP_TCP) -#endif - -/** - * MEM_STATS==1: Enable mem.c stats. - */ -#ifndef MEM_STATS -#define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) -#endif - -/** - * MEMP_STATS==1: Enable memp.c pool stats. - */ -#ifndef MEMP_STATS -#define MEMP_STATS (MEMP_MEM_MALLOC == 0) -#endif - -/** - * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). - */ -#ifndef SYS_STATS -#define SYS_STATS (NO_SYS == 0) -#endif - -#else -#define ETHARP_STATS 0 -#define LINK_STATS 0 -#define IP_STATS 0 -#define IPFRAG_STATS 0 -#define ICMP_STATS 0 -#define IGMP_STATS 0 -#define UDP_STATS 0 -#define TCP_STATS 0 -#define MEM_STATS 0 -#define MEMP_STATS 0 -#define SYS_STATS 0 -#define LWIP_STATS_DISPLAY 0 - -#endif /* LWIP_STATS */ - -/* - --------------------------------- - ---------- PPP options ---------- - --------------------------------- -*/ -/** - * PPP_SUPPORT==1: Enable PPP. - */ -#ifndef PPP_SUPPORT -#define PPP_SUPPORT 0 -#endif - -/** - * PPPOE_SUPPORT==1: Enable PPP Over Ethernet - */ -#ifndef PPPOE_SUPPORT -#define PPPOE_SUPPORT 0 -#endif - -/** - * PPPOS_SUPPORT==1: Enable PPP Over Serial - */ -#ifndef PPPOS_SUPPORT -#define PPPOS_SUPPORT PPP_SUPPORT -#endif - -#if PPP_SUPPORT - -/** - * NUM_PPP: Max PPP sessions. - */ -#ifndef NUM_PPP -#define NUM_PPP 1 -#endif - -/** - * PAP_SUPPORT==1: Support PAP. - */ -#ifndef PAP_SUPPORT -#define PAP_SUPPORT 0 -#endif - -/** - * CHAP_SUPPORT==1: Support CHAP. - */ -#ifndef CHAP_SUPPORT -#define CHAP_SUPPORT 0 -#endif - -/** - * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET! - */ -#ifndef MSCHAP_SUPPORT -#define MSCHAP_SUPPORT 0 -#endif - -/** - * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET! - */ -#ifndef CBCP_SUPPORT -#define CBCP_SUPPORT 0 -#endif - -/** - * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET! - */ -#ifndef CCP_SUPPORT -#define CCP_SUPPORT 0 -#endif - -/** - * VJ_SUPPORT==1: Support VJ header compression. - */ -#ifndef VJ_SUPPORT -#define VJ_SUPPORT 0 -#endif - -/** - * MD5_SUPPORT==1: Support MD5 (see also CHAP). - */ -#ifndef MD5_SUPPORT -#define MD5_SUPPORT 0 -#endif - -/* - * Timeouts - */ -#ifndef FSM_DEFTIMEOUT -#define FSM_DEFTIMEOUT 6 /* Timeout time in seconds */ -#endif - -#ifndef FSM_DEFMAXTERMREQS -#define FSM_DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ -#endif - -#ifndef FSM_DEFMAXCONFREQS -#define FSM_DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ -#endif - -#ifndef FSM_DEFMAXNAKLOOPS -#define FSM_DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ -#endif - -#ifndef UPAP_DEFTIMEOUT -#define UPAP_DEFTIMEOUT 6 /* Timeout (seconds) for retransmitting req */ -#endif - -#ifndef UPAP_DEFREQTIME -#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ -#endif - -#ifndef CHAP_DEFTIMEOUT -#define CHAP_DEFTIMEOUT 6 /* Timeout time in seconds */ -#endif - -#ifndef CHAP_DEFTRANSMITS -#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */ -#endif - -/* Interval in seconds between keepalive echo requests, 0 to disable. */ -#ifndef LCP_ECHOINTERVAL -#define LCP_ECHOINTERVAL 0 -#endif - -/* Number of unanswered echo requests before failure. */ -#ifndef LCP_MAXECHOFAILS -#define LCP_MAXECHOFAILS 3 -#endif - -/* Max Xmit idle time (in jiffies) before resend flag char. */ -#ifndef PPP_MAXIDLEFLAG -#define PPP_MAXIDLEFLAG 100 -#endif - -/* - * Packet sizes - * - * Note - lcp shouldn't be allowed to negotiate stuff outside these - * limits. See lcp.h in the pppd directory. - * (XXX - these constants should simply be shared by lcp.c instead - * of living in lcp.h) - */ -#define PPP_MTU 1500 /* Default MTU (size of Info field) */ -#ifndef PPP_MAXMTU -/* #define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN) */ -#define PPP_MAXMTU 1500 /* Largest MTU we allow */ -#endif -#define PPP_MINMTU 64 -#define PPP_MRU 1500 /* default MRU = max length of info field */ -#define PPP_MAXMRU 1500 /* Largest MRU we allow */ -#ifndef PPP_DEFMRU -#define PPP_DEFMRU 296 /* Try for this */ -#endif -#define PPP_MINMRU 128 /* No MRUs below this */ - -#ifndef MAXNAMELEN -#define MAXNAMELEN 256 /* max length of hostname or name for auth */ -#endif -#ifndef MAXSECRETLEN -#define MAXSECRETLEN 256 /* max length of password or secret */ -#endif - -#endif /* PPP_SUPPORT */ - -/* - -------------------------------------- - ---------- Checksum options ---------- - -------------------------------------- -*/ -/** - * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. - */ -#ifndef CHECKSUM_GEN_IP -#define CHECKSUM_GEN_IP 1 -#endif - -/** - * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. - */ -#ifndef CHECKSUM_GEN_UDP -#define CHECKSUM_GEN_UDP 1 -#endif - -/** - * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. - */ -#ifndef CHECKSUM_GEN_TCP -#define CHECKSUM_GEN_TCP 1 -#endif - -/** - * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. - */ -#ifndef CHECKSUM_CHECK_IP -#define CHECKSUM_CHECK_IP 1 -#endif - -/** - * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. - */ -#ifndef CHECKSUM_CHECK_UDP -#define CHECKSUM_CHECK_UDP 1 -#endif - -/** - * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. - */ -#ifndef CHECKSUM_CHECK_TCP -#define CHECKSUM_CHECK_TCP 1 -#endif - -/** - * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from - * application buffers to pbufs. - */ -#ifndef LWIP_CHECKSUM_ON_COPY -#define LWIP_CHECKSUM_ON_COPY 0 -#endif - -/* - --------------------------------------- - ---------- Debugging options ---------- - --------------------------------------- -*/ -/** - * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is - * compared against this value. If it is smaller, then debugging - * messages are written. - */ -#ifndef LWIP_DBG_MIN_LEVEL -#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL -#endif - -/** - * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable - * debug messages of certain types. - */ -#ifndef LWIP_DBG_TYPES_ON -#define LWIP_DBG_TYPES_ON LWIP_DBG_OFF -#endif - -/** - * ETHARP_DEBUG: Enable debugging in etharp.c. - */ -#ifndef ETHARP_DEBUG -#define ETHARP_DEBUG LWIP_DBG_OFF -#endif - -/** - * NETIF_DEBUG: Enable debugging in netif.c. - */ -#ifndef NETIF_DEBUG -#define NETIF_DEBUG LWIP_DBG_OFF -#endif - -/** - * PBUF_DEBUG: Enable debugging in pbuf.c. - */ -#ifndef PBUF_DEBUG -#define PBUF_DEBUG LWIP_DBG_OFF -#endif - -/** - * API_LIB_DEBUG: Enable debugging in api_lib.c. - */ -#ifndef API_LIB_DEBUG -#define API_LIB_DEBUG LWIP_DBG_OFF -#endif - -/** - * API_MSG_DEBUG: Enable debugging in api_msg.c. - */ -#ifndef API_MSG_DEBUG -#define API_MSG_DEBUG LWIP_DBG_OFF -#endif - -/** - * SOCKETS_DEBUG: Enable debugging in sockets.c. - */ -#ifndef SOCKETS_DEBUG -#define SOCKETS_DEBUG LWIP_DBG_OFF -#endif - -/** - * ICMP_DEBUG: Enable debugging in icmp.c. - */ -#ifndef ICMP_DEBUG -#define ICMP_DEBUG LWIP_DBG_OFF -#endif - -/** - * IGMP_DEBUG: Enable debugging in igmp.c. - */ -#ifndef IGMP_DEBUG -#define IGMP_DEBUG LWIP_DBG_OFF -#endif - -/** - * INET_DEBUG: Enable debugging in inet.c. - */ -#ifndef INET_DEBUG -#define INET_DEBUG LWIP_DBG_OFF -#endif - -/** - * IP_DEBUG: Enable debugging for IP. - */ -#ifndef IP_DEBUG -#define IP_DEBUG LWIP_DBG_OFF -#endif - -/** - * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. - */ -#ifndef IP_REASS_DEBUG -#define IP_REASS_DEBUG LWIP_DBG_OFF -#endif - -/** - * RAW_DEBUG: Enable debugging in raw.c. - */ -#ifndef RAW_DEBUG -#define RAW_DEBUG LWIP_DBG_OFF -#endif - -/** - * MEM_DEBUG: Enable debugging in mem.c. - */ -#ifndef MEM_DEBUG -#define MEM_DEBUG LWIP_DBG_OFF -#endif - -/** - * MEMP_DEBUG: Enable debugging in memp.c. - */ -#ifndef MEMP_DEBUG -#define MEMP_DEBUG LWIP_DBG_OFF -#endif - -/** - * SYS_DEBUG: Enable debugging in sys.c. - */ -#ifndef SYS_DEBUG -#define SYS_DEBUG LWIP_DBG_OFF -#endif - -/** - * TIMERS_DEBUG: Enable debugging in timers.c. - */ -#ifndef TIMERS_DEBUG -#define TIMERS_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_DEBUG: Enable debugging for TCP. - */ -#ifndef TCP_DEBUG -#define TCP_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. - */ -#ifndef TCP_INPUT_DEBUG -#define TCP_INPUT_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. - */ -#ifndef TCP_FR_DEBUG -#define TCP_FR_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit - * timeout. - */ -#ifndef TCP_RTO_DEBUG -#define TCP_RTO_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. - */ -#ifndef TCP_CWND_DEBUG -#define TCP_CWND_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. - */ -#ifndef TCP_WND_DEBUG -#define TCP_WND_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. - */ -#ifndef TCP_OUTPUT_DEBUG -#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. - */ -#ifndef TCP_RST_DEBUG -#define TCP_RST_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. - */ -#ifndef TCP_QLEN_DEBUG -#define TCP_QLEN_DEBUG LWIP_DBG_OFF -#endif - -/** - * UDP_DEBUG: Enable debugging in UDP. - */ -#ifndef UDP_DEBUG -#define UDP_DEBUG LWIP_DBG_OFF -#endif - -/** - * TCPIP_DEBUG: Enable debugging in tcpip.c. - */ -#ifndef TCPIP_DEBUG -#define TCPIP_DEBUG LWIP_DBG_OFF -#endif - -/** - * PPP_DEBUG: Enable debugging for PPP. - */ -#ifndef PPP_DEBUG -#define PPP_DEBUG LWIP_DBG_OFF -#endif - -/** - * SLIP_DEBUG: Enable debugging in slipif.c. - */ -#ifndef SLIP_DEBUG -#define SLIP_DEBUG LWIP_DBG_OFF -#endif - -/** - * DHCP_DEBUG: Enable debugging in dhcp.c. - */ -#ifndef DHCP_DEBUG -#define DHCP_DEBUG LWIP_DBG_OFF -#endif - -/** - * AUTOIP_DEBUG: Enable debugging in autoip.c. - */ -#ifndef AUTOIP_DEBUG -#define AUTOIP_DEBUG LWIP_DBG_OFF -#endif - -/** - * SNMP_MSG_DEBUG: Enable debugging for SNMP messages. - */ -#ifndef SNMP_MSG_DEBUG -#define SNMP_MSG_DEBUG LWIP_DBG_OFF -#endif - -/** - * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs. - */ -#ifndef SNMP_MIB_DEBUG -#define SNMP_MIB_DEBUG LWIP_DBG_OFF -#endif - -/** - * DNS_DEBUG: Enable debugging for DNS. - */ -#ifndef DNS_DEBUG -#define DNS_DEBUG LWIP_DBG_OFF -#endif - -#endif /* __LWIP_OPT_H__ */ diff --git a/cpu/esp8266/vendor/espressif/osapi.h b/cpu/esp8266/vendor/espressif/osapi.h deleted file mode 100644 index 5700e5475460..000000000000 --- a/cpu/esp8266/vendor/espressif/osapi.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2016 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef OSAPI_H -#define OSAPI_H - -#ifndef DOXYGEN - -#include -#include "os_type.h" -#include "user_config.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void ets_bzero(void *s, size_t n); -void ets_delay_us(uint16_t us); -void ets_install_putc1(void (*p)(char c)); - -#define os_bzero ets_bzero -#define os_delay_us ets_delay_us -#define os_install_putc1 ets_install_putc1 - -int ets_memcmp(const void *str1, const void *str2, unsigned int nbyte); -void *ets_memcpy(void *dest, const void *src, unsigned int nbyte); -void *ets_memmove(void *dest, const void *src, unsigned int nbyte); -void *ets_memset(void *dest, int val, unsigned int nbyte); - -int ets_strcmp(const char *s1, const char *s2); -char *ets_strcpy(char *s1, const char *s2); -int ets_strlen(const char *s); -int ets_strncmp(const char *s1, const char *s2, unsigned int n); -char *ets_strncpy(char *s1, const char *s2, unsigned int n); -char *ets_strstr(const char *s1, const char *s2); - -#define os_memcmp ets_memcmp -#define os_memcpy ets_memcpy -#define os_memmove ets_memmove -#define os_memset ets_memset -#define os_strcat strcat -#define os_strchr strchr -#define os_strcmp ets_strcmp -#define os_strcpy ets_strcpy -#define os_strlen ets_strlen -#define os_strncmp ets_strncmp -#define os_strncpy ets_strncpy -#define os_strstr ets_strstr - -void ets_timer_arm_new(os_timer_t *ptimer, uint32_t time, bool repeat_flag, bool ms_flag); -void ets_timer_disarm(os_timer_t *ptimer); -void ets_timer_setfn(os_timer_t *ptimer, os_timer_func_t *pfunction, void *parg); - -#ifdef USE_US_TIMER -#define os_timer_arm_us(a, b, c) ets_timer_arm_new(a, b, c, 0) -#endif -#define os_timer_arm(a, b, c) ets_timer_arm_new(a, b, c, 1) -#define os_timer_disarm ets_timer_disarm -#define os_timer_setfn ets_timer_setfn - -int ets_sprintf(char *str, const char *format, ...) __attribute__ ((format (printf, 2, 3))); -int os_printf_plus(const char *format, ...) __attribute__ ((format (printf, 1, 2))); - -#define os_sprintf ets_sprintf - -#ifdef USE_OPTIMIZE_PRINTF -#define os_printf(fmt, ...) do { \ - static const char flash_str[] ICACHE_RODATA_ATTR STORE_ATTR = fmt; \ - os_printf_plus(flash_str, ##__VA_ARGS__); \ - } while(0) -#else -#define os_printf os_printf_plus -#endif - -unsigned long os_random(void); -int os_get_random(unsigned char *buf, size_t len); - -#ifdef __cplusplus -} -#endif - -#endif // DOXYGEN -#endif /* OSAPI_H */ diff --git a/cpu/esp8266/vendor/espressif/spi_flash.h b/cpu/esp8266/vendor/espressif/spi_flash.h deleted file mode 100644 index 215afd07b303..000000000000 --- a/cpu/esp8266/vendor/espressif/spi_flash.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2016 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef SPI_FLASH_H -#define SPI_FLASH_H - -#ifndef DOXYGEN - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - SPI_FLASH_RESULT_OK, - SPI_FLASH_RESULT_ERR, - SPI_FLASH_RESULT_TIMEOUT -} SpiFlashOpResult; - -typedef struct{ - uint32 deviceId; - uint32 chip_size; // chip size in byte - uint32 block_size; - uint32 sector_size; - uint32 page_size; - uint32 status_mask; -} SpiFlashChip; - -#define SPI_FLASH_SEC_SIZE 4096 - -uint32 spi_flash_get_id(void); -SpiFlashOpResult spi_flash_erase_sector(uint16 sec); -SpiFlashOpResult spi_flash_write(uint32 des_addr, uint32 *src_addr, uint32 size); -SpiFlashOpResult spi_flash_read(uint32 src_addr, uint32 *des_addr, uint32 size); - -typedef SpiFlashOpResult (* user_spi_flash_read)( - SpiFlashChip *spi, - uint32 src_addr, - uint32 *des_addr, - uint32 size); - -void spi_flash_set_read_func(user_spi_flash_read read); - -bool spi_flash_erase_protect_enable(void); -bool spi_flash_erase_protect_disable(void); - -#ifdef __cplusplus -} -#endif - -#endif // DOXYGEN -#endif /* SPI_FLASH_H */ diff --git a/cpu/esp8266/vendor/espressif/user_interface.h b/cpu/esp8266/vendor/espressif/user_interface.h deleted file mode 100644 index d0cf3e53abc0..000000000000 --- a/cpu/esp8266/vendor/espressif/user_interface.h +++ /dev/null @@ -1,658 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2016 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef USER_INTERFACE_H -#define USER_INTERFACE_H - -#ifndef DOXYGEN - -#include "os_type.h" -#ifdef LWIP_OPEN_SRC -#include "lwip/ip_addr.h" -#else -#include "ip_addr.h" -#endif - -#include "queue.h" -#include "user_config.h" -#include "spi_flash.h" -#include "gpio.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef MAC2STR -#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] -#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" -#endif - -enum rst_reason { - REASON_DEFAULT_RST = 0, - REASON_WDT_RST = 1, - REASON_EXCEPTION_RST = 2, - REASON_SOFT_WDT_RST = 3, - REASON_SOFT_RESTART = 4, - REASON_DEEP_SLEEP_AWAKE = 5, - REASON_EXT_SYS_RST = 6 -}; - -struct rst_info{ - uint32 reason; - uint32 exccause; - uint32 epc1; - uint32 epc2; - uint32 epc3; - uint32 excvaddr; - uint32 depc; -}; - -struct rst_info* system_get_rst_info(void); - -#define UPGRADE_FW_BIN1 0x00 -#define UPGRADE_FW_BIN2 0x01 - -void system_restore(void); -void system_restart(void); - -bool system_deep_sleep_set_option(uint8 option); -bool system_deep_sleep(uint64 time_in_us); -bool system_deep_sleep_instant(uint64 time_in_us); - -uint8 system_upgrade_userbin_check(void); -void system_upgrade_reboot(void); -uint8 system_upgrade_flag_check(void); -void system_upgrade_flag_set(uint8 flag); - -void system_timer_reinit(void); -uint32 system_get_time(void); - -/* user task's prio must be 0/1/2 !!!*/ -enum { - USER_TASK_PRIO_0 = 0, - USER_TASK_PRIO_1, - USER_TASK_PRIO_2, - USER_TASK_PRIO_MAX -}; - -bool system_os_task(os_task_t task, uint8 prio, os_event_t *queue, uint8 qlen); -bool system_os_post(uint8 prio, os_signal_t sig, os_param_t par); - -void system_print_meminfo(void); -uint32 system_get_free_heap_size(void); - -void system_set_os_print(uint8 onoff); -uint8 system_get_os_print(void); - -uint64 system_mktime(uint32 year, uint32 mon, uint32 day, uint32 hour, uint32 min, uint32 sec); - -uint32 system_get_chip_id(void); - -typedef void (* init_done_cb_t)(void); - -void system_init_done_cb(init_done_cb_t cb); - -uint32 system_rtc_clock_cali_proc(void); -uint32 system_get_rtc_time(void); - -bool system_rtc_mem_read(uint8 src_addr, void *des_addr, uint16 load_size); -bool system_rtc_mem_write(uint8 des_addr, const void *src_addr, uint16 save_size); - -void system_uart_swap(void); -void system_uart_de_swap(void); - -uint16 system_adc_read(void); -void system_adc_read_fast(uint16 *adc_addr, uint16 adc_num, uint8 adc_clk_div); -uint16 system_get_vdd33(void); - -const char *system_get_sdk_version(void); - -#define SYS_BOOT_ENHANCE_MODE 0 -#define SYS_BOOT_NORMAL_MODE 1 - -#define SYS_BOOT_NORMAL_BIN 0 -#define SYS_BOOT_TEST_BIN 1 - -uint8 system_get_boot_version(void); -uint32 system_get_userbin_addr(void); -uint8 system_get_boot_mode(void); -bool system_restart_enhance(uint8 bin_type, uint32 bin_addr); - -#define SYS_CPU_80MHZ 80 -#define SYS_CPU_160MHZ 160 - -bool system_update_cpu_freq(uint8 freq); -uint8 system_get_cpu_freq(void); - -enum flash_size_map { - FLASH_SIZE_4M_MAP_256_256 = 0, /**< Flash size : 4Mbits. Map : 256KBytes + 256KBytes */ - FLASH_SIZE_2M, /**< Flash size : 2Mbits. Map : 256KBytes */ - FLASH_SIZE_8M_MAP_512_512, /**< Flash size : 8Mbits. Map : 512KBytes + 512KBytes */ - FLASH_SIZE_16M_MAP_512_512, /**< Flash size : 16Mbits. Map : 512KBytes + 512KBytes */ - FLASH_SIZE_32M_MAP_512_512, /**< Flash size : 32Mbits. Map : 512KBytes + 512KBytes */ - FLASH_SIZE_16M_MAP_1024_1024, /**< Flash size : 16Mbits. Map : 1024KBytes + 1024KBytes */ - FLASH_SIZE_32M_MAP_1024_1024, /**< Flash size : 32Mbits. Map : 1024KBytes + 1024KBytes */ - FLASH_SIZE_32M_MAP_2048_2048, /**< attention: don't support now ,just compatible for nodemcu; - Flash size : 32Mbits. Map : 2048KBytes + 2048KBytes */ - FLASH_SIZE_64M_MAP_1024_1024, /**< Flash size : 64Mbits. Map : 1024KBytes + 1024KBytes */ - FLASH_SIZE_128M_MAP_1024_1024 /**< Flash size : 128Mbits. Map : 1024KBytes + 1024KBytes */ -}; - -enum flash_size_map system_get_flash_size_map(void); - -void system_phy_set_max_tpw(uint8 max_tpw); -void system_phy_set_tpw_via_vdd33(uint16 vdd33); -void system_phy_set_rfoption(uint8 option); -void system_phy_set_powerup_option(uint8 option); -void system_phy_freq_trace_enable(bool enable); - -bool system_param_save_with_protect(uint16 start_sec, void *param, uint16 len); -bool system_param_load(uint16 start_sec, uint16 offset, void *param, uint16 len); - -void system_soft_wdt_stop(void); -void system_soft_wdt_restart(void); -void system_soft_wdt_feed(void); - -void system_show_malloc(void); - -#define NULL_MODE 0x00 -#define STATION_MODE 0x01 -#define SOFTAP_MODE 0x02 -#define STATIONAP_MODE 0x03 - -typedef enum _auth_mode { - AUTH_OPEN = 0, - AUTH_WEP, - AUTH_WPA_PSK, - AUTH_WPA2_PSK, - AUTH_WPA_WPA2_PSK, - AUTH_MAX -} AUTH_MODE; - -uint8 wifi_get_opmode(void); -uint8 wifi_get_opmode_default(void); -bool wifi_set_opmode(uint8 opmode); -bool wifi_set_opmode_current(uint8 opmode); -uint8 wifi_get_broadcast_if(void); -bool wifi_set_broadcast_if(uint8 interface); - -struct bss_info { - STAILQ_ENTRY(bss_info) next; - - uint8 bssid[6]; - uint8 ssid[32]; - uint8 ssid_len; - uint8 channel; - sint8 rssi; - AUTH_MODE authmode; - uint8 is_hidden; - sint16 freq_offset; - sint16 freqcal_val; - uint8 *esp_mesh_ie; - uint8 simple_pair; -}; - -typedef struct _scaninfo { - STAILQ_HEAD(, bss_info) *pbss; - struct espconn *pespconn; - uint8 totalpage; - uint8 pagenum; - uint8 page_sn; - uint8 data_cnt; -} scaninfo; - -typedef void (* scan_done_cb_t)(void *arg, STATUS status); - -struct station_config { - uint8 ssid[32]; - uint8 password[64]; - uint8 bssid_set; // Note: If bssid_set is 1, station will just connect to the router - // with both ssid[] and bssid[] matched. Please check about this. - uint8 bssid[6]; -}; - -bool wifi_station_get_config(struct station_config *config); -bool wifi_station_get_config_default(struct station_config *config); -bool wifi_station_set_config(struct station_config *config); -bool wifi_station_set_config_current(struct station_config *config); - -bool wifi_station_connect(void); -bool wifi_station_disconnect(void); - -sint8 wifi_station_get_rssi(void); - -struct scan_config { - uint8 *ssid; // Note: ssid == NULL, don't filter ssid. - uint8 *bssid; // Note: bssid == NULL, don't filter bssid. - uint8 channel; // Note: channel == 0, scan all channels, otherwise scan set channel. - uint8 show_hidden; // Note: show_hidden == 1, can get hidden ssid routers' info. -}; - -bool wifi_station_scan(struct scan_config *config, scan_done_cb_t cb); - -uint8 wifi_station_get_auto_connect(void); -bool wifi_station_set_auto_connect(uint8 set); - -bool wifi_station_set_reconnect_policy(bool set); - -enum { - STATION_IDLE = 0, - STATION_CONNECTING, - STATION_WRONG_PASSWORD, - STATION_NO_AP_FOUND, - STATION_CONNECT_FAIL, - STATION_GOT_IP -}; - -enum dhcp_status { - DHCP_STOPPED, - DHCP_STARTED -}; - -uint8 wifi_station_get_connect_status(void); - -uint8 wifi_station_get_current_ap_id(void); -bool wifi_station_ap_change(uint8 current_ap_id); -bool wifi_station_ap_number_set(uint8 ap_number); -uint8 wifi_station_get_ap_info(struct station_config config[]); - -bool wifi_station_dhcpc_start(void); -bool wifi_station_dhcpc_stop(void); -enum dhcp_status wifi_station_dhcpc_status(void); -bool wifi_station_dhcpc_set_maxtry(uint8 num); - -char* wifi_station_get_hostname(void); -bool wifi_station_set_hostname(char *name); - -int wifi_station_set_cert_key(uint8 *client_cert, int client_cert_len, - uint8 *private_key, int private_key_len, - uint8 *private_key_passwd, int private_key_passwd_len); -void wifi_station_clear_cert_key(void); -int wifi_station_set_username(uint8 *username, int len); -void wifi_station_clear_username(void); - -struct softap_config { - uint8 ssid[32]; - uint8 password[64]; - uint8 ssid_len; // Note: Recommend to set it according to your ssid - uint8 channel; // Note: support 1 ~ 13 - AUTH_MODE authmode; // Note: Don't support AUTH_WEP in softAP mode. - uint8 ssid_hidden; // Note: default 0 - uint8 max_connection; // Note: default 4, max 4 - uint16 beacon_interval; // Note: support 100 ~ 60000 ms, default 100 -}; - -bool wifi_softap_get_config(struct softap_config *config); -bool wifi_softap_get_config_default(struct softap_config *config); -bool wifi_softap_set_config(struct softap_config *config); -bool wifi_softap_set_config_current(struct softap_config *config); - -struct station_info { - STAILQ_ENTRY(station_info) next; - - uint8 bssid[6]; - struct ip_addr ip; -}; - -struct dhcps_lease { - bool enable; - struct ip_addr start_ip; - struct ip_addr end_ip; -}; - -enum dhcps_offer_option{ - OFFER_START = 0x00, - OFFER_ROUTER = 0x01, - OFFER_END -}; - -uint8 wifi_softap_get_station_num(void); -struct station_info * wifi_softap_get_station_info(void); -void wifi_softap_free_station_info(void); - -bool wifi_softap_dhcps_start(void); -bool wifi_softap_dhcps_stop(void); - -bool wifi_softap_set_dhcps_lease(struct dhcps_lease *please); -bool wifi_softap_get_dhcps_lease(struct dhcps_lease *please); -uint32 wifi_softap_get_dhcps_lease_time(void); -bool wifi_softap_set_dhcps_lease_time(uint32 minute); -bool wifi_softap_reset_dhcps_lease_time(void); - -enum dhcp_status wifi_softap_dhcps_status(void); -bool wifi_softap_set_dhcps_offer_option(uint8 level, void* optarg); - -#define STATION_IF 0x00 -#define SOFTAP_IF 0x01 - -bool wifi_get_ip_info(uint8 if_index, struct ip_info *info); -bool wifi_set_ip_info(uint8 if_index, struct ip_info *info); -bool wifi_get_macaddr(uint8 if_index, uint8 *macaddr); -bool wifi_set_macaddr(uint8 if_index, uint8 *macaddr); - -uint8 wifi_get_channel(void); -bool wifi_set_channel(uint8 channel); - -void wifi_status_led_install(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func); -void wifi_status_led_uninstall(void); - -/** Get the absolute difference between 2 u32_t values (correcting overflows) - * 'a' is expected to be 'higher' (without overflow) than 'b'. */ -#define ESP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1))) - -void wifi_promiscuous_enable(uint8 promiscuous); - -typedef void (* wifi_promiscuous_cb_t)(uint8 *buf, uint16 len); - -void wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb); - -void wifi_promiscuous_set_mac(const uint8_t *address); - -enum phy_mode { - PHY_MODE_11B = 1, - PHY_MODE_11G = 2, - PHY_MODE_11N = 3 -}; - -enum phy_mode wifi_get_phy_mode(void); -bool wifi_set_phy_mode(enum phy_mode mode); - -enum sleep_type { - NONE_SLEEP_T = 0, - LIGHT_SLEEP_T, - MODEM_SLEEP_T -}; - -bool wifi_set_sleep_type(enum sleep_type type); -enum sleep_type wifi_get_sleep_type(void); - -void wifi_fpm_open(void); -void wifi_fpm_close(void); -void wifi_fpm_do_wakeup(void); -sint8 wifi_fpm_do_sleep(uint32 sleep_time_in_us); -void wifi_fpm_set_sleep_type(enum sleep_type type); -enum sleep_type wifi_fpm_get_sleep_type(void); - -typedef void (*fpm_wakeup_cb)(void); -void wifi_fpm_set_wakeup_cb(fpm_wakeup_cb cb); - -void wifi_fpm_auto_sleep_set_in_null_mode(uint8 req); - -enum { - EVENT_STAMODE_CONNECTED = 0, - EVENT_STAMODE_DISCONNECTED, - EVENT_STAMODE_AUTHMODE_CHANGE, - EVENT_STAMODE_GOT_IP, - EVENT_STAMODE_DHCP_TIMEOUT, - EVENT_SOFTAPMODE_STACONNECTED, - EVENT_SOFTAPMODE_STADISCONNECTED, - EVENT_SOFTAPMODE_PROBEREQRECVED, - EVENT_OPMODE_CHANGED, - EVENT_MAX -}; - -enum { - REASON_UNSPECIFIED = 1, - REASON_AUTH_EXPIRE = 2, - REASON_AUTH_LEAVE = 3, - REASON_ASSOC_EXPIRE = 4, - REASON_ASSOC_TOOMANY = 5, - REASON_NOT_AUTHED = 6, - REASON_NOT_ASSOCED = 7, - REASON_ASSOC_LEAVE = 8, - REASON_ASSOC_NOT_AUTHED = 9, - REASON_DISASSOC_PWRCAP_BAD = 10, /* 11h */ - REASON_DISASSOC_SUPCHAN_BAD = 11, /* 11h */ - REASON_IE_INVALID = 13, /* 11i */ - REASON_MIC_FAILURE = 14, /* 11i */ - REASON_4WAY_HANDSHAKE_TIMEOUT = 15, /* 11i */ - REASON_GROUP_KEY_UPDATE_TIMEOUT = 16, /* 11i */ - REASON_IE_IN_4WAY_DIFFERS = 17, /* 11i */ - REASON_GROUP_CIPHER_INVALID = 18, /* 11i */ - REASON_PAIRWISE_CIPHER_INVALID = 19, /* 11i */ - REASON_AKMP_INVALID = 20, /* 11i */ - REASON_UNSUPP_RSN_IE_VERSION = 21, /* 11i */ - REASON_INVALID_RSN_IE_CAP = 22, /* 11i */ - REASON_802_1X_AUTH_FAILED = 23, /* 11i */ - REASON_CIPHER_SUITE_REJECTED = 24, /* 11i */ - - REASON_BEACON_TIMEOUT = 200, - REASON_NO_AP_FOUND = 201, - REASON_AUTH_FAIL = 202, - REASON_ASSOC_FAIL = 203, - REASON_HANDSHAKE_TIMEOUT = 204, -}; - -typedef struct { - uint8 ssid[32]; - uint8 ssid_len; - uint8 bssid[6]; - uint8 channel; -} Event_StaMode_Connected_t; - -typedef struct { - uint8 ssid[32]; - uint8 ssid_len; - uint8 bssid[6]; - uint8 reason; -} Event_StaMode_Disconnected_t; - -typedef struct { - uint8 old_mode; - uint8 new_mode; -} Event_StaMode_AuthMode_Change_t; - -typedef struct { - struct ip_addr ip; - struct ip_addr mask; - struct ip_addr gw; -} Event_StaMode_Got_IP_t; - -typedef struct { - uint8 mac[6]; - uint8 aid; -} Event_SoftAPMode_StaConnected_t; - -typedef struct { - uint8 mac[6]; - uint8 aid; -} Event_SoftAPMode_StaDisconnected_t; - -typedef struct { - int rssi; - uint8 mac[6]; -} Event_SoftAPMode_ProbeReqRecved_t; - -typedef struct { - uint8 old_opmode; - uint8 new_opmode; -} Event_OpMode_Change_t; - -typedef union { - Event_StaMode_Connected_t connected; - Event_StaMode_Disconnected_t disconnected; - Event_StaMode_AuthMode_Change_t auth_change; - Event_StaMode_Got_IP_t got_ip; - Event_SoftAPMode_StaConnected_t sta_connected; - Event_SoftAPMode_StaDisconnected_t sta_disconnected; - Event_SoftAPMode_ProbeReqRecved_t ap_probereqrecved; - Event_OpMode_Change_t opmode_changed; -} Event_Info_u; - -typedef struct _esp_event { - uint32 event; - Event_Info_u event_info; -} System_Event_t; - -typedef void (* wifi_event_handler_cb_t)(System_Event_t *event); - -void wifi_set_event_handler_cb(wifi_event_handler_cb_t cb); - -typedef enum wps_type { - WPS_TYPE_DISABLE = 0, - WPS_TYPE_PBC, - WPS_TYPE_PIN, - WPS_TYPE_DISPLAY, - WPS_TYPE_MAX, -} WPS_TYPE_t; - -enum wps_cb_status { - WPS_CB_ST_SUCCESS = 0, - WPS_CB_ST_FAILED, - WPS_CB_ST_TIMEOUT, - WPS_CB_ST_WEP, -}; - -bool wifi_wps_enable(WPS_TYPE_t wps_type); -bool wifi_wps_disable(void); -bool wifi_wps_start(void); - -typedef void (*wps_st_cb_t)(int status); -bool wifi_set_wps_cb(wps_st_cb_t cb); - -typedef void (*freedom_outside_cb_t)(uint8 status); -int wifi_register_send_pkt_freedom_cb(freedom_outside_cb_t cb); -void wifi_unregister_send_pkt_freedom_cb(void); -int wifi_send_pkt_freedom(uint8 *buf, int len, bool sys_seq); - -int wifi_rfid_locp_recv_open(void); -void wifi_rfid_locp_recv_close(void); - -typedef void (*rfid_locp_cb_t)(uint8 *frm, int len, int rssi); -int wifi_register_rfid_locp_recv_cb(rfid_locp_cb_t cb); -void wifi_unregister_rfid_locp_recv_cb(void); - -enum FIXED_RATE { - PHY_RATE_48 = 0x8, - PHY_RATE_24 = 0x9, - PHY_RATE_12 = 0xA, - PHY_RATE_6 = 0xB, - PHY_RATE_54 = 0xC, - PHY_RATE_36 = 0xD, - PHY_RATE_18 = 0xE, - PHY_RATE_9 = 0xF, -}; - -#define FIXED_RATE_MASK_NONE 0x00 -#define FIXED_RATE_MASK_STA 0x01 -#define FIXED_RATE_MASK_AP 0x02 -#define FIXED_RATE_MASK_ALL 0x03 - -int wifi_set_user_fixed_rate(uint8 enable_mask, uint8 rate); -int wifi_get_user_fixed_rate(uint8 *enable_mask, uint8 *rate); - -enum support_rate { - RATE_11B5M = 0, - RATE_11B11M = 1, - RATE_11B1M = 2, - RATE_11B2M = 3, - RATE_11G6M = 4, - RATE_11G12M = 5, - RATE_11G24M = 6, - RATE_11G48M = 7, - RATE_11G54M = 8, - RATE_11G9M = 9, - RATE_11G18M = 10, - RATE_11G36M = 11, -}; - -int wifi_set_user_sup_rate(uint8 min, uint8 max); - -enum RATE_11B_ID { - RATE_11B_B11M = 0, - RATE_11B_B5M = 1, - RATE_11B_B2M = 2, - RATE_11B_B1M = 3, -}; - -enum RATE_11G_ID { - RATE_11G_G54M = 0, - RATE_11G_G48M = 1, - RATE_11G_G36M = 2, - RATE_11G_G24M = 3, - RATE_11G_G18M = 4, - RATE_11G_G12M = 5, - RATE_11G_G9M = 6, - RATE_11G_G6M = 7, - RATE_11G_B5M = 8, - RATE_11G_B2M = 9, - RATE_11G_B1M = 10 -}; - -enum RATE_11N_ID { - RATE_11N_MCS7S = 0, - RATE_11N_MCS7 = 1, - RATE_11N_MCS6 = 2, - RATE_11N_MCS5 = 3, - RATE_11N_MCS4 = 4, - RATE_11N_MCS3 = 5, - RATE_11N_MCS2 = 6, - RATE_11N_MCS1 = 7, - RATE_11N_MCS0 = 8, - RATE_11N_B5M = 9, - RATE_11N_B2M = 10, - RATE_11N_B1M = 11 -}; - -#define RC_LIMIT_11B 0 -#define RC_LIMIT_11G 1 -#define RC_LIMIT_11N 2 -#define RC_LIMIT_P2P_11G 3 -#define RC_LIMIT_P2P_11N 4 -#define RC_LIMIT_NUM 5 - -#define LIMIT_RATE_MASK_NONE 0x00 -#define LIMIT_RATE_MASK_STA 0x01 -#define LIMIT_RATE_MASK_AP 0x02 -#define LIMIT_RATE_MASK_ALL 0x03 - -bool wifi_set_user_rate_limit(uint8 mode, uint8 ifidx, uint8 max, uint8 min); -uint8 wifi_get_user_limit_rate_mask(void); -bool wifi_set_user_limit_rate_mask(uint8 enable_mask); - -enum { - USER_IE_BEACON = 0, - USER_IE_PROBE_REQ, - USER_IE_PROBE_RESP, - USER_IE_ASSOC_REQ, - USER_IE_ASSOC_RESP, - USER_IE_MAX -}; - -typedef void (*user_ie_manufacturer_recv_cb_t)(uint8 type, const uint8 sa[6], const uint8 m_oui[3], uint8 *ie, uint8 ie_len, int rssi); - -bool wifi_set_user_ie(bool enable, uint8 *m_oui, uint8 type, uint8 *user_ie, uint8 len); -int wifi_register_user_ie_manufacturer_recv_cb(user_ie_manufacturer_recv_cb_t cb); -void wifi_unregister_user_ie_manufacturer_recv_cb(void); - -void wifi_enable_gpio_wakeup(uint32 i, GPIO_INT_TYPE intr_status); -void wifi_disable_gpio_wakeup(void); - -void uart_div_modify(uint8 uart_no, uint32 DivLatchValue); - -#ifdef __cplusplus -} -#endif - -#endif // DOXYGEN -#endif /* USER_INTERFACE_H */ diff --git a/cpu/esp_common/esp-now/esp_now_gnrc.c b/cpu/esp_common/esp-now/esp_now_gnrc.c index ce8ff50933b1..2b02b4e40c02 100644 --- a/cpu/esp_common/esp-now/esp_now_gnrc.c +++ b/cpu/esp_common/esp-now/esp_now_gnrc.c @@ -24,16 +24,12 @@ #include "cpu_conf.h" #include "net/netdev.h" #include "net/gnrc.h" +#include "esp_common_log.h" #include "esp_now_params.h" #include "esp_now_netdev.h" #include "esp_now_gnrc.h" #include "net/gnrc/netif.h" -#ifdef MCU_ESP8266 -#include "log.h" -#include "common.h" -#endif - #define ENABLE_DEBUG (0) #include "debug.h" diff --git a/cpu/esp_common/esp-now/esp_now_netdev.c b/cpu/esp_common/esp-now/esp_now_netdev.c index e1ef709565f2..64c2c360fc5e 100644 --- a/cpu/esp_common/esp-now/esp_now_netdev.c +++ b/cpu/esp_common/esp-now/esp_now_netdev.c @@ -27,25 +27,17 @@ #include "net/gnrc.h" #include "xtimer.h" -#ifdef MCU_ESP32 #include "esp_common.h" #include "esp_attr.h" #include "esp_event_loop.h" #include "esp_now.h" #include "esp_system.h" #include "esp_wifi.h" -#include "nvs_flash/include/nvs_flash.h" -#else -#include "common.h" -#include "espressif/c_types.h" -#include "espnow.h" -#include "esp/common_macros.h" -#include "sdk/sdk.h" -#endif /* MCU_ESP32 */ - #include "irq_arch.h" #include "od.h" +#include "nvs_flash/include/nvs_flash.h" + #include "esp_now_params.h" #include "esp_now_netdev.h" @@ -61,50 +53,25 @@ #define ESP_NOW_AP_PREFIX "RIOT_ESP_" #define ESP_NOW_AP_PREFIX_LEN (strlen(ESP_NOW_AP_PREFIX)) -#ifdef MCU_ESP32 - -#define esp_now_set_self_role(r) - -#else - -#define ESP_NOW_ROLE_IDLE (0) -#define ESP_NOW_ROLE_CONTROLLER (1) -#define ESP_NOW_ROLE_SLAVE (2) -#define ESP_NOW_ROLE_COMBO (3) -#define ESP_NOW_KEY_LEN (16) - -#define ESP_OK (0) - -#ifndef IRAM_ATTR -#define IRAM_ATTR IRAM -#endif - -#endif /* MCU_ESP8266 */ - #if MODULE_ESP_WIFI && !ESP_NOW_UNICAST #error If module esp_wifi is used, module esp_now has to be used in unicast mode #endif /** * There is only one ESP-NOW device. We define it as static device variable - * to have accesss to the device inside ESP-NOW interrupt routines which do + * to have access to the device inside ESP-NOW interrupt routines which do * not provide an argument that could be used as pointer to the ESP-NOW * device which triggers the interrupt. */ -static esp_now_netdev_t _esp_now_dev; +static esp_now_netdev_t _esp_now_dev = { 0 }; static const netdev_driver_t _esp_now_driver; -#ifdef MCU_ESP32 static bool _esp_now_add_peer(const uint8_t* bssid, uint8_t channel, uint8_t* key) -#else -static bool _esp_now_add_peer(uint8_t* bssid, uint8_t channel, uint8_t* key) -#endif { if (esp_now_is_peer_exist(bssid)) { return false; } -#ifdef MCU_ESP32 esp_now_peer_info_t peer = {}; memcpy(peer.peer_addr, bssid, ESP_NOW_ETH_ALEN); @@ -117,11 +84,6 @@ static bool _esp_now_add_peer(uint8_t* bssid, uint8_t channel, uint8_t* key) } esp_err_t ret = esp_now_add_peer(&peer); -#else - int ret = esp_now_add_peer(bssid, ESP_NOW_ROLE_COMBO, channel, - esp_now_params.key, - esp_now_params.key ? ESP_NOW_KEY_LEN : 0); -#endif DEBUG("esp_now_add_peer node %02x:%02x:%02x:%02x:%02x:%02x " "added with return value %d\n", bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], ret); @@ -133,8 +95,6 @@ static bool _esp_now_add_peer(uint8_t* bssid, uint8_t channel, uint8_t* key) static xtimer_t _esp_now_scan_peers_timer; static bool _esp_now_scan_peers_done = false; -#ifdef MCU_ESP32 - #define ESP_NOW_APS_BLOCK_SIZE 8 /* has to be power of two */ static wifi_ap_record_t* aps = NULL; @@ -207,64 +167,14 @@ static void IRAM_ATTR esp_now_scan_peers_done(void) mutex_unlock(&_esp_now_dev.dev_lock); } -#else /* MCU_ESP32 */ - -static const struct scan_config scan_cfg = { - .ssid = 0, - .bssid = 0, - .channel = ESP_NOW_CHANNEL, - .show_hidden = true -}; - -static void IRAM esp_now_scan_peers_done(void *arg, STATUS status) -{ - /* This function is executed in interrupt context */ - - DEBUG("%s: %p %d\n", __func__, arg, status); - - CHECK_PARAM (status == OK); - CHECK_PARAM (arg != NULL); - - critical_enter(); - - struct bss_info *bss_link = (struct bss_info*)arg; - - /* iterate over APs records */ - while (bss_link) { - /* check whether the AP is an ESP_NOW node */ - if (strncmp((char*)bss_link->ssid, ESP_NOW_AP_PREFIX, ESP_NOW_AP_PREFIX_LEN) == 0) { - /* add the AP as peer */ - _esp_now_add_peer(bss_link->bssid, bss_link->channel, esp_now_params.key); - } - bss_link = STAILQ_NEXT(bss_link, next); - } - -#if ENABLE_DEBUG - uint8_t peers_all; - uint8_t peers_enc; - esp_now_get_cnt_info (&peers_all, &peers_enc); - DEBUG("associated peers total=%d, encrypted=%d\n", peers_all, peers_enc); -#endif /* ENABLE_DEBUG */ - - _esp_now_scan_peers_done = true; - - critical_exit(); -} - -#endif /* MCU_ESP32 */ - static void esp_now_scan_peers_start(void) { DEBUG("%s\n", __func__); - /* set the time for next scan */ - xtimer_set(&_esp_now_scan_peers_timer, esp_now_params.scan_period); /* start the scan */ -#ifdef MCU_ESP32 esp_wifi_scan_start(&scan_cfg, false); -#else - wifi_station_scan((struct scan_config*)&scan_cfg, esp_now_scan_peers_done); -#endif + /* set the time for next scan */ + xtimer_set(&_esp_now_scan_peers_timer, esp_now_params.scan_period); } static void IRAM_ATTR esp_now_scan_peers_timer_cb(void* arg) @@ -287,11 +197,7 @@ static const uint8_t _esp_now_mac[6] = { 0x82, 0x73, 0x79, 0x84, 0x79, 0x83 }; / static bool _in_recv_cb = false; -#ifdef MCU_ESP32 static IRAM_ATTR void esp_now_recv_cb(const uint8_t *mac, const uint8_t *data, int len) -#else -static IRAM_ATTR void esp_now_recv_cb(uint8_t *mac, uint8_t *data, uint8_t len) -#endif { #if ESP_NOW_UNICAST if (!_esp_now_scan_peers_done) { @@ -349,11 +255,7 @@ static IRAM_ATTR void esp_now_recv_cb(uint8_t *mac, uint8_t *data, uint8_t len) static volatile int _esp_now_sending = 0; -#ifdef MCU_ESP32 static void IRAM_ATTR esp_now_send_cb(const uint8_t *mac, esp_now_send_status_t status) -#else -static void IRAM_ATTR esp_now_send_cb(uint8_t *mac, uint8_t status) -#endif { DEBUG("%s: sent to %02x:%02x:%02x:%02x:%02x:%02x with status %d\n", __func__, @@ -364,7 +266,6 @@ static void IRAM_ATTR esp_now_send_cb(uint8_t *mac, uint8_t status) } } -#ifdef MCU_ESP32 /* * Event handler for esp system events. */ @@ -389,12 +290,6 @@ static esp_err_t IRAM_ATTR _esp_system_event_handler(void *ctx, system_event_t * extern esp_err_t esp_system_event_add_handler(system_event_cb_t handler, void *arg); -#else /* MCU_ESP32 */ - -#define ESP_IF_WIFI_STA (STATION_IF) - -#endif /* MCU_ESP32 */ - esp_now_netdev_t *netdev_esp_now_setup(void) { esp_now_netdev_t* dev = &_esp_now_dev; @@ -406,17 +301,17 @@ esp_now_netdev_t *netdev_esp_now_setup(void) return dev; } -#ifdef MCU_ESP32 - /* initialize buffer */ dev->rx_len = 0; /* set the event handler */ esp_system_event_add_handler(_esp_system_event_handler, NULL); +#ifdef MCU_ESP32 /* init the WiFi driver */ extern portMUX_TYPE g_intr_lock_mux; mutex_init(&g_intr_lock_mux); +#endif /* MCU_ESP32 */ esp_err_t result; @@ -462,7 +357,7 @@ esp_now_netdev_t *netdev_esp_now_setup(void) } }; - /* get SoftAP interface mac address and store it as device addresss */ + /* get SoftAP interface mac address and store it as device address */ esp_read_mac(dev->addr, ESP_MAC_WIFI_SOFTAP); /* prepare the ESP_NOW configuration for SoftAP */ @@ -513,6 +408,7 @@ esp_now_netdev_t *netdev_esp_now_setup(void) "esp_wifi_start failed with return value %d\n", result); return NULL; } + #if !ESP_NOW_UNICAST /* all ESP-NOW nodes get the shared mac address on their station interface */ esp_wifi_set_mac(ESP_IF_WIFI_STA, (uint8_t*)_esp_now_mac); @@ -520,41 +416,6 @@ esp_now_netdev_t *netdev_esp_now_setup(void) #endif /* MODULE_ESP_WIFI */ -#else /* MCU_ESP32 */ - - int result; - - /* set the WiFi interface to Station + SoftAP mode without DHCP */ - wifi_set_opmode_current(ESP_NOW_WIFI_STA_SOFTAP); - wifi_softap_dhcps_stop(); - - /* get SoftAP mac address and store it in device address */ - wifi_get_macaddr(SOFTAP_IF, dev->addr); - - /* set the SoftAP configuration */ - struct softap_config ap_conf; - - strcpy((char*)ap_conf.password, esp_now_params.softap_pass); - sprintf((char*)ap_conf.ssid, "%s%02x%02x%02x%02x%02x%02x", ESP_NOW_AP_PREFIX, - dev->addr[0], dev->addr[1], dev->addr[2], - dev->addr[3], dev->addr[4], dev->addr[5]); - - ap_conf.ssid_len = strlen((char*)ap_conf.ssid); - ap_conf.channel = esp_now_params.channel; /* support 1 ~ 13 */ - ap_conf.authmode = AUTH_WPA2_PSK; /* don't support AUTH_WEP in softAP mode. */ - ap_conf.ssid_hidden = 0; /* default 0 */ - ap_conf.max_connection = 4; /* default 4, max 4 */ - ap_conf.beacon_interval = 100; /* support 100 ~ 60000 ms, default 100 */ - - wifi_softap_set_config_current(&ap_conf); - -#if !ESP_NOW_UNICAST - /* all ESP-NOW nodes get the shared mac address on their station interface */ - wifi_set_macaddr(ESP_IF_WIFI_STA, (uint8_t*)_esp_now_mac); -#endif - -#endif /* MCU_ESP32 */ - /* set the netdev driver */ dev->netdev.driver = &_esp_now_driver; @@ -572,7 +433,6 @@ esp_now_netdev_t *netdev_esp_now_setup(void) } esp_now_register_send_cb(esp_now_send_cb); esp_now_register_recv_cb(esp_now_recv_cb); - esp_now_set_self_role(ESP_NOW_ROLE_COMBO); #if ESP_NOW_UNICAST /* timer for peer scan initialization */ diff --git a/cpu/esp_common/vendor/xtensa/portasm.S b/cpu/esp_common/vendor/xtensa/portasm.S index b26088cfc949..dbe01e6bf32d 100644 --- a/cpu/esp_common/vendor/xtensa/portasm.S +++ b/cpu/esp_common/vendor/xtensa/portasm.S @@ -57,6 +57,8 @@ port_IntStack: .space configISR_STACK_SIZE .global port_IntStackTop port_IntStackTop: + .global _chip_interrupt_tmp +_chip_interrupt_tmp: .word 0 #ifndef RIOT_VERSION diff --git a/cpu/esp_common/vendor/xtensa/xtensa_intr.c b/cpu/esp_common/vendor/xtensa/xtensa_intr.c index b1fb19685b3c..38021012f8c3 100644 --- a/cpu/esp_common/vendor/xtensa/xtensa_intr.c +++ b/cpu/esp_common/vendor/xtensa/xtensa_intr.c @@ -112,13 +112,7 @@ xt_handler xt_set_interrupt_handler(int n, xt_handler f, void * arg) if( Xthal_intlevel[n] > XCHAL_EXCM_LEVEL ) return 0; /* priority level too high to safely handle in C */ - #ifdef MODULE_ESP_SDK - /* for compatibility reasons with SDK, we use _xtos_interrupt_table */ - /* in reverse order */ - entry = _xt_interrupt_table + (XCHAL_NUM_INTERRUPTS - n); - #else entry = _xt_interrupt_table + n; - #endif old = entry->handler; if (f) { diff --git a/cpu/esp_common/vendor/xtensa/xtensa_intr_asm.S b/cpu/esp_common/vendor/xtensa/xtensa_intr_asm.S index 7230ed028796..70a9d0672065 100644 --- a/cpu/esp_common/vendor/xtensa/xtensa_intr_asm.S +++ b/cpu/esp_common/vendor/xtensa/xtensa_intr_asm.S @@ -66,7 +66,6 @@ _xt_vpri_mask: .word 0xFFFFFFFF /* Virtual priority mask */ in SDK we use _xtos_interrupt_table_ which is provided as symbol _xt_interrupt_table_ by ld script */ -#ifndef MODULE_ESP_SDK .data .global _xt_interrupt_table .align 8 @@ -79,7 +78,6 @@ _xt_interrupt_table: .word i /* handler arg (default: intnum) */ .set i, i+1 .endr -#endif #endif /* XCHAL_HAVE_INTERRUPTS */ diff --git a/cpu/esp_common/vendor/xtensa/xtensa_vectors.S b/cpu/esp_common/vendor/xtensa/xtensa_vectors.S index 42dd8bd4245c..75e3485c7875 100644 --- a/cpu/esp_common/vendor/xtensa/xtensa_vectors.S +++ b/cpu/esp_common/vendor/xtensa/xtensa_vectors.S @@ -96,7 +96,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /* Enable stack backtrace across exception/interrupt - see below */ #define XT_DEBUG_BACKTRACE 1 - /* -------------------------------------------------------------------------------- Defines used to access _xtos_interrupt_table. @@ -225,10 +224,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. find_ms_setbit a3, a4, a3, 0 /* a3 = interrupt number */ -#if MODULE_ESP_SDK /* _xtos_interrupt_table is in reverse order */ - movi a4, XCHAL_NUM_INTERRUPTS /* intnum = XCHAL_NUM_INTERRUPTS - intnum */ - sub a3, a4, a3 -#endif movi a4, _xt_interrupt_table addx8 a3, a3, a4 /* a3 = address of interrupt table entry */ l32i a4, a3, XIE_HANDLER /* a4 = handler address */ @@ -302,6 +297,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ .text + .literal_position .global _xt_panic .type _xt_panic,@function .align 4 @@ -315,6 +311,10 @@ _xt_panic: movi a2, SYS_gdb_abort simcall #else + #ifdef RIOT_VERSION + addi a2, a0, -3 + call0 _panic_handler + #endif rsil a2, XCHAL_EXCM_LEVEL /* disable all low & med ints */ 1: j 1b /* loop infinitely */ #endif @@ -388,6 +388,14 @@ Debug Exception. .align 4 _DebugExceptionVector: + /* + * Please note that this code will be overwritten with + * + * xsr a2, excsave2 + * jx a2 + * + * if module esp_gdbstub is used. + */ #ifdef XT_SIMULATOR /* @@ -401,15 +409,15 @@ _DebugExceptionVector: wsr a3, EXCSAVE+XCHAL_DEBUGLEVEL movi a3, xthal_debugexc_defhndlr_nw /* use default debug handler */ jx a3 - #else + #else /* XT_SIMULATOR */ wsr a0, EXCSAVE+XCHAL_DEBUGLEVEL /* save original a0 somewhere */ call0 _xt_panic /* does not return */ rfi XCHAL_DEBUGLEVEL /* make a0 point here not later */ - #endif + #endif /* XT_SIMULATOR */ - .end literal_prefix + .end literal_prefix -#endif +#endif /* XCHAL_HAVE_DEBUG */ /* -------------------------------------------------------------------------------- @@ -503,6 +511,7 @@ _UserExceptionVector: * "LoadStoreError Handler END" markers was extracted from esp-open-rtos. It is * under the following copyright: * + * Part of esp-open-rtos * Original vector contents Copyright (C) 2014-2015 Espressif Systems * Additions Copyright (C) Superhouse Automation Pty Ltd and Angus Gratton * BSD Licensed as described in the file LICENSE @@ -573,13 +582,13 @@ _LoadStoreErrorHandler: s32i a2, sp, 0x08 s32i a3, sp, 0x0c s32i a4, sp, 0x10 - rsr a0, sar # Save SAR in a0 to restore later + rsr a0, sar # Save SAR in a0 to restore later /* Examine the opcode which generated the exception */ /* Note: Instructions are in this order to avoid pipeline stalls. */ rsr a2, epc1 movi a3, ~3 - ssa8l a2 # sar is now correct shift for aligned read + ssa8l a2 # sar is now correct shift for aligned read and a2, a2, a3 # a2 now 4-byte aligned address of instruction l32i a4, a2, 0 l32i a2, a2, 4 @@ -600,8 +609,8 @@ _LoadStoreErrorHandler: and a4, a3, a4 # a4 now word aligned read address l32i a4, a4, 0 # perform the actual read - ssa8l a3 # sar is now shift to extract a3's byte - srl a3, a4 # shift right correct distance + ssa8l a3 # sar is now shift to extract a3's byte + srl a3, a4 # shift right correct distance extui a4, a3, 0, 8 # mask off bits we need for an l8 .LSE_post_fetch: @@ -678,8 +687,8 @@ _LoadStoreErrorHandler: and a4, a3, a4 # a4 now word aligned read address l32i a4, a4, 0 # perform the actual read - ssa8l a3 # sar is now shift to extract a3's bytes - srl a3, a4 # shift right correct distance + ssa8l a3 # sar is now shift to extract a3's bytes + srl a3, a4 # shift right correct distance extui a4, a3, 0, 16 # mask off bits we need for an l16 bbci a2, 15, .LSE_post_fetch # Not a signed op @@ -1951,14 +1960,32 @@ _xt_highint6: #if XCHAL_HAVE_NMI +#define NMI_STACK_CANARY 0xABBABABA + +/* Stack space for NMI handler + + NMI handler stack high water mark measured at 0x134 bytes. Any use + of the NMI timer callback will add stack overhead as well. + + The NMI handler does a basic check for stack overflow +*/ + + .section .bss + .balign 16 + +NMIHandlerStack: + .skip 0x200 +.NMIHandlerStackTop: + .begin literal_prefix .NMIExceptionVector .section .NMIExceptionVector.text, "ax" .global _NMIExceptionVector .type _NMIExceptionVector,@function .literal_position - .align 4 + _NMIExceptionVector: + wsr a0, EXCSAVE + XCHAL_NMILEVEL _ /* preserve a0 */ call0 _xt_nmi /* load interrupt handler */ /* never returns here - call0 is used as a jump (see note at top) */ @@ -1983,6 +2010,113 @@ _xt_nmi: /* USER_EDIT: ADD HIGH PRIORITY NON-MASKABLE INTERRUPT (NMI) HANDLER CODE HERE. */ + #if defined(RIOT_VERSION) && defined(MCU_ESP8266) + + rsr a0, EXCSAVE + XCHAL_NMILEVEL /* restore a0 as saved in _NMIExceptionHandler */ + + /*************************** NMI Handler BEGIN **************************/ + /* + * PLEASE NOTE: The code between "NMI Handler BEGIN" and + * "NMI Handler END" markers was extracted from esp-open-rtos. + * It is under the following copyright: + * + * Part of esp-open-rtos + * Original vector contents Copyright (C) 2014-2015 Espressif Systems + * Additions Copyright (C) Superhouse Automation Pty Ltd and Angus Gratton + * BSD Licensed as described in the file LICENSE. + */ + wsr sp, excsave3 # excsave3 holds user stack + movi sp, .NMIHandlerStackTop - 0x40 + s32i a0, sp, 0x00 + s32i a2, sp, 0x04 + s32i a3, sp, 0x08 + s32i a4, sp, 0x0c + s32i a5, sp, 0x10 + s32i a6, sp, 0x14 + s32i a7, sp, 0x18 + s32i a8, sp, 0x1c + s32i a9, sp, 0x20 + s32i a10, sp, 0x24 + s32i a11, sp, 0x28 + rsr a0, epc1 + s32i a0, sp, 0x2c + rsr a0, exccause + s32i a0, sp, 0x30 + rsr a0, excsave1 + s32i a0, sp, 0x34 + rsr a0, excvaddr + s32i a0, sp, 0x38 + rsr a0, sar + s32i a0, sp, 0x3c + movi a0, 0x23 # Override PS for NMI handler + wsr a0, ps + rsync + + /* mark the stack overflow point before we call the actual NMI handler */ + movi a0, NMIHandlerStack + movi a2, NMI_STACK_CANARY + s32i a2, a0, 0x00 + + call0 wDev_ProcessFiq + + /* verify we didn't overflow */ + movi a0, NMIHandlerStack + l32i a3, a0, 0 + movi a2, NMI_STACK_CANARY + bne a3, a2, _xt_panic /* .NMIFatalStackOverflow */ + + l32i a0, sp, 0x3c + wsr a0, sar + l32i a0, sp, 0x38 + wsr a0, excvaddr + l32i a0, sp, 0x34 + wsr a0, excsave1 + l32i a0, sp, 0x30 + wsr a0, exccause + l32i a0, sp, 0x2c + wsr a0, epc1 + l32i a11, sp, 0x28 + l32i a10, sp, 0x24 + l32i a9, sp, 0x20 + l32i a8, sp, 0x1c + l32i a7, sp, 0x18 + l32i a6, sp, 0x14 + l32i a5, sp, 0x10 + l32i a4, sp, 0x0c + l32i a3, sp, 0x08 + movi a0, 0x33 # Reset PS + wsr a0, ps + rsync + /* set dport nmi status to 1 (wDev_ProcessFiq clears bit 0 and verifies it + * stays cleared, see + * http://esp8266-re.foogod.com/wiki/WDev_ProcessFiq_%28IoT_RTOS_SDK_0.9.9%29) + */ + movi a0, 0x3ff00000 + movi a2, 0x1 + s32i a2, a0, 0 + l32i a2, sp, 0x04 + l32i a0, sp, 0x00 + movi a1, 0x0 + xsr a1, excsave3 # Load stack back from excsave3, clear excsave3 + rfi XCHAL_NMILEVEL + + .section .rodata +.NMIStackOverflowErrorMsg: + .string "\nFATAL: NMI Stack Overflow\n" + + .section .NMIExceptionhandler.text, "ax" + .literal_position + +.NMIFatalStackOverflow: + movi a2, .NMIStackOverflowErrorMsg + call0 printf + +.NMIInfiniteLoop: + j .NMIInfiniteLoop /* TODO: replace with call to abort() */ + + /*************************** NMI Handler END ****************************/ + + #endif /* defined(RIOT_VERSION) && defined(MCU_ESP8266) */ .align 4 .L_xt_nmi_exit: diff --git a/dist/tools/esptool/espreset.py b/dist/tools/esptool/espreset.py new file mode 100755 index 000000000000..d05e8fd0aa8d --- /dev/null +++ b/dist/tools/esptool/espreset.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2019 Gunar Schorcht +# 2014 Oliver Hahm +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + + +try: + import configparser +except ImportError: + import ConfigParser as configparser + +import serial +import sys +import time +import argparse + +try: + serial.Serial +except AttributeError: + print("\033[1;37;41m\n") + print("Something went terribly wrong when loading the pyserial package.") + print("There is a good chance that you installed the 'serial' package instead") + print("of 'pyserial'. Try running 'pip uninstall serial && pip install pyserial'") + print("\033[0m") + sys.exit(1) + +# default serial port +defaultport = "/dev/ttyUSB0" + +# default baudrate for serial connection +defaultbaud = 115200 + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="espreset - ESP reset program") + parser.add_argument("-p", "--port", + help="Specifies the serial port to use, default is %s" + % defaultport, + default=defaultport) + parser.add_argument("-b", "--baudrate", + help="Specifies baudrate for the serial port, default " + "is %s" % defaultbaud, + default=defaultbaud) + + args = parser.parse_args() + + ser = serial.Serial(port=args.port, dsrdtr=0, rtscts=0) + ser.baudrate = args.baudrate + # set RST low and GPIO0 high + ser.setRTS(1) + ser.setDTR(0) + # keep the RST line low for 0.1 seconds + time.sleep(0.1) + # set the RST high + ser.setRTS(1) + ser.setDTR(1) + # wait 1 second for boot + time.sleep(1) + sys.exit(0) diff --git a/dist/tools/esptool/esptool.py b/dist/tools/esptool/esptool.py new file mode 100755 index 000000000000..cd70056e95f3 --- /dev/null +++ b/dist/tools/esptool/esptool.py @@ -0,0 +1,3023 @@ +#!/usr/bin/env python +# +# ESP8266 & ESP32 ROM Bootloader Utility +# Copyright (C) 2014-2016 Fredrik Ahlberg, Angus Gratton, Espressif Systems (Shanghai) PTE LTD, other contributors as noted. +# https://github.com/espressif/esptool +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin +# Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from __future__ import division, print_function + +import argparse +import base64 +import binascii +import copy +import hashlib +import inspect +import io +import os +import shlex +import struct +import sys +import time +import zlib +import string +import serial.tools.list_ports as list_ports + +import serial + +# check 'serial' is 'pyserial' and not 'serial' https://github.com/espressif/esptool/issues/269 +try: + if "serialization" in serial.__doc__ and "deserialization" in serial.__doc__: + raise ImportError(""" +esptool.py depends on pyserial, but there is a conflict with a currently installed package named 'serial'. + +You may be able to work around this by 'pip uninstall serial; pip install pyserial' \ +but this may break other installed Python software that depends on 'serial'. + +There is no good fix for this right now, apart from configuring virtualenvs. \ +See https://github.com/espressif/esptool/issues/269#issuecomment-385298196 for discussion of the underlying issue(s).""") +except TypeError: + pass # __doc__ returns None for pyserial + + +__version__ = "2.4.0" + +MAX_UINT32 = 0xffffffff +MAX_UINT24 = 0xffffff + +DEFAULT_TIMEOUT = 3 # timeout for most flash operations +START_FLASH_TIMEOUT = 20 # timeout for starting flash (may perform erase) +CHIP_ERASE_TIMEOUT = 120 # timeout for full chip erase +MAX_TIMEOUT = CHIP_ERASE_TIMEOUT * 2 # longest any command can run +SYNC_TIMEOUT = 0.1 # timeout for syncing with bootloader +MD5_TIMEOUT_PER_MB = 8 # timeout (per megabyte) for calculating md5sum +ERASE_REGION_TIMEOUT_PER_MB = 30 # timeout (per megabyte) for erasing a region +MEM_END_ROM_TIMEOUT = 0.05 # special short timeout for ESP_MEM_END, as it may never respond + + +def timeout_per_mb(seconds_per_mb, size_bytes): + """ Scales timeouts which are size-specific """ + result = seconds_per_mb * (size_bytes / 1e6) + if result < DEFAULT_TIMEOUT: + return DEFAULT_TIMEOUT + return result + + +DETECTED_FLASH_SIZES = {0x12: '256KB', 0x13: '512KB', 0x14: '1MB', + 0x15: '2MB', 0x16: '4MB', 0x17: '8MB', 0x18: '16MB'} + + +def check_supported_function(func, check_func): + """ + Decorator implementation that wraps a check around an ESPLoader + bootloader function to check if it's supported. + + This is used to capture the multidimensional differences in + functionality between the ESP8266 & ESP32 ROM loaders, and the + software stub that runs on both. Not possible to do this cleanly + via inheritance alone. + """ + def inner(*args, **kwargs): + obj = args[0] + if check_func(obj): + return func(*args, **kwargs) + else: + raise NotImplementedInROMError(obj, func) + return inner + + +def stub_function_only(func): + """ Attribute for a function only supported in the software stub loader """ + return check_supported_function(func, lambda o: o.IS_STUB) + + +def stub_and_esp32_function_only(func): + """ Attribute for a function only supported by software stubs or ESP32 ROM """ + return check_supported_function(func, lambda o: o.IS_STUB or o.CHIP_NAME == "ESP32") + + +PYTHON2 = sys.version_info[0] < 3 # True if on pre-Python 3 + +# Function to return nth byte of a bitstring +# Different behaviour on Python 2 vs 3 +if PYTHON2: + def byte(bitstr, index): + return ord(bitstr[index]) +else: + def byte(bitstr, index): + return bitstr[index] + +# Provide a 'basestring' class on Python 3 +try: + basestring +except NameError: + basestring = str + + +def esp8266_function_only(func): + """ Attribute for a function only supported on ESP8266 """ + return check_supported_function(func, lambda o: o.CHIP_NAME == "ESP8266") + + +class ESPLoader(object): + """ Base class providing access to ESP ROM & software stub bootloaders. + Subclasses provide ESP8266 & ESP32 specific functionality. + + Don't instantiate this base class directly, either instantiate a subclass or + call ESPLoader.detect_chip() which will interrogate the chip and return the + appropriate subclass instance. + + """ + CHIP_NAME = "Espressif device" + IS_STUB = False + + DEFAULT_PORT = "/dev/ttyUSB0" + + # Commands supported by ESP8266 ROM bootloader + ESP_FLASH_BEGIN = 0x02 + ESP_FLASH_DATA = 0x03 + ESP_FLASH_END = 0x04 + ESP_MEM_BEGIN = 0x05 + ESP_MEM_END = 0x06 + ESP_MEM_DATA = 0x07 + ESP_SYNC = 0x08 + ESP_WRITE_REG = 0x09 + ESP_READ_REG = 0x0a + + # Some comands supported by ESP32 ROM bootloader (or -8266 w/ stub) + ESP_SPI_SET_PARAMS = 0x0B + ESP_SPI_ATTACH = 0x0D + ESP_CHANGE_BAUDRATE = 0x0F + ESP_FLASH_DEFL_BEGIN = 0x10 + ESP_FLASH_DEFL_DATA = 0x11 + ESP_FLASH_DEFL_END = 0x12 + ESP_SPI_FLASH_MD5 = 0x13 + + # Some commands supported by stub only + ESP_ERASE_FLASH = 0xD0 + ESP_ERASE_REGION = 0xD1 + ESP_READ_FLASH = 0xD2 + ESP_RUN_USER_CODE = 0xD3 + + # Maximum block sized for RAM and Flash writes, respectively. + ESP_RAM_BLOCK = 0x1800 + + FLASH_WRITE_SIZE = 0x400 + + # Default baudrate. The ROM auto-bauds, so we can use more or less whatever we want. + ESP_ROM_BAUD = 115200 + + # First byte of the application image + ESP_IMAGE_MAGIC = 0xe9 + + # Initial state for the checksum routine + ESP_CHECKSUM_MAGIC = 0xef + + # Flash sector size, minimum unit of erase. + FLASH_SECTOR_SIZE = 0x1000 + + UART_DATA_REG_ADDR = 0x60000078 + + # Memory addresses + IROM_MAP_START = 0x40200000 + IROM_MAP_END = 0x40300000 + + # The number of bytes in the UART response that signify command status + STATUS_BYTES_LENGTH = 2 + + def __init__(self, port=DEFAULT_PORT, baud=ESP_ROM_BAUD, trace_enabled=False): + """Base constructor for ESPLoader bootloader interaction + + Don't call this constructor, either instantiate ESP8266ROM + or ESP32ROM, or use ESPLoader.detect_chip(). + + This base class has all of the instance methods for bootloader + functionality supported across various chips & stub + loaders. Subclasses replace the functions they don't support + with ones which throw NotImplementedInROMError(). + + """ + if isinstance(port, basestring): + self._port = serial.serial_for_url(port) + else: + self._port = port + self._slip_reader = slip_reader(self._port, self.trace) + # setting baud rate in a separate step is a workaround for + # CH341 driver on some Linux versions (this opens at 9600 then + # sets), shouldn't matter for other platforms/drivers. See + # https://github.com/espressif/esptool/issues/44#issuecomment-107094446 + self._set_port_baudrate(baud) + self._trace_enabled = trace_enabled + + def _set_port_baudrate(self, baud): + try: + self._port.baudrate = baud + except IOError: + raise FatalError("Failed to set baud rate %d. The driver may not support this rate." % baud) + + @staticmethod + def detect_chip(port=DEFAULT_PORT, baud=ESP_ROM_BAUD, connect_mode='default_reset', trace_enabled=False): + """ Use serial access to detect the chip type. + + We use the UART's datecode register for this, it's mapped at + the same address on ESP8266 & ESP32 so we can use one + memory read and compare to the datecode register for each chip + type. + + This routine automatically performs ESPLoader.connect() (passing + connect_mode parameter) as part of querying the chip. + """ + detect_port = ESPLoader(port, baud, trace_enabled=trace_enabled) + detect_port.connect(connect_mode) + print('Detecting chip type...', end='') + sys.stdout.flush() + date_reg = detect_port.read_reg(ESPLoader.UART_DATA_REG_ADDR) + + for cls in [ESP8266ROM, ESP32ROM]: + if date_reg == cls.DATE_REG_VALUE: + # don't connect a second time + inst = cls(detect_port._port, baud, trace_enabled=trace_enabled) + print(' %s' % inst.CHIP_NAME) + return inst + print('') + raise FatalError("Unexpected UART datecode value 0x%08x. Failed to autodetect chip type." % date_reg) + + """ Read a SLIP packet from the serial port """ + def read(self): + return next(self._slip_reader) + + """ Write bytes to the serial port while performing SLIP escaping """ + def write(self, packet): + buf = b'\xc0' \ + + (packet.replace(b'\xdb',b'\xdb\xdd').replace(b'\xc0',b'\xdb\xdc')) \ + + b'\xc0' + self.trace("Write %d bytes: %s", len(buf), HexFormatter(buf)) + self._port.write(buf) + + def trace(self, message, *format_args): + if self._trace_enabled: + now = time.time() + try: + + delta = now - self._last_trace + except AttributeError: + delta = 0.0 + self._last_trace = now + prefix = "TRACE +%.3f " % delta + print(prefix + (message % format_args)) + + """ Calculate checksum of a blob, as it is defined by the ROM """ + @staticmethod + def checksum(data, state=ESP_CHECKSUM_MAGIC): + for b in data: + if type(b) is int: # python 2/3 compat + state ^= b + else: + state ^= ord(b) + + return state + + """ Send a request and read the response """ + def command(self, op=None, data=b"", chk=0, wait_response=True, timeout=DEFAULT_TIMEOUT): + saved_timeout = self._port.timeout + new_timeout = min(timeout, MAX_TIMEOUT) + if new_timeout != saved_timeout: + self._port.timeout = new_timeout + + try: + if op is not None: + self.trace("command op=0x%02x data len=%s wait_response=%d timeout=%.3f data=%s", + op, len(data), 1 if wait_response else 0, timeout, HexFormatter(data)) + pkt = struct.pack(b' self.STATUS_BYTES_LENGTH: + return data[:-self.STATUS_BYTES_LENGTH] + else: # otherwise, just return the 'val' field which comes from the reply header (this is used by read_reg) + return val + + def flush_input(self): + self._port.flushInput() + self._slip_reader = slip_reader(self._port, self.trace) + + def sync(self): + self.command(self.ESP_SYNC, b'\x07\x07\x12\x20' + 32 * b'\x55', + timeout=SYNC_TIMEOUT) + for i in range(7): + self.command() + + def _setDTR(self, state): + self._port.setDTR(state) + + def _setRTS(self, state): + self._port.setRTS(state) + # Work-around for adapters on Windows using the usbser.sys driver: + # generate a dummy change to DTR so that the set-control-line-state + # request is sent with the updated RTS state and the same DTR state + self._port.setDTR(self._port.dtr) + + def _connect_attempt(self, mode='default_reset', esp32r0_delay=False): + """ A single connection attempt, with esp32r0 workaround options """ + # esp32r0_delay is a workaround for bugs with the most common auto reset + # circuit and Windows, if the EN pin on the dev board does not have + # enough capacitance. + # + # Newer dev boards shouldn't have this problem (higher value capacitor + # on the EN pin), and ESP32 revision 1 can't use this workaround as it + # relies on a silicon bug. + # + # Details: https://github.com/espressif/esptool/issues/136 + last_error = None + + # If we're doing no_sync, we're likely communicating as a pass through + # with an intermediate device to the ESP32 + if mode == "no_reset_no_sync": + return last_error + + # issue reset-to-bootloader: + # RTS = either CH_PD/EN or nRESET (both active low = chip in reset + # DTR = GPIO0 (active low = boot to flasher) + # + # DTR & RTS are active low signals, + # ie True = pin @ 0V, False = pin @ VCC. + if mode != 'no_reset': + self._setDTR(False) # IO0=HIGH + self._setRTS(True) # EN=LOW, chip in reset + time.sleep(0.1) + if esp32r0_delay: + # Some chips are more likely to trigger the esp32r0 + # watchdog reset silicon bug if they're held with EN=LOW + # for a longer period + time.sleep(1.2) + self._setDTR(True) # IO0=LOW + self._setRTS(False) # EN=HIGH, chip out of reset + if esp32r0_delay: + # Sleep longer after reset. + # This workaround only works on revision 0 ESP32 chips, + # it exploits a silicon bug spurious watchdog reset. + time.sleep(0.4) # allow watchdog reset to occur + time.sleep(0.05) + self._setDTR(False) # IO0=HIGH, done + + for _ in range(5): + try: + self.flush_input() + self._port.flushOutput() + self.sync() + return None + except FatalError as e: + if esp32r0_delay: + print('_', end='') + else: + print('.', end='') + sys.stdout.flush() + time.sleep(0.05) + last_error = e + return last_error + + def connect(self, mode='default_reset'): + """ Try connecting repeatedly until successful, or giving up """ + print('Connecting...', end='') + sys.stdout.flush() + last_error = None + + try: + for _ in range(7): + last_error = self._connect_attempt(mode=mode, esp32r0_delay=False) + if last_error is None: + return + last_error = self._connect_attempt(mode=mode, esp32r0_delay=True) + if last_error is None: + return + finally: + print('') # end 'Connecting...' line + raise FatalError('Failed to connect to %s: %s' % (self.CHIP_NAME, last_error)) + + """ Read memory address in target """ + def read_reg(self, addr): + # we don't call check_command here because read_reg() function is called + # when detecting chip type, and the way we check for success (STATUS_BYTES_LENGTH) is different + # for different chip types (!) + val, data = self.command(self.ESP_READ_REG, struct.pack(' start: + raise FatalError(("Software loader is resident at 0x%08x-0x%08x. " + + "Can't load binary at overlapping address range 0x%08x-0x%08x. " + + "Either change binary loading address, or use the --no-stub " + + "option to disable the software loader.") % (start, end, load_start, load_end)) + + return self.check_command("enter RAM download mode", self.ESP_MEM_BEGIN, + struct.pack(' length: + raise FatalError('Read more than expected') + digest_frame = self.read() + if len(digest_frame) != 16: + raise FatalError('Expected digest, got: %s' % hexify(digest_frame)) + expected_digest = hexify(digest_frame).upper() + digest = hashlib.md5(data).hexdigest().upper() + if digest != expected_digest: + raise FatalError('Digest mismatch: expected %s, got %s' % (expected_digest, digest)) + return data + + def flash_spi_attach(self, hspi_arg): + """Send SPI attach command to enable the SPI flash pins + + ESP8266 ROM does this when you send flash_begin, ESP32 ROM + has it as a SPI command. + """ + # last 3 bytes in ESP_SPI_ATTACH argument are reserved values + arg = struct.pack(' 0: + self.write_reg(SPI_MOSI_DLEN_REG, mosi_bits - 1) + if miso_bits > 0: + self.write_reg(SPI_MISO_DLEN_REG, miso_bits - 1) + else: + + def set_data_lengths(mosi_bits, miso_bits): + SPI_DATA_LEN_REG = SPI_USR1_REG + SPI_MOSI_BITLEN_S = 17 + SPI_MISO_BITLEN_S = 8 + mosi_mask = 0 if (mosi_bits == 0) else (mosi_bits - 1) + miso_mask = 0 if (miso_bits == 0) else (miso_bits - 1) + self.write_reg(SPI_DATA_LEN_REG, + (miso_mask << SPI_MISO_BITLEN_S) | ( + mosi_mask << SPI_MOSI_BITLEN_S)) + + # SPI peripheral "command" bitmasks for SPI_CMD_REG + SPI_CMD_USR = (1 << 18) + + # shift values + SPI_USR2_DLEN_SHIFT = 28 + + if read_bits > 32: + raise FatalError("Reading more than 32 bits back from a SPI flash operation is unsupported") + if len(data) > 64: + raise FatalError("Writing more than 64 bytes of data with one SPI command is unsupported") + + data_bits = len(data) * 8 + old_spi_usr = self.read_reg(SPI_USR_REG) + old_spi_usr2 = self.read_reg(SPI_USR2_REG) + flags = SPI_USR_COMMAND + if read_bits > 0: + flags |= SPI_USR_MISO + if data_bits > 0: + flags |= SPI_USR_MOSI + set_data_lengths(data_bits, read_bits) + self.write_reg(SPI_USR_REG, flags) + self.write_reg(SPI_USR2_REG, + (7 << SPI_USR2_DLEN_SHIFT) | spiflash_command) + if data_bits == 0: + self.write_reg(SPI_W0_REG, 0) # clear data register before we read it + else: + data = pad_to(data, 4, b'\00') # pad to 32-bit multiple + words = struct.unpack("I" * (len(data) // 4), data) + next_reg = SPI_W0_REG + for word in words: + self.write_reg(next_reg, word) + next_reg += 4 + self.write_reg(SPI_CMD_REG, SPI_CMD_USR) + + def wait_done(): + for _ in range(10): + if (self.read_reg(SPI_CMD_REG) & SPI_CMD_USR) == 0: + return + raise FatalError("SPI command did not complete in time") + wait_done() + + status = self.read_reg(SPI_W0_REG) + # restore some SPI controller registers + self.write_reg(SPI_USR_REG, old_spi_usr) + self.write_reg(SPI_USR2_REG, old_spi_usr2) + return status + + def read_status(self, num_bytes=2): + """Read up to 24 bits (num_bytes) of SPI flash status register contents + via RDSR, RDSR2, RDSR3 commands + + Not all SPI flash supports all three commands. The upper 1 or 2 + bytes may be 0xFF. + """ + SPIFLASH_RDSR = 0x05 + SPIFLASH_RDSR2 = 0x35 + SPIFLASH_RDSR3 = 0x15 + + status = 0 + shift = 0 + for cmd in [SPIFLASH_RDSR, SPIFLASH_RDSR2, SPIFLASH_RDSR3][0:num_bytes]: + status += self.run_spiflash_command(cmd, read_bits=8) << shift + shift += 8 + return status + + def write_status(self, new_status, num_bytes=2, set_non_volatile=False): + """Write up to 24 bits (num_bytes) of new status register + + num_bytes can be 1, 2 or 3. + + Not all flash supports the additional commands to write the + second and third byte of the status register. When writing 2 + bytes, esptool also sends a 16-byte WRSR command (as some + flash types use this instead of WRSR2.) + + If the set_non_volatile flag is set, non-volatile bits will + be set as well as volatile ones (WREN used instead of WEVSR). + + """ + SPIFLASH_WRSR = 0x01 + SPIFLASH_WRSR2 = 0x31 + SPIFLASH_WRSR3 = 0x11 + SPIFLASH_WEVSR = 0x50 + SPIFLASH_WREN = 0x06 + SPIFLASH_WRDI = 0x04 + + enable_cmd = SPIFLASH_WREN if set_non_volatile else SPIFLASH_WEVSR + + # try using a 16-bit WRSR (not supported by all chips) + # this may be redundant, but shouldn't hurt + if num_bytes == 2: + self.run_spiflash_command(enable_cmd) + self.run_spiflash_command(SPIFLASH_WRSR, struct.pack(">= 8 + + self.run_spiflash_command(SPIFLASH_WRDI) + + def hard_reset(self): + self._setRTS(True) # EN->LOW + time.sleep(0.1) + self._setRTS(False) + time.sleep(1) + + def soft_reset(self, stay_in_bootloader): + if not self.IS_STUB: + if stay_in_bootloader: + return # ROM bootloader is already in bootloader! + else: + # 'run user code' is as close to a soft reset as we can do + self.flash_begin(0, 0) + self.flash_finish(False) + else: + if stay_in_bootloader: + # soft resetting from the stub loader + # will re-load the ROM bootloader + self.flash_begin(0, 0) + self.flash_finish(True) + elif self.CHIP_NAME != "ESP8266": + raise FatalError("Soft resetting is currently only supported on ESP8266") + else: + # running user code from stub loader requires some hacks + # in the stub loader + self.command(self.ESP_RUN_USER_CODE, wait_response=False) + + +class ESP8266ROM(ESPLoader): + """ Access class for ESP8266 ROM bootloader + """ + CHIP_NAME = "ESP8266" + IS_STUB = False + + DATE_REG_VALUE = 0x00062000 + + # OTP ROM addresses + ESP_OTP_MAC0 = 0x3ff00050 + ESP_OTP_MAC1 = 0x3ff00054 + ESP_OTP_MAC3 = 0x3ff0005c + + SPI_REG_BASE = 0x60000200 + SPI_W0_OFFS = 0x40 + SPI_HAS_MOSI_DLEN_REG = False + + FLASH_SIZES = { + '512KB':0x00, + '256KB':0x10, + '1MB':0x20, + '2MB':0x30, + '4MB':0x40, + '2MB-c1': 0x50, + '4MB-c1':0x60, + '8MB':0x80, + '16MB':0x90, + } + + BOOTLOADER_FLASH_OFFSET = 0 + + def get_efuses(self): + # Return the 128 bits of ESP8266 efuse as a single Python integer + return (self.read_reg(0x3ff0005c) << 96 | + self.read_reg(0x3ff00058) << 64 | + self.read_reg(0x3ff00054) << 32 | + self.read_reg(0x3ff00050)) + + def get_chip_description(self): + efuses = self.get_efuses() + is_8285 = (efuses & ((1 << 4) | 1 << 80)) != 0 # One or the other efuse bit is set for ESP8285 + return "ESP8285" if is_8285 else "ESP8266EX" + + def get_chip_features(self): + features = ["WiFi"] + if self.get_chip_description() == "ESP8285": + features += ["Embedded Flash"] + return features + + def flash_spi_attach(self, hspi_arg): + if self.IS_STUB: + super(ESP8266ROM, self).flash_spi_attach(hspi_arg) + else: + # ESP8266 ROM has no flash_spi_attach command in serial protocol, + # but flash_begin will do it + self.flash_begin(0, 0) + + def flash_set_parameters(self, size): + # not implemented in ROM, but OK to silently skip for ROM + if self.IS_STUB: + super(ESP8266ROM, self).flash_set_parameters(size) + + def chip_id(self): + """ Read Chip ID from efuse - the equivalent of the SDK system_get_chip_id() function """ + id0 = self.read_reg(self.ESP_OTP_MAC0) + id1 = self.read_reg(self.ESP_OTP_MAC1) + return (id0 >> 24) | ((id1 & MAX_UINT24) << 8) + + def read_mac(self): + """ Read MAC from OTP ROM """ + mac0 = self.read_reg(self.ESP_OTP_MAC0) + mac1 = self.read_reg(self.ESP_OTP_MAC1) + mac3 = self.read_reg(self.ESP_OTP_MAC3) + if (mac3 != 0): + oui = ((mac3 >> 16) & 0xff, (mac3 >> 8) & 0xff, mac3 & 0xff) + elif ((mac1 >> 16) & 0xff) == 0: + oui = (0x18, 0xfe, 0x34) + elif ((mac1 >> 16) & 0xff) == 1: + oui = (0xac, 0xd0, 0x74) + else: + raise FatalError("Unknown OUI") + return oui + ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff) + + def get_erase_size(self, offset, size): + """ Calculate an erase size given a specific size in bytes. + + Provides a workaround for the bootloader erase bug.""" + + sectors_per_block = 16 + sector_size = self.FLASH_SECTOR_SIZE + num_sectors = (size + sector_size - 1) // sector_size + start_sector = offset // sector_size + + head_sectors = sectors_per_block - (start_sector % sectors_per_block) + if num_sectors < head_sectors: + head_sectors = num_sectors + + if num_sectors < 2 * head_sectors: + return (num_sectors + 1) // 2 * sector_size + else: + return (num_sectors - head_sectors) * sector_size + + def override_vddsdio(self, new_voltage): + raise NotImplementedInROMError("Overriding VDDSDIO setting only applies to ESP32") + + +class ESP8266StubLoader(ESP8266ROM): + """ Access class for ESP8266 stub loader, runs on top of ROM. + """ + FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c + IS_STUB = True + + def __init__(self, rom_loader): + self._port = rom_loader._port + self._trace_enabled = rom_loader._trace_enabled + self.flush_input() # resets _slip_reader + + def get_erase_size(self, offset, size): + return size # stub doesn't have same size bug as ROM loader + + +ESP8266ROM.STUB_CLASS = ESP8266StubLoader + + +class ESP32ROM(ESPLoader): + """Access class for ESP32 ROM bootloader + + """ + CHIP_NAME = "ESP32" + IS_STUB = False + + DATE_REG_VALUE = 0x15122500 + + IROM_MAP_START = 0x400d0000 + IROM_MAP_END = 0x40400000 + DROM_MAP_START = 0x3F400000 + DROM_MAP_END = 0x3F800000 + + # ESP32 uses a 4 byte status reply + STATUS_BYTES_LENGTH = 4 + + SPI_REG_BASE = 0x60002000 + EFUSE_REG_BASE = 0x6001a000 + + SPI_W0_OFFS = 0x80 + SPI_HAS_MOSI_DLEN_REG = True + + FLASH_SIZES = { + '1MB':0x00, + '2MB':0x10, + '4MB':0x20, + '8MB':0x30, + '16MB':0x40 + } + + BOOTLOADER_FLASH_OFFSET = 0x1000 + + OVERRIDE_VDDSDIO_CHOICES = ["1.8V", "1.9V", "OFF"] + + def get_chip_description(self): + word3 = self.read_efuse(3) + chip_ver_rev1 = (word3 >> 15) & 0x1 + pkg_version = (word3 >> 9) & 0x07 + + chip_name = { + 0: "ESP32D0WDQ6", + 1: "ESP32D0WDQ5", + 2: "ESP32D2WDQ5", + 5: "ESP32-PICO-D4", + }.get(pkg_version, "unknown ESP32") + + return "%s (revision %d)" % (chip_name, chip_ver_rev1) + + def get_chip_features(self): + features = ["WiFi"] + word3 = self.read_efuse(3) + + # names of variables in this section are lowercase + # versions of EFUSE names as documented in TRM and + # ESP-IDF efuse_reg.h + + chip_ver_dis_bt = word3 & (1 << 1) + if chip_ver_dis_bt == 0: + features += ["BT"] + + chip_ver_dis_app_cpu = word3 & (1 << 0) + if chip_ver_dis_app_cpu: + features += ["Single Core"] + else: + features += ["Dual Core"] + + chip_cpu_freq_rated = word3 & (1 << 13) + if chip_cpu_freq_rated: + chip_cpu_freq_low = word3 & (1 << 12) + if chip_cpu_freq_low: + features += ["160MHz"] + else: + features += ["240MHz"] + + pkg_version = (word3 >> 9) & 0x07 + if pkg_version in [2, 4, 5]: + features += ["Embedded Flash"] + + word4 = self.read_efuse(4) + adc_vref = (word4 >> 8) & 0x1F + if adc_vref: + features += ["VRef calibration in efuse"] + + return features + + def read_efuse(self, n): + """ Read the nth word of the ESP3x EFUSE region. """ + return self.read_reg(self.EFUSE_REG_BASE + (4 * n)) + + def chip_id(self): + raise NotSupportedError(self, "chip_id") + + def read_mac(self): + """ Read MAC from EFUSE region """ + words = [self.read_efuse(2), self.read_efuse(1)] + bitstring = struct.pack(">II", *words) + bitstring = bitstring[2:8] # trim the 2 byte CRC + try: + return tuple(ord(b) for b in bitstring) + except TypeError: # Python 3, bitstring elements are already bytes + return tuple(bitstring) + + def get_erase_size(self, offset, size): + return size + + def override_vddsdio(self, new_voltage): + new_voltage = new_voltage.upper() + if new_voltage not in self.OVERRIDE_VDDSDIO_CHOICES: + raise FatalError("The only accepted VDDSDIO overrides are '1.8V', '1.9V' and 'OFF'") + RTC_CNTL_SDIO_CONF_REG = 0x3ff48074 + RTC_CNTL_XPD_SDIO_REG = (1 << 31) + RTC_CNTL_DREFH_SDIO_M = (3 << 29) + RTC_CNTL_DREFM_SDIO_M = (3 << 27) + RTC_CNTL_DREFL_SDIO_M = (3 << 25) + # RTC_CNTL_SDIO_TIEH = (1 << 23) # not used here, setting TIEH=1 would set 3.3V output, not safe for esptool.py to do + RTC_CNTL_SDIO_FORCE = (1 << 22) + RTC_CNTL_SDIO_PD_EN = (1 << 21) + + reg_val = RTC_CNTL_SDIO_FORCE # override efuse setting + reg_val |= RTC_CNTL_SDIO_PD_EN + if new_voltage != "OFF": + reg_val |= RTC_CNTL_XPD_SDIO_REG # enable internal LDO + if new_voltage == "1.9V": + reg_val |= (RTC_CNTL_DREFH_SDIO_M | RTC_CNTL_DREFM_SDIO_M | RTC_CNTL_DREFL_SDIO_M) # boost voltage + self.write_reg(RTC_CNTL_SDIO_CONF_REG, reg_val) + print("VDDSDIO regulator set to %s" % new_voltage) + + +class ESP32StubLoader(ESP32ROM): + """ Access class for ESP32 stub loader, runs on top of ROM. + """ + FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c + STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM + IS_STUB = True + + def __init__(self, rom_loader): + self._port = rom_loader._port + self._trace_enabled = rom_loader._trace_enabled + self.flush_input() # resets _slip_reader + + +ESP32ROM.STUB_CLASS = ESP32StubLoader + + +class ESPBOOTLOADER(object): + """ These are constants related to software ESP bootloader, working with 'v2' image files """ + + # First byte of the "v2" application image + IMAGE_V2_MAGIC = 0xea + + # First 'segment' value in a "v2" application image, appears to be a constant version value? + IMAGE_V2_SEGMENT = 4 + + +def LoadFirmwareImage(chip, filename): + """ Load a firmware image. Can be for ESP8266 or ESP32. ESP8266 images will be examined to determine if they are + original ROM firmware images (ESP8266ROMFirmwareImage) or "v2" OTA bootloader images. + + Returns a BaseFirmwareImage subclass, either ESP8266ROMFirmwareImage (v1) or ESP8266V2FirmwareImage (v2). + """ + with open(filename, 'rb') as f: + if chip.lower() == 'esp32': + return ESP32FirmwareImage(f) + else: # Otherwise, ESP8266 so look at magic to determine the image type + magic = ord(f.read(1)) + f.seek(0) + if magic == ESPLoader.ESP_IMAGE_MAGIC: + return ESP8266ROMFirmwareImage(f) + elif magic == ESPBOOTLOADER.IMAGE_V2_MAGIC: + return ESP8266V2FirmwareImage(f) + else: + raise FatalError("Invalid image magic number: %d" % magic) + + +class ImageSegment(object): + """ Wrapper class for a segment in an ESP image + (very similar to a section in an ELFImage also) """ + def __init__(self, addr, data, file_offs=None): + self.addr = addr + self.data = data + self.file_offs = file_offs + self.include_in_checksum = True + self.pad_to_alignment(4) # pad all ImageSegments to at least 4 bytes length + + def copy_with_new_addr(self, new_addr): + """ Return a new ImageSegment with same data, but mapped at + a new address. """ + return ImageSegment(new_addr, self.data, 0) + + def split_image(self, split_len): + """ Return a new ImageSegment which splits "split_len" bytes + from the beginning of the data. Remaining bytes are kept in + this segment object (and the start address is adjusted to match.) """ + result = copy.copy(self) + result.data = self.data[:split_len] + self.data = self.data[split_len:] + self.addr += split_len + self.file_offs = None + result.file_offs = None + return result + + def __repr__(self): + r = "len 0x%05x load 0x%08x" % (len(self.data), self.addr) + if self.file_offs is not None: + r += " file_offs 0x%08x" % (self.file_offs) + return r + + def pad_to_alignment(self, alignment): + self.data = pad_to(self.data, alignment, b'\x00') + + +class ELFSection(ImageSegment): + """ Wrapper class for a section in an ELF image, has a section + name as well as the common properties of an ImageSegment. """ + def __init__(self, name, addr, data): + super(ELFSection, self).__init__(addr, data) + self.name = name.decode("utf-8") + + def __repr__(self): + return "%s %s" % (self.name, super(ELFSection, self).__repr__()) + + +class BaseFirmwareImage(object): + SEG_HEADER_LEN = 8 + + """ Base class with common firmware image functions """ + def __init__(self): + self.segments = [] + self.entrypoint = 0 + + def load_common_header(self, load_file, expected_magic): + (magic, segments, self.flash_mode, self.flash_size_freq, self.entrypoint) = struct.unpack(' 16: + raise FatalError('Invalid firmware image magic=%d segments=%d' % (magic, segments)) + return segments + + def load_segment(self, f, is_irom_segment=False): + """ Load the next segment from the image file """ + file_offs = f.tell() + (offset, size) = struct.unpack(' 0x40200000 or offset < 0x3ffe0000 or size > 65536: + print('WARNING: Suspicious segment 0x%x, length %d' % (offset, size)) + + def save_segment(self, f, segment, checksum=None): + """ Save the next segment to the image file, return next checksum value if provided """ + f.write(struct.pack(' 0: + if len(irom_segments) != 1: + raise FatalError('Found %d segments that could be irom0. Bad ELF file?' % len(irom_segments)) + return irom_segments[0] + return None + + def get_non_irom_segments(self): + irom_segment = self.get_irom_segment() + return [s for s in self.segments if s != irom_segment] + + +class ESP8266ROMFirmwareImage(BaseFirmwareImage): + """ 'Version 1' firmware image, segments loaded directly by the ROM bootloader. """ + + ROM_LOADER = ESP8266ROM + + def __init__(self, load_file=None): + super(ESP8266ROMFirmwareImage, self).__init__() + self.flash_mode = 0 + self.flash_size_freq = 0 + self.version = 1 + + if load_file is not None: + segments = self.load_common_header(load_file, ESPLoader.ESP_IMAGE_MAGIC) + + for _ in range(segments): + self.load_segment(load_file) + self.checksum = self.read_checksum(load_file) + + def default_output_name(self, input_file): + """ Derive a default output name from the ELF name. """ + return input_file + '-' + + def save(self, basename): + """ Save a set of V1 images for flashing. Parameter is a base filename. """ + # IROM data goes in its own plain binary file + irom_segment = self.get_irom_segment() + if irom_segment is not None: + with open("%s0x%05x.bin" % (basename, irom_segment.addr - ESP8266ROM.IROM_MAP_START), "wb") as f: + f.write(irom_segment.data) + + # everything but IROM goes at 0x00000 in an image file + normal_segments = self.get_non_irom_segments() + with open("%s0x00000.bin" % basename, 'wb') as f: + self.write_common_header(f, normal_segments) + checksum = ESPLoader.ESP_CHECKSUM_MAGIC + for segment in normal_segments: + checksum = self.save_segment(f, segment, checksum) + self.append_checksum(f, checksum) + + +class ESP8266V2FirmwareImage(BaseFirmwareImage): + """ 'Version 2' firmware image, segments loaded by software bootloader stub + (ie Espressif bootloader or rboot) + """ + + ROM_LOADER = ESP8266ROM + + def __init__(self, load_file=None): + super(ESP8266V2FirmwareImage, self).__init__() + self.version = 2 + if load_file is not None: + segments = self.load_common_header(load_file, ESPBOOTLOADER.IMAGE_V2_MAGIC) + if segments != ESPBOOTLOADER.IMAGE_V2_SEGMENT: + # segment count is not really segment count here, but we expect to see '4' + print('Warning: V2 header has unexpected "segment" count %d (usually 4)' % segments) + + # irom segment comes before the second header + # + # the file is saved in the image with a zero load address + # in the header, so we need to calculate a load address + irom_segment = self.load_segment(load_file, True) + irom_segment.addr = 0 # for actual mapped addr, add ESP8266ROM.IROM_MAP_START + flashing_addr + 8 + irom_segment.include_in_checksum = False + + first_flash_mode = self.flash_mode + first_flash_size_freq = self.flash_size_freq + first_entrypoint = self.entrypoint + # load the second header + + segments = self.load_common_header(load_file, ESPLoader.ESP_IMAGE_MAGIC) + + if first_flash_mode != self.flash_mode: + print('WARNING: Flash mode value in first header (0x%02x) disagrees with second (0x%02x). Using second value.' + % (first_flash_mode, self.flash_mode)) + if first_flash_size_freq != self.flash_size_freq: + print('WARNING: Flash size/freq value in first header (0x%02x) disagrees with second (0x%02x). Using second value.' + % (first_flash_size_freq, self.flash_size_freq)) + if first_entrypoint != self.entrypoint: + print('WARNING: Entrypoint address in first header (0x%08x) disagrees with second header (0x%08x). Using second value.' + % (first_entrypoint, self.entrypoint)) + + # load all the usual segments + for _ in range(segments): + self.load_segment(load_file) + self.checksum = self.read_checksum(load_file) + + def default_output_name(self, input_file): + """ Derive a default output name from the ELF name. """ + irom_segment = self.get_irom_segment() + if irom_segment is not None: + irom_offs = irom_segment.addr - ESP8266ROM.IROM_MAP_START + else: + irom_offs = 0 + return "%s-0x%05x.bin" % (os.path.splitext(input_file)[0], + irom_offs & ~(ESPLoader.FLASH_SECTOR_SIZE - 1)) + + def save(self, filename): + with open(filename, 'wb') as f: + # Save first header for irom0 segment + f.write(struct.pack(b' 0: + last_addr = flash_segments[0].addr + #print('%x' % last_addr) + for segment in flash_segments[1:]: + if segment.addr // IROM_ALIGN == last_addr // IROM_ALIGN: + raise FatalError(("Segment loaded at 0x%08x lands in same 64KB flash mapping as segment loaded at 0x%08x. " + + "Can't generate binary. Suggest changing linker script or ELF to merge sections.") % + (segment.addr, last_addr)) + last_addr = segment.addr + print('%x' % last_addr) + + def get_alignment_data_needed(segment): + # Actual alignment (in data bytes) required for a segment header: positioned so that + # after we write the next 8 byte header, file_offs % IROM_ALIGN == segment.addr % IROM_ALIGN + # + # (this is because the segment's vaddr may not be IROM_ALIGNed, more likely is aligned + # IROM_ALIGN+0x18 to account for the binary file header + align_past = (segment.addr % IROM_ALIGN) - self.SEG_HEADER_LEN + pad_len = (IROM_ALIGN - (f.tell() % IROM_ALIGN)) + align_past + if pad_len == 0 or pad_len == IROM_ALIGN: + return 0 # already aligned + + # subtract SEG_HEADER_LEN a second time, as the padding block has a header as well + pad_len -= self.SEG_HEADER_LEN + if pad_len < 0: + pad_len += IROM_ALIGN + return pad_len + + # try to fit each flash segment on a 64kB aligned boundary + # by padding with parts of the non-flash segments... + while len(flash_segments) > 0: + segment = flash_segments[0] + pad_len = 0 + #get_alignment_data_needed(segment) + if pad_len > 0: # need to pad + #if len(ram_segments) > 0 and pad_len > self.SEG_HEADER_LEN: + # pad_segment = ram_segments[0].split_image(pad_len) + # if len(ram_segments[0].data) == 0: + # ram_segments.pop(0) + #else: + pad_segment = ImageSegment(0, b'\x00' * pad_len, f.tell()) + print('qqq %x' % pad_segment.addr) + checksum = self.save_segment(f, pad_segment, checksum) + total_segments += 1 + else: + # write the flash segment + #assert (f.tell() + 8) % IROM_ALIGN == segment.addr % IROM_ALIGN + checksum = self.save_segment(f, segment, checksum) + flash_segments.pop(0) + total_segments += 1 + + # flash segments all written, so write any remaining RAM segments + for segment in ram_segments: + checksum = self.save_segment(f, segment, checksum) + total_segments += 1 + + # done writing segments + self.append_checksum(f, checksum) + # kinda hacky: go back to the initial header and write the new segment count + # that includes padding segments. This header is not checksummed + image_length = f.tell() + f.seek(1) + try: + f.write(chr(total_segments)) + except TypeError: # Python 3 + f.write(bytes([total_segments])) + + if self.append_digest: + # calculate the SHA256 of the whole file and append it + f.seek(0) + digest = hashlib.sha256() + digest.update(f.read(image_length)) + f.write(digest.digest()) + + with open(filename, 'wb') as real_file: + real_file.write(f.getvalue()) + + def load_extended_header(self, load_file): + def split_byte(n): + return (n & 0x0F, (n >> 4) & 0x0F) + + fields = list(struct.unpack(self.EXTENDED_HEADER_STRUCT_FMT, load_file.read(16))) + + self.wp_pin = fields[0] + + # SPI pin drive stengths are two per byte + self.clk_drv, self.q_drv = split_byte(fields[1]) + self.d_drv, self.cs_drv = split_byte(fields[2]) + self.hd_drv, self.wp_drv = split_byte(fields[3]) + + if fields[15] in [0, 1]: + self.append_digest = (fields[15] == 1) + else: + raise RuntimeError("Invalid value for append_digest field (0x%02x). Should be 0 or 1.", fields[15]) + + # remaining fields in the middle should all be zero + if any(f for f in fields[4:15] if f != 0): + print("Warning: some reserved header fields have non-zero values. This image may be from a newer esptool.py?") + + def save_extended_header(self, save_file): + def join_byte(ln,hn): + return (ln & 0x0F) + ((hn & 0x0F) << 4) + + append_digest = 1 if self.append_digest else 0 + + fields = [self.wp_pin, + join_byte(self.clk_drv, self.q_drv), + join_byte(self.d_drv, self.cs_drv), + join_byte(self.hd_drv, self.wp_drv)] + fields += [0] * 11 + fields += [append_digest] + + packed = struct.pack(self.EXTENDED_HEADER_STRUCT_FMT, *fields) + save_file.write(packed) + +# Backwards compatibility for previous API, remove in esptool.py V3 +ESPFirmwareImage = ESP8266ROMFirmwareImage +OTAFirmwareImage = ESP8266V2FirmwareImage + + +def esp8266_crc32(data): + """ + CRC32 algorithm used by 8266 SDK bootloader (and gen_appbin.py). + """ + crc = binascii.crc32(data, 0) & 0xFFFFFFFF + if crc & 0x80000000: + return crc ^ 0xFFFFFFFF + else: + return crc + 1 + + +class ESP32FirmwareImage(BaseFirmwareImage): + """ ESP32 firmware image is very similar to V1 ESP8266 image, + except with an additional 16 byte reserved header at top of image, + and because of new flash mapping capabilities the flash-mapped regions + can be placed in the normal image (just @ 64kB padded offsets). + """ + + ROM_LOADER = ESP32ROM + + # ROM bootloader will read the wp_pin field if SPI flash + # pins are remapped via flash. IDF actually enables QIO only + # from software bootloader, so this can be ignored. But needs + # to be set to this value so ROM bootloader will skip it. + WP_PIN_DISABLED = 0xEE + + EXTENDED_HEADER_STRUCT_FMT = "B" * 16 + + def __init__(self, load_file=None): + super(ESP32FirmwareImage, self).__init__() + self.flash_mode = 0 + self.flash_size_freq = 0 + self.version = 1 + self.wp_pin = self.WP_PIN_DISABLED + # SPI pin drive levels + self.clk_drv = 0 + self.q_drv = 0 + self.d_drv = 0 + self.cs_drv = 0 + self.hd_drv = 0 + self.wp_drv = 0 + + self.append_digest = True + + if load_file is not None: + start = load_file.tell() + + segments = self.load_common_header(load_file, ESPLoader.ESP_IMAGE_MAGIC) + self.load_extended_header(load_file) + + for _ in range(segments): + self.load_segment(load_file) + self.checksum = self.read_checksum(load_file) + + if self.append_digest: + end = load_file.tell() + self.stored_digest = load_file.read(32) + load_file.seek(start) + calc_digest = hashlib.sha256() + calc_digest.update(load_file.read(end - start)) + self.calc_digest = calc_digest.digest() # TODO: decide what to do here? + + def is_flash_addr(self, addr): + return (ESP32ROM.IROM_MAP_START <= addr < ESP32ROM.IROM_MAP_END) \ + or (ESP32ROM.DROM_MAP_START <= addr < ESP32ROM.DROM_MAP_END) + + def default_output_name(self, input_file): + """ Derive a default output name from the ELF name. """ + return "%s.bin" % (os.path.splitext(input_file)[0]) + + def warn_if_unusual_segment(self, offset, size, is_irom_segment): + pass # TODO: add warnings for ESP32 segment offset/size combinations that are wrong + + def save(self, filename): + total_segments = 0 + with io.BytesIO() as f: # write file to memory first + self.write_common_header(f, self.segments) + + # first 4 bytes of header are read by ROM bootloader for SPI + # config, but currently unused + self.save_extended_header(f) + + checksum = ESPLoader.ESP_CHECKSUM_MAGIC + + # split segments into flash-mapped vs ram-loaded, and take copies so we can mutate them + flash_segments = [copy.deepcopy(s) for s in sorted(self.segments, key=lambda s:s.addr) if self.is_flash_addr(s.addr)] + ram_segments = [copy.deepcopy(s) for s in sorted(self.segments, key=lambda s:s.addr) if not self.is_flash_addr(s.addr)] + + IROM_ALIGN = 65536 + + # check for multiple ELF sections that are mapped in the same flash mapping region. + # this is usually a sign of a broken linker script, but if you have a legitimate + # use case then let us know (we can merge segments here, but as a rule you probably + # want to merge them in your linker script.) + if len(flash_segments) > 0: + last_addr = flash_segments[0].addr + for segment in flash_segments[1:]: + if segment.addr // IROM_ALIGN == last_addr // IROM_ALIGN: + raise FatalError(("Segment loaded at 0x%08x lands in same 64KB flash mapping as segment loaded at 0x%08x. " + + "Can't generate binary. Suggest changing linker script or ELF to merge sections.") % + (segment.addr, last_addr)) + last_addr = segment.addr + + def get_alignment_data_needed(segment): + # Actual alignment (in data bytes) required for a segment header: positioned so that + # after we write the next 8 byte header, file_offs % IROM_ALIGN == segment.addr % IROM_ALIGN + # + # (this is because the segment's vaddr may not be IROM_ALIGNed, more likely is aligned + # IROM_ALIGN+0x18 to account for the binary file header + align_past = (segment.addr % IROM_ALIGN) - self.SEG_HEADER_LEN + pad_len = (IROM_ALIGN - (f.tell() % IROM_ALIGN)) + align_past + if pad_len == 0 or pad_len == IROM_ALIGN: + return 0 # already aligned + + # subtract SEG_HEADER_LEN a second time, as the padding block has a header as well + pad_len -= self.SEG_HEADER_LEN + if pad_len < 0: + pad_len += IROM_ALIGN + return pad_len + + # try to fit each flash segment on a 64kB aligned boundary + # by padding with parts of the non-flash segments... + while len(flash_segments) > 0: + segment = flash_segments[0] + pad_len = get_alignment_data_needed(segment) + if pad_len > 0: # need to pad + if len(ram_segments) > 0 and pad_len > self.SEG_HEADER_LEN: + pad_segment = ram_segments[0].split_image(pad_len) + if len(ram_segments[0].data) == 0: + ram_segments.pop(0) + else: + pad_segment = ImageSegment(0, b'\x00' * pad_len, f.tell()) + checksum = self.save_segment(f, pad_segment, checksum) + total_segments += 1 + else: + # write the flash segment + assert (f.tell() + 8) % IROM_ALIGN == segment.addr % IROM_ALIGN + checksum = self.save_segment(f, segment, checksum) + flash_segments.pop(0) + total_segments += 1 + + # flash segments all written, so write any remaining RAM segments + for segment in ram_segments: + checksum = self.save_segment(f, segment, checksum) + total_segments += 1 + + # done writing segments + self.append_checksum(f, checksum) + # kinda hacky: go back to the initial header and write the new segment count + # that includes padding segments. This header is not checksummed + image_length = f.tell() + f.seek(1) + try: + f.write(chr(total_segments)) + except TypeError: # Python 3 + f.write(bytes([total_segments])) + + if self.append_digest: + # calculate the SHA256 of the whole file and append it + f.seek(0) + digest = hashlib.sha256() + digest.update(f.read(image_length)) + f.write(digest.digest()) + + with open(filename, 'wb') as real_file: + real_file.write(f.getvalue()) + + def load_extended_header(self, load_file): + def split_byte(n): + return (n & 0x0F, (n >> 4) & 0x0F) + + fields = list(struct.unpack(self.EXTENDED_HEADER_STRUCT_FMT, load_file.read(16))) + + self.wp_pin = fields[0] + + # SPI pin drive stengths are two per byte + self.clk_drv, self.q_drv = split_byte(fields[1]) + self.d_drv, self.cs_drv = split_byte(fields[2]) + self.hd_drv, self.wp_drv = split_byte(fields[3]) + + if fields[15] in [0, 1]: + self.append_digest = (fields[15] == 1) + else: + raise RuntimeError("Invalid value for append_digest field (0x%02x). Should be 0 or 1.", fields[15]) + + # remaining fields in the middle should all be zero + if any(f for f in fields[4:15] if f != 0): + print("Warning: some reserved header fields have non-zero values. This image may be from a newer esptool.py?") + + def save_extended_header(self, save_file): + def join_byte(ln,hn): + return (ln & 0x0F) + ((hn & 0x0F) << 4) + + append_digest = 1 if self.append_digest else 0 + + fields = [self.wp_pin, + join_byte(self.clk_drv, self.q_drv), + join_byte(self.d_drv, self.cs_drv), + join_byte(self.hd_drv, self.wp_drv)] + fields += [0] * 11 + fields += [append_digest] + + packed = struct.pack(self.EXTENDED_HEADER_STRUCT_FMT, *fields) + save_file.write(packed) + + +class ELFFile(object): + SEC_TYPE_PROGBITS = 0x01 + SEC_TYPE_STRTAB = 0x03 + + LEN_SEC_HEADER = 0x28 + + def __init__(self, name): + # Load sections from the ELF file + self.name = name + with open(self.name, 'rb') as f: + self._read_elf_file(f) + + def get_section(self, section_name): + for s in self.sections: + if s.name == section_name: + return s + raise ValueError("No section %s in ELF file" % section_name) + + def _read_elf_file(self, f): + # read the ELF file header + LEN_FILE_HEADER = 0x34 + try: + (ident,_type,machine,_version, + self.entrypoint,_phoff,shoff,_flags, + _ehsize, _phentsize,_phnum, shentsize, + shnum,shstrndx) = struct.unpack("<16sHHLLLLLHHHHHH", f.read(LEN_FILE_HEADER)) + except struct.error as e: + raise FatalError("Failed to read a valid ELF header from %s: %s" % (self.name, e)) + + if byte(ident, 0) != 0x7f or ident[1:4] != b'ELF': + raise FatalError("%s has invalid ELF magic header" % self.name) + if machine != 0x5e: + raise FatalError("%s does not appear to be an Xtensa ELF file. e_machine=%04x" % (self.name, machine)) + if shentsize != self.LEN_SEC_HEADER: + raise FatalError("%s has unexpected section header entry size 0x%x (not 0x28)" % (self.name, shentsize, self.LEN_SEC_HEADER)) + if shnum == 0: + raise FatalError("%s has 0 section headers" % (self.name)) + self._read_sections(f, shoff, shnum, shstrndx) + + def _read_sections(self, f, section_header_offs, section_header_count, shstrndx): + f.seek(section_header_offs) + len_bytes = section_header_count * self.LEN_SEC_HEADER + section_header = f.read(len_bytes) + if len(section_header) == 0: + raise FatalError("No section header found at offset %04x in ELF file." % section_header_offs) + if len(section_header) != (len_bytes): + raise FatalError("Only read 0x%x bytes from section header (expected 0x%x.) Truncated ELF file?" % (len(section_header), len_bytes)) + + # walk through the section header and extract all sections + section_header_offsets = range(0, len(section_header), self.LEN_SEC_HEADER) + + def read_section_header(offs): + name_offs,sec_type,_flags,lma,sec_offs,size = struct.unpack_from(" 16 bytes) will be + printed as separately indented lines, with ASCII decoding at the end + of each line. + """ + def __init__(self, binary_string, auto_split=True): + self._s = binary_string + self._auto_split = auto_split + + def __str__(self): + if self._auto_split and len(self._s) > 16: + result = "" + s = self._s + while len(s) > 0: + line = s[:16] + ascii_line = "".join(c if (c == ' ' or (c in string.printable and c not in string.whitespace)) + else '.' for c in line.decode('ascii', 'replace')) + s = s[16:] + result += "\n %-16s %-16s | %s" % (hexify(line[:8], False), hexify(line[8:], False), ascii_line) + return result + else: + return hexify(self._s, False) + + +def pad_to(data, alignment, pad_character=b'\xFF'): + """ Pad to the next alignment boundary """ + pad_mod = len(data) % alignment + if pad_mod != 0: + data += pad_character * (alignment - pad_mod) + return data + + +class FatalError(RuntimeError): + """ + Wrapper class for runtime errors that aren't caused by internal bugs, but by + ESP8266 responses or input content. + """ + def __init__(self, message): + RuntimeError.__init__(self, message) + + @staticmethod + def WithResult(message, result): + """ + Return a fatal error object that appends the hex values of + 'result' as a string formatted argument. + """ + message += " (result was %s)" % hexify(result) + return FatalError(message) + + +class NotImplementedInROMError(FatalError): + """ + Wrapper class for the error thrown when a particular ESP bootloader function + is not implemented in the ROM bootloader. + """ + def __init__(self, bootloader, func): + FatalError.__init__(self, "%s ROM does not support function %s." % (bootloader.CHIP_NAME, func.__name__)) + + +class NotSupportedError(FatalError): + def __init__(self, esp, function_name): + FatalError.__init__(self, "Function %s is not supported for %s." % (function_name, esp.CHIP_NAME)) + +# "Operation" commands, executable at command line. One function each +# +# Each function takes either two args (, ) or a single +# argument. + + +def load_ram(esp, args): + image = LoadFirmwareImage(esp.CHIP_NAME, args.filename) + + print('RAM boot...') + for seg in image.segments: + size = len(seg.data) + print('Downloading %d bytes at %08x...' % (size, seg.addr), end=' ') + sys.stdout.flush() + esp.mem_begin(size, div_roundup(size, esp.ESP_RAM_BLOCK), esp.ESP_RAM_BLOCK, seg.addr) + + seq = 0 + while len(seg.data) > 0: + esp.mem_block(seg.data[0:esp.ESP_RAM_BLOCK], seq) + seg.data = seg.data[esp.ESP_RAM_BLOCK:] + seq += 1 + print('done!') + + print('All segments done, executing at %08x' % image.entrypoint) + esp.mem_finish(image.entrypoint) + + +def read_mem(esp, args): + print('0x%08x = 0x%08x' % (args.address, esp.read_reg(args.address))) + + +def write_mem(esp, args): + esp.write_reg(args.address, args.value, args.mask, 0) + print('Wrote %08x, mask %08x to %08x' % (args.value, args.mask, args.address)) + + +def dump_mem(esp, args): + f = open(args.filename, 'wb') + for i in range(args.size // 4): + d = esp.read_reg(args.address + (i * 4)) + f.write(struct.pack(b'> 16 + args.flash_size = DETECTED_FLASH_SIZES.get(size_id) + if args.flash_size is None: + print('Warning: Could not auto-detect Flash size (FlashID=0x%x, SizeID=0x%x), defaulting to 4MB' % (flash_id, size_id)) + args.flash_size = '4MB' + else: + print('Auto-detected Flash size:', args.flash_size) + + +def _update_image_flash_params(esp, address, args, image): + """ Modify the flash mode & size bytes if this looks like an executable bootloader image """ + if len(image) < 8: + return image # not long enough to be a bootloader image + + # unpack the (potential) image header + magic, _, flash_mode, flash_size_freq = struct.unpack("BBBB", image[:4]) + if address != esp.BOOTLOADER_FLASH_OFFSET or magic != esp.ESP_IMAGE_MAGIC: + return image # not flashing a bootloader, so don't modify this + + if args.flash_mode != 'keep': + flash_mode = {'qio':0, 'qout':1, 'dio':2, 'dout': 3}[args.flash_mode] + + flash_freq = flash_size_freq & 0x0F + if args.flash_freq != 'keep': + flash_freq = {'40m':0, '26m':1, '20m':2, '80m': 0xf}[args.flash_freq] + + flash_size = flash_size_freq & 0xF0 + if args.flash_size != 'keep': + flash_size = esp.parse_flash_size_arg(args.flash_size) + + flash_params = struct.pack(b'BB', flash_mode, flash_size + flash_freq) + if flash_params != image[2:4]: + print('Flash params set to 0x%04x' % struct.unpack(">H", flash_params)) + image = image[0:2] + flash_params + image[4:] + return image + + +def write_flash(esp, args): + # set args.compress based on default behaviour: + # -> if either --compress or --no-compress is set, honour that + # -> otherwise, set --compress unless --no-stub is set + if args.compress is None and not args.no_compress: + args.compress = not args.no_stub + + # verify file sizes fit in flash + flash_end = flash_size_bytes(args.flash_size) + for address, argfile in args.addr_filename: + argfile.seek(0,2) # seek to end + if address + argfile.tell() > flash_end: + raise FatalError(("File %s (length %d) at offset %d will not fit in %d bytes of flash. " + + "Use --flash-size argument, or change flashing address.") + % (argfile.name, argfile.tell(), address, flash_end)) + argfile.seek(0) + + for address, argfile in args.addr_filename: + if args.no_stub: + print('Erasing flash...') + image = pad_to(argfile.read(), 4) + if len(image) == 0: + print('WARNING: File %s is empty' % argfile.name) + continue + image = _update_image_flash_params(esp, address, args, image) + calcmd5 = hashlib.md5(image).hexdigest() + uncsize = len(image) + if args.compress: + uncimage = image + image = zlib.compress(uncimage, 9) + ratio = uncsize / len(image) + blocks = esp.flash_defl_begin(uncsize, len(image), address) + else: + ratio = 1.0 + blocks = esp.flash_begin(uncsize, address) + argfile.seek(0) # in case we need it again + seq = 0 + written = 0 + t = time.time() + while len(image) > 0: + print('\rWriting at 0x%08x... (%d %%)' % (address + seq * esp.FLASH_WRITE_SIZE, 100 * (seq + 1) // blocks), end='') + sys.stdout.flush() + block = image[0:esp.FLASH_WRITE_SIZE] + if args.compress: + esp.flash_defl_block(block, seq, timeout=DEFAULT_TIMEOUT * ratio) + else: + # Pad the last block + block = block + b'\xff' * (esp.FLASH_WRITE_SIZE - len(block)) + esp.flash_block(block, seq) + image = image[esp.FLASH_WRITE_SIZE:] + seq += 1 + written += len(block) + t = time.time() - t + speed_msg = "" + if args.compress: + if t > 0.0: + speed_msg = " (effective %.1f kbit/s)" % (uncsize / t * 8 / 1000) + print('\rWrote %d bytes (%d compressed) at 0x%08x in %.1f seconds%s...' % (uncsize, written, address, t, speed_msg)) + else: + if t > 0.0: + speed_msg = " (%.1f kbit/s)" % (written / t * 8 / 1000) + print('\rWrote %d bytes at 0x%08x in %.1f seconds%s...' % (written, address, t, speed_msg)) + try: + res = esp.flash_md5sum(address, uncsize) + if res != calcmd5: + print('File md5: %s' % calcmd5) + print('Flash md5: %s' % res) + print('MD5 of 0xFF is %s' % (hashlib.md5(b'\xFF' * uncsize).hexdigest())) + raise FatalError("MD5 of file does not match data in flash!") + else: + print('Hash of data verified.') + except NotImplementedInROMError: + pass + + print('\nLeaving...') + + if esp.IS_STUB: + # skip sending flash_finish to ROM loader here, + # as it causes the loader to exit and run user code + esp.flash_begin(0, 0) + if args.compress: + esp.flash_defl_finish(False) + else: + esp.flash_finish(False) + + if args.verify: + print('Verifying just-written flash...') + print('(This option is deprecated, flash contents are now always read back after flashing.)') + verify_flash(esp, args) + + +def image_info(args): + image = LoadFirmwareImage(args.chip, args.filename) + print('Image version: %d' % image.version) + print('Entry point: %08x' % image.entrypoint if image.entrypoint != 0 else 'Entry point not set') + print('%d segments' % len(image.segments)) + print + idx = 0 + for seg in image.segments: + idx += 1 + print('Segment %d: %r' % (idx, seg)) + calc_checksum = image.calculate_checksum() + print('Checksum: %02x (%s)' % (image.checksum, + 'valid' if image.checksum == calc_checksum else 'invalid - calculated %02x' % calc_checksum)) + try: + digest_msg = 'Not appended' + if image.append_digest: + is_valid = image.stored_digest == image.calc_digest + digest_msg = "%s (%s)" % (hexify(image.calc_digest).lower(), + "valid" if is_valid else "invalid") + print('Validation Hash: %s' % digest_msg) + except AttributeError: + pass # ESP8266 image has no append_digest field + + +def make_image(args): + image = ESP8266ROMFirmwareImage() + if len(args.segfile) == 0: + raise FatalError('No segments specified') + if len(args.segfile) != len(args.segaddr): + raise FatalError('Number of specified files does not match number of specified addresses') + for (seg, addr) in zip(args.segfile, args.segaddr): + data = open(seg, 'rb').read() + image.segments.append(ImageSegment(addr, data)) + image.entrypoint = args.entrypoint + image.save(args.output) + + +def elf2image(args): + e = ELFFile(args.input) + if args.chip == 'auto': # Default to ESP8266 for backwards compatibility + print("Creating image for ESP8266...") + args.chip = 'esp8266' + + if args.chip == 'esp32': + image = ESP32FirmwareImage() + elif args.version == '1': # ESP8266 + image = ESP8266ROMFirmwareImage() + elif args.version == '2': # ESP8266 + image = ESP8266V2FirmwareImage() + else: + image = ESP8266V3FirmwareImage() + image.entrypoint = e.entrypoint + image.segments = e.sections # ELFSection is a subclass of ImageSegment + image.flash_mode = {'qio':0, 'qout':1, 'dio':2, 'dout': 3}[args.flash_mode] + image.flash_size_freq = image.ROM_LOADER.FLASH_SIZES[args.flash_size] + image.flash_size_freq += {'40m':0, '26m':1, '20m':2, '80m': 0xf}[args.flash_freq] + + if args.output is None: + args.output = image.default_output_name(args.input) + image.save(args.output) + + +def read_mac(esp, args): + mac = esp.read_mac() + + def print_mac(label, mac): + print('%s: %s' % (label, ':'.join(map(lambda x: '%02x' % x, mac)))) + print_mac("MAC", mac) + + +def chip_id(esp, args): + try: + chipid = esp.chip_id() + print('Chip ID: 0x%08x' % chipid) + except NotSupportedError: + print('Warning: %s has no Chip ID. Reading MAC instead.' % esp.CHIP_NAME) + read_mac(esp, args) + + +def erase_flash(esp, args): + print('Erasing flash (this may take a while)...') + t = time.time() + esp.erase_flash() + print('Chip erase completed successfully in %.1fs' % (time.time() - t)) + + +def erase_region(esp, args): + print('Erasing region (may be slow depending on size)...') + t = time.time() + esp.erase_region(args.address, args.size) + print('Erase completed successfully in %.1f seconds.' % (time.time() - t)) + + +def run(esp, args): + esp.run() + + +def flash_id(esp, args): + flash_id = esp.flash_id() + print('Manufacturer: %02x' % (flash_id & 0xff)) + flid_lowbyte = (flash_id >> 16) & 0xFF + print('Device: %02x%02x' % ((flash_id >> 8) & 0xff, flid_lowbyte)) + print('Detected flash size: %s' % (DETECTED_FLASH_SIZES.get(flid_lowbyte, "Unknown"))) + + +def read_flash(esp, args): + if args.no_progress: + flash_progress = None + else: + def flash_progress(progress, length): + msg = '%d (%d %%)' % (progress, progress * 100.0 / length) + padding = '\b' * len(msg) + if progress == length: + padding = '\n' + sys.stdout.write(msg + padding) + sys.stdout.flush() + t = time.time() + data = esp.read_flash(args.address, args.size, flash_progress) + t = time.time() - t + print('\rRead %d bytes at 0x%x in %.1f seconds (%.1f kbit/s)...' + % (len(data), args.address, t, len(data) / t * 8 / 1000)) + open(args.filename, 'wb').write(data) + + +def verify_flash(esp, args): + differences = False + + for address, argfile in args.addr_filename: + image = pad_to(argfile.read(), 4) + argfile.seek(0) # rewind in case we need it again + + image = _update_image_flash_params(esp, address, args, image) + + image_size = len(image) + print('Verifying 0x%x (%d) bytes @ 0x%08x in flash against %s...' % (image_size, image_size, address, argfile.name)) + # Try digest first, only read if there are differences. + digest = esp.flash_md5sum(address, image_size) + expected_digest = hashlib.md5(image).hexdigest() + if digest == expected_digest: + print('-- verify OK (digest matched)') + continue + else: + differences = True + if getattr(args, 'diff', 'no') != 'yes': + print('-- verify FAILED (digest mismatch)') + continue + + flash = esp.read_flash(address, image_size) + assert flash != image + diff = [i for i in range(image_size) if flash[i] != image[i]] + print('-- verify FAILED: %d differences, first @ 0x%08x' % (len(diff), address + diff[0])) + for d in diff: + flash_byte = flash[d] + image_byte = image[d] + if PYTHON2: + flash_byte = ord(flash_byte) + image_byte = ord(image_byte) + print(' %08x %02x %02x' % (address + d, flash_byte, image_byte)) + if differences: + raise FatalError("Verify failed.") + + +def read_flash_status(esp, args): + print('Status value: 0x%04x' % esp.read_status(args.bytes)) + + +def write_flash_status(esp, args): + fmt = "0x%%0%dx" % (args.bytes * 2) + args.value = args.value & ((1 << (args.bytes * 8)) - 1) + print(('Initial flash status: ' + fmt) % esp.read_status(args.bytes)) + print(('Setting flash status: ' + fmt) % args.value) + esp.write_status(args.value, args.bytes, args.non_volatile) + print(('After flash status: ' + fmt) % esp.read_status(args.bytes)) + + +def version(args): + print(__version__) + +# +# End of operations functions +# + + +def main(): + parser = argparse.ArgumentParser(description='esptool.py v%s - ESP8266 ROM Bootloader Utility' % __version__, prog='esptool') + + parser.add_argument('--chip', '-c', + help='Target chip type', + choices=['auto', 'esp8266', 'esp32'], + default=os.environ.get('ESPTOOL_CHIP', 'auto')) + + parser.add_argument( + '--port', '-p', + help='Serial port device', + default=os.environ.get('ESPTOOL_PORT', None)) + + parser.add_argument( + '--baud', '-b', + help='Serial port baud rate used when flashing/reading', + type=arg_auto_int, + default=os.environ.get('ESPTOOL_BAUD', ESPLoader.ESP_ROM_BAUD)) + + parser.add_argument( + '--before', + help='What to do before connecting to the chip', + choices=['default_reset', 'no_reset', 'no_reset_no_sync'], + default=os.environ.get('ESPTOOL_BEFORE', 'default_reset')) + + parser.add_argument( + '--after', '-a', + help='What to do after esptool.py is finished', + choices=['hard_reset', 'soft_reset', 'no_reset'], + default=os.environ.get('ESPTOOL_AFTER', 'hard_reset')) + + parser.add_argument( + '--no-stub', + help="Disable launching the flasher stub, only talk to ROM bootloader. Some features will not be available.", + action='store_true') + + parser.add_argument( + '--trace', '-t', + help="Enable trace-level output of esptool.py interactions.", + action='store_true') + + parser.add_argument( + '--override-vddsdio', + help="Override ESP32 VDDSDIO internal voltage regulator (use with care)", + choices=ESP32ROM.OVERRIDE_VDDSDIO_CHOICES, + nargs='?') + + subparsers = parser.add_subparsers( + dest='operation', + help='Run esptool {command} -h for additional help') + + def add_spi_connection_arg(parent): + parent.add_argument('--spi-connection', '-sc', help='ESP32-only argument. Override default SPI Flash connection. ' + + 'Value can be SPI, HSPI or a comma-separated list of 5 I/O numbers to use for SPI flash (CLK,Q,D,HD,CS).', + action=SpiConnectionAction) + + parser_load_ram = subparsers.add_parser( + 'load_ram', + help='Download an image to RAM and execute') + parser_load_ram.add_argument('filename', help='Firmware image') + + parser_dump_mem = subparsers.add_parser( + 'dump_mem', + help='Dump arbitrary memory to disk') + parser_dump_mem.add_argument('address', help='Base address', type=arg_auto_int) + parser_dump_mem.add_argument('size', help='Size of region to dump', type=arg_auto_int) + parser_dump_mem.add_argument('filename', help='Name of binary dump') + + parser_read_mem = subparsers.add_parser( + 'read_mem', + help='Read arbitrary memory location') + parser_read_mem.add_argument('address', help='Address to read', type=arg_auto_int) + + parser_write_mem = subparsers.add_parser( + 'write_mem', + help='Read-modify-write to arbitrary memory location') + parser_write_mem.add_argument('address', help='Address to write', type=arg_auto_int) + parser_write_mem.add_argument('value', help='Value', type=arg_auto_int) + parser_write_mem.add_argument('mask', help='Mask of bits to write', type=arg_auto_int) + + def add_spi_flash_subparsers(parent, is_elf2image): + """ Add common parser arguments for SPI flash properties """ + extra_keep_args = [] if is_elf2image else ['keep'] + auto_detect = not is_elf2image + + parent.add_argument('--flash_freq', '-ff', help='SPI Flash frequency', + choices=extra_keep_args + ['40m', '26m', '20m', '80m'], + default=os.environ.get('ESPTOOL_FF', '40m' if is_elf2image else 'keep')) + parent.add_argument('--flash_mode', '-fm', help='SPI Flash mode', + choices=extra_keep_args + ['qio', 'qout', 'dio', 'dout'], + default=os.environ.get('ESPTOOL_FM', 'qio' if is_elf2image else 'keep')) + parent.add_argument('--flash_size', '-fs', help='SPI Flash size in MegaBytes (1MB, 2MB, 4MB, 8MB, 16M)' + ' plus ESP8266-only (256KB, 512KB, 2MB-c1, 4MB-c1)', + action=FlashSizeAction, auto_detect=auto_detect, + default=os.environ.get('ESPTOOL_FS', 'detect' if auto_detect else '1MB')) + add_spi_connection_arg(parent) + + parser_write_flash = subparsers.add_parser( + 'write_flash', + help='Write a binary blob to flash') + parser_write_flash.add_argument('addr_filename', metavar='
', help='Address followed by binary filename, separated by space', + action=AddrFilenamePairAction) + add_spi_flash_subparsers(parser_write_flash, is_elf2image=False) + parser_write_flash.add_argument('--no-progress', '-p', help='Suppress progress output', action="store_true") + parser_write_flash.add_argument('--verify', help='Verify just-written data on flash ' + + '(mostly superfluous, data is read back during flashing)', action='store_true') + compress_args = parser_write_flash.add_mutually_exclusive_group(required=False) + compress_args.add_argument('--compress', '-z', help='Compress data in transfer (default unless --no-stub is specified)',action="store_true", default=None) + compress_args.add_argument('--no-compress', '-u', help='Disable data compression during transfer (default if --no-stub is specified)',action="store_true") + + subparsers.add_parser( + 'run', + help='Run application code in flash') + + parser_image_info = subparsers.add_parser( + 'image_info', + help='Dump headers from an application image') + parser_image_info.add_argument('filename', help='Image file to parse') + + parser_make_image = subparsers.add_parser( + 'make_image', + help='Create an application image from binary files') + parser_make_image.add_argument('output', help='Output image file') + parser_make_image.add_argument('--segfile', '-f', action='append', help='Segment input file') + parser_make_image.add_argument('--segaddr', '-a', action='append', help='Segment base address', type=arg_auto_int) + parser_make_image.add_argument('--entrypoint', '-e', help='Address of entry point', type=arg_auto_int, default=0) + + parser_elf2image = subparsers.add_parser( + 'elf2image', + help='Create an application image from ELF file') + parser_elf2image.add_argument('input', help='Input ELF file') + parser_elf2image.add_argument('--output', '-o', help='Output filename prefix (for version 1 image), or filename (for version 2 single image)', type=str) + parser_elf2image.add_argument('--version', '-e', help='Output image version', choices=['1','2','3'], default='1') + + add_spi_flash_subparsers(parser_elf2image, is_elf2image=True) + + subparsers.add_parser( + 'read_mac', + help='Read MAC address from OTP ROM') + + subparsers.add_parser( + 'chip_id', + help='Read Chip ID from OTP ROM') + + parser_flash_id = subparsers.add_parser( + 'flash_id', + help='Read SPI flash manufacturer and device ID') + add_spi_connection_arg(parser_flash_id) + + parser_read_status = subparsers.add_parser( + 'read_flash_status', + help='Read SPI flash status register') + + add_spi_connection_arg(parser_read_status) + parser_read_status.add_argument('--bytes', help='Number of bytes to read (1-3)', type=int, choices=[1,2,3], default=2) + + parser_write_status = subparsers.add_parser( + 'write_flash_status', + help='Write SPI flash status register') + + add_spi_connection_arg(parser_write_status) + parser_write_status.add_argument('--non-volatile', help='Write non-volatile bits (use with caution)', action='store_true') + parser_write_status.add_argument('--bytes', help='Number of status bytes to write (1-3)', type=int, choices=[1,2,3], default=2) + parser_write_status.add_argument('value', help='New value', type=arg_auto_int) + + parser_read_flash = subparsers.add_parser( + 'read_flash', + help='Read SPI flash content') + add_spi_connection_arg(parser_read_flash) + parser_read_flash.add_argument('address', help='Start address', type=arg_auto_int) + parser_read_flash.add_argument('size', help='Size of region to dump', type=arg_auto_int) + parser_read_flash.add_argument('filename', help='Name of binary dump') + parser_read_flash.add_argument('--no-progress', '-p', help='Suppress progress output', action="store_true") + + parser_verify_flash = subparsers.add_parser( + 'verify_flash', + help='Verify a binary blob against flash') + parser_verify_flash.add_argument('addr_filename', help='Address and binary file to verify there, separated by space', + action=AddrFilenamePairAction) + parser_verify_flash.add_argument('--diff', '-d', help='Show differences', + choices=['no', 'yes'], default='no') + add_spi_flash_subparsers(parser_verify_flash, is_elf2image=False) + + parser_erase_flash = subparsers.add_parser( + 'erase_flash', + help='Perform Chip Erase on SPI flash') + add_spi_connection_arg(parser_erase_flash) + + parser_erase_region = subparsers.add_parser( + 'erase_region', + help='Erase a region of the flash') + add_spi_connection_arg(parser_erase_region) + parser_erase_region.add_argument('address', help='Start address (must be multiple of 4096)', type=arg_auto_int) + parser_erase_region.add_argument('size', help='Size of region to erase (must be multiple of 4096)', type=arg_auto_int) + + subparsers.add_parser( + 'version', help='Print esptool version') + + # internal sanity check - every operation matches a module function of the same name + for operation in subparsers.choices.keys(): + assert operation in globals(), "%s should be a module function" % operation + + expand_file_arguments() + + args = parser.parse_args() + + print('esptool.py v%s' % __version__) + + # operation function can take 1 arg (args), 2 args (esp, arg) + # or be a member function of the ESPLoader class. + + if args.operation is None: + parser.print_help() + sys.exit(1) + + operation_func = globals()[args.operation] + + if PYTHON2: + # This function is depreciated in Python3 + operation_args = inspect.getargspec(operation_func).args + else: + operation_args = inspect.getfullargspec(operation_func).args + + if operation_args[0] == 'esp': # operation function takes an ESPLoader connection object + if args.before != "no_reset_no_sync": + initial_baud = min(ESPLoader.ESP_ROM_BAUD, args.baud) # don't sync faster than the default baud rate + else: + initial_baud = args.baud + + ser_list = sorted(ports.device for ports in list_ports.comports()) + if args.port is None: + raise FatalError('Cannot find target port named \'%s\'.' % args.port) + + try: + if args.chip == 'auto': + esp = ESPLoader.detect_chip(args.port, initial_baud, args.before, args.trace) + else: + chip_class = { + 'esp8266': ESP8266ROM, + 'esp32': ESP32ROM, + }[args.chip] + esp = chip_class(args.port, initial_baud, args.trace) + esp.connect(args.before) + except FatalError as err: + if args.port is not None: + raise + print("%s failed to connect: %s" % (args.port, err)) + esp = None + if esp is None: + raise FatalError("All of the %d available serial ports could not connect to a Espressif device." % len(ser_list)) + + print("Chip is %s" % (esp.get_chip_description())) + + print("Features: %s" % ", ".join(esp.get_chip_features())) + + read_mac(esp, args) + + if not args.no_stub: + esp = esp.run_stub() + + if args.override_vddsdio: + esp.override_vddsdio(args.override_vddsdio) + + if args.baud > initial_baud: + try: + esp.change_baud(args.baud) + except NotImplementedInROMError: + print("WARNING: ROM doesn't support changing baud rate. Keeping initial baud rate %d" % initial_baud) + + # override common SPI flash parameter stuff if configured to do so + if hasattr(args, "spi_connection") and args.spi_connection is not None: + if esp.CHIP_NAME != "ESP32": + raise FatalError("Chip %s does not support --spi-connection option." % esp.CHIP_NAME) + print("Configuring SPI flash mode...") + esp.flash_spi_attach(args.spi_connection) + elif args.no_stub: + print("Enabling default SPI flash mode...") + # ROM loader doesn't enable flash unless we explicitly do it + esp.flash_spi_attach(0) + + if hasattr(args, "flash_size"): + print("Configuring flash size...") + detect_flash_size(esp, args) + esp.flash_set_parameters(flash_size_bytes(args.flash_size)) + + operation_func(esp, args) + + # Handle post-operation behaviour (reset or other) + if operation_func == load_ram: + # the ESP is now running the loaded image, so let it run + print('Exiting immediately.') + elif args.after == 'hard_reset': + print('Hard resetting via RTS pin...') + esp.hard_reset() + elif args.after == 'soft_reset': + print('Soft resetting...') + # flash_finish will trigger a soft reset + esp.soft_reset(False) + else: + print('Staying in bootloader.') + if esp.IS_STUB: + esp.soft_reset(True) # exit stub back to ROM loader + + esp._port.close() + + else: + operation_func(args) + + +def expand_file_arguments(): + """ Any argument starting with "@" gets replaced with all values read from a text file. + Text file arguments can be split by newline or by space. + Values are added "as-is", as if they were specified in this order on the command line. + """ + new_args = [] + expanded = False + for arg in sys.argv: + if arg.startswith("@"): + expanded = True + with open(arg[1:],"r") as f: + for line in f.readlines(): + new_args += shlex.split(line) + else: + new_args.append(arg) + if expanded: + print("esptool.py %s" % (" ".join(new_args[1:]))) + sys.argv = new_args + + +class FlashSizeAction(argparse.Action): + """ Custom flash size parser class to support backwards compatibility with megabit size arguments. + + (At next major release, remove deprecated sizes and this can become a 'normal' choices= argument again.) + """ + def __init__(self, option_strings, dest, nargs=1, auto_detect=False, **kwargs): + super(FlashSizeAction, self).__init__(option_strings, dest, nargs, **kwargs) + self._auto_detect = auto_detect + + def __call__(self, parser, namespace, values, option_string=None): + try: + value = { + '2m': '256KB', + '4m': '512KB', + '8m': '1MB', + '16m': '2MB', + '32m': '4MB', + '16m-c1': '2MB-c1', + '32m-c1': '4MB-c1', + }[values[0]] + print("WARNING: Flash size arguments in megabits like '%s' are deprecated." % (values[0])) + print("Please use the equivalent size '%s'." % (value)) + print("Megabit arguments may be removed in a future release.") + except KeyError: + value = values[0] + + known_sizes = dict(ESP8266ROM.FLASH_SIZES) + known_sizes.update(ESP32ROM.FLASH_SIZES) + if self._auto_detect: + known_sizes['detect'] = 'detect' + if value not in known_sizes: + raise argparse.ArgumentError(self, '%s is not a known flash size. Known sizes: %s' % (value, ", ".join(known_sizes.keys()))) + setattr(namespace, self.dest, value) + + +class SpiConnectionAction(argparse.Action): + """ Custom action to parse 'spi connection' override. Values are SPI, HSPI, or a sequence of 5 pin numbers separated by commas. + """ + def __call__(self, parser, namespace, value, option_string=None): + if value.upper() == "SPI": + value = 0 + elif value.upper() == "HSPI": + value = 1 + elif "," in value: + values = value.split(",") + if len(values) != 5: + raise argparse.ArgumentError(self, '%s is not a valid list of comma-separate pin numbers. Must be 5 numbers - CLK,Q,D,HD,CS.' % value) + try: + values = tuple(int(v,0) for v in values) + except ValueError: + raise argparse.ArgumentError(self, '%s is not a valid argument. All pins must be numeric values' % values) + if any([v for v in values if v > 33 or v < 0]): + raise argparse.ArgumentError(self, 'Pin numbers must be in the range 0-33.') + # encode the pin numbers as a 32-bit integer with packed 6-bit values, the same way ESP32 ROM takes them + # TODO: make this less ESP32 ROM specific somehow... + clk,q,d,hd,cs = values + value = (hd << 24) | (cs << 18) | (d << 12) | (q << 6) | clk + else: + raise argparse.ArgumentError(self, '%s is not a valid spi-connection value. ' + + 'Values are SPI, HSPI, or a sequence of 5 pin numbers CLK,Q,D,HD,CS).' % value) + setattr(namespace, self.dest, value) + + +class AddrFilenamePairAction(argparse.Action): + """ Custom parser class for the address/filename pairs passed as arguments """ + def __init__(self, option_strings, dest, nargs='+', **kwargs): + super(AddrFilenamePairAction, self).__init__(option_strings, dest, nargs, **kwargs) + + def __call__(self, parser, namespace, values, option_string=None): + # validate pair arguments + pairs = [] + for i in range(0,len(values),2): + try: + address = int(values[i],0) + except ValueError: + raise argparse.ArgumentError(self,'Address "%s" must be a number' % values[i]) + try: + argfile = open(values[i + 1], 'rb') + except IOError as e: + raise argparse.ArgumentError(self, e) + except IndexError: + raise argparse.ArgumentError(self,'Must be pairs of an address and the binary filename to write there') + pairs.append((address, argfile)) + + # Sort the addresses and check for overlapping + end = 0 + for address, argfile in sorted(pairs): + argfile.seek(0,2) # seek to end + size = argfile.tell() + argfile.seek(0) + sector_start = address & ~(ESPLoader.FLASH_SECTOR_SIZE - 1) + sector_end = ((address + size + ESPLoader.FLASH_SECTOR_SIZE - 1) & ~(ESPLoader.FLASH_SECTOR_SIZE - 1)) - 1 + if sector_start < end: + message = 'Detected overlap at address: 0x%x for file: %s' % (address, argfile.name) + raise argparse.ArgumentError(self, message) + end = sector_end + setattr(namespace, self.dest, pairs) + + +# Binary stub code (see flasher_stub dir for source & details) +ESP8266ROM.STUB_CODE = eval(zlib.decompress(base64.b64decode(b""" +eNrNPHt/1Da2X2XshJCE0Fq2x5bTsMxMwvAo3PLYpHQ3bWPLNpTbdpMhv03K0vvZr89Lkj0TAn3d+0dgZFvS0XmfoyP95+Z5c3l+c3dU3Ty+LPXxpYqOL6No0v2jji/bFv7m9+BR/093f21z96sH04ddv7T7q+DT\ +u91bw43mLn2mvW5NN0NbwCwT+pJenAwmUKt/K+8bAs0DyPRnohkGULtOk5XLOb4szC1eRxnJr27am97AqQe1HZAh6WFi0JDhqh62eggabXmwdqjSNYL10gMQaGR7F9BovEZhEZ96b6CzqtzQZXS8GCBHWxCOz+Xn\ +0+6fxmuo2BvCeGBUkddQrV3EXve4YIAiH1QgVll70EUedFHvpaG57Dxq7KFI9XkgijzWw4bMXhmhUUd4rb1G6Rovsddk5zH+F32B/10+sOzyiH9V6UP+Zcxn/Et1EzQxN2pd4K/X9lk3SC0zFiAHyNWTxxsCEg8Z\ +EKiwqKLrWSpieuiiut8mCsu1EAlIC47L/e5pXM668eNyCvOV3XBtXN4l0WlyGs1YFMEUMTzs3lYJIxDQA3yd+QIHIMVfhjl8rXlWbbYD+H7/HvWOVCB07SZRQjklD7d3YO4RDWkALfFM4JeFjGnSulwBKlKwZVRE\ +yg4GVImjdGQf4NA78A+Plg5Hu+o5wIoImcqPZ90PxMyZ/GAUxRUDwoOZdhXIEWMABLLDwJqFURN4Knsr3QQx/AYnSfproqcqDqfAJiF/BECYdXw2nj3bj8twg1gGJlEmyUlcVTeLznz5lgESmS4GCQyBv6Jw1M6g\ +36Yj2iZ8EZbhXBiDidbB82yffxvGRpUNsSFMkwIbhzBRzDTX90g/opWxKw99mGgwpUbwY9QhVsescHNiYZUT8xSgpBTP1TQ0aGmuAEagLctlBjEZCC9znMMzCBeYgCIh2OAzjXooj5+1AnDGkADg2du1Fj+efytP\ +9o9/btfk08c8J/SpfQXW7mOvM/z9wpsucRAWuq8six5wUfaOIAMst2+9IcTWZfwxqD3qNb90o1XeaPOf4HlHe81aVpkBIgqaa7NldYCrm8jH8KAD5GcauR3A+ZlDgs5dF+UDMJPnoffwG4Eq9uhaK/hCJTvdhOfy\ +LKJn3Z8GaH8d8EKfrDq74b9L+u+63yBIYx9XqgYbIGJ2wrossxa0ZczF81Lenfnq6HyZBZvuy6YGR4QkWGc/WdO8M4VOZ8NORyT5qsQFXdaggXHxn9FX2jwZAQumRy/AHLKmjcEKaVZuGet/54mA1KFi/mFpuueE\ +ziaiuQzO9Tn/yP9Ga4A50PgtD03LKK9aRrZyGUdsWhqg49eOBOCh1LGI9oZF+Eth9pYxLwSpWqFoLTT5YunVPr0y2X/5xN6QT+ZPUJ0/DtY94+ADEgvfeeI+v8vzwVgpT6fibpTuv+bjBpqLFvgbjQVIitL51Mcv\ +DFf4w8UscJE3bkaugRNk9H30Dui/58QdaNyAb8giWfXJwxRgQZD5xTdo2rmbqSn3Z47y4H02zSSE4fLPYPznDN24Evdjxj9QVR2C5hclnJ8cojE6gIdPD0bwAfoek2QEcBkxK0bJmkcowB2Q81seXiQGcGjwcKOy\ +5PgcVIp9q49Yq+mY9RAix2Qjp600qRBii3VHYfSckWvmI8t9X+FXm8J3JLM91ouyLWG9QRzEvYELNvvTOPYnPaXyXjfLtBvevDjylEQVZMoR/JKoZkzeZ5fW/EtxAOfPWbwml6XNsx3oPqIIyYepsIxC/nzB+jRC\ +OLe7RsFOuf4ypFY03v56RF8Z5BnQVu03BBp+kMw5HhxbJcur156Y1Q5LywglBSW+tECM/BGNQIePz9mJxqYZv/X8DHEj2oqVktNjnZUxpXXUZIoWXbLOSCUo/jOhN80cpTCQmOoaleYGMuc8xBhceAW4bi1nXy+e\ +E2ajNBaDhrM8ZEsqbqDMpMQpytxwKBgmoVXgauvhigKSLHroPNmAidOMEvTvwPtORmsgE74njiFIb7w78PI2xqDwfjx8H5LbDbyGH6jhB2xWjB/+4fQ0cTKDf9OXx8fgp/0bRpkTu9Hnq/3NBJ3NZBQzOlCzINve\ ++yezTubSIlH0cR51iEqcFKlTmOUtZtCGXQtg2DQgn7htpg7hVRwyfyoORpqKOSoJQd/Ei+BWVd6g6Jjt8c2cVa9IXYwfxCVMM37C7nocjM8kZQAMFdw6/ZKteHlAMTl47nX531W5hYPsTF5yQNoxT9mSOKvxHBy8\ +9KIb0vLwzwQAuKqNWexQLw3UUePNH2G2cmNRruOo23svQLO+B3mED9LXoG1ArVaJx7swdtrBrRFgskeb9B7RETOr5i3zsq+FgZ0Kkhr4X8cFCEtBEV+Z393F0Hn9J+rS/dxgBwcsSYca8AzNWoSpq+DfjDHDBhQN\ ++sPqW8KZqSmjoDMXWJc5aeEGBJXSDcEpjQLrMm3B3mzGfxE/oMHmvg8Vu3RTr+8S/OgcNDD53g6D48c6OPKCVnbjaY4rM25lUfKNXZG46nYZmVvG94NlFLKMZJh/E/mIgn96fQz2Cb7hRwBBAgmv+DVbiugGiNKb\ +cFZGz8u0Kj8HooEkMD8rio6WNASSfRZEz4O0CrBTkBDXkxg2pKRGLTGnMf9+OkpFXPUIg66nf4cIuzqUIPzsKfMWZqIwzsGUwKvcESUaTyaQ5hFfJJuAICVRC5xk5jyUuHKOFMEdGHtnvyC0zylX0UcjE6TN7txF\ +um6xXfNfWv5jrg1Hmyy0hhYXmSSANTZFJcxLw5iS5rNkjoWuoSyP53CJotDlcYmc/LueiCaHAL4BMQLBRZ4E5xMzJ2ebhM7OwK53S6nyUTCFJeUkfE0yJesIS2rro3ANTfM6qoZ6DzFw4wMYKCwGtthZMC+OwJyW\ +3Ckd5A4te/8J657Lolmdwzo4iTfh5QKN1Hug3IgwpSLnE6vsCTk2LXBmXeDq165c/UKWjgEEjmOOyAa1qadP7Jr1n0Jr0Dpo+9qAHU2wYxF6kW/C3RCYbEZGyhKaY8tGT2XlQzLtTT+e78GOgnrgmJoyO4stQyNU\ +HHg5BR0wneopMUpbW133JnwUCpYIap7aebNTCpvb+k3yKAn34RuL7IA4i0ZWMrKRkQUPgloF8LTZvO8oYmpY0ZDgCpwXYRe1gJqkZFnbeRznX8TH57u+FyKJzzoKMSVSsJ3R7BQOkLjzdi6pa0lfAc9dJ3EDnttL\ +jsi+wqr/cnmjzm3kRK7BvZZz9Dk2PB5zjOfFr1G0tz+nXGMUL+uVTqEUAD3QOloEEFpV7eKeAHjoXEGyQ0+oUUf74DOcrKHncJMcLEh+ISFqL6eX0LPGrJhf4/zazj8X7vNU3g44UOcSFr1zfv8Kuu2QBYX5Kn2F\ +VCGtIBPaLIKtpwC6wSjoHfxzQQnZSEGCLb6gVDC1stugtcDjN4CDnEz4At2ugRWvIxJTZ8UXQSzWm+w22HCY0bw7PG05LYQypTmnAdDGnYwv5sNob7Ae3GVKOKGKDLLhYiWdBY6rwlcgRDvsoBeoEmbwLBbPc/yB\ +RYFLvLQoSZjo7QtF4gyfuCV2K+7WDZjLZbdEz/aFuZIL4g+Mik18SvuEEXuiRTqTpGkVcqDY5qFsXMiuEtDZnA/D4tkD25XkTGsZYhzTnk6jdzlah+xHLuO12w8WB64zO++YQsRgQHkpuyx4jyoyDK28faRFX/Jp\ +MGMtesaYvp653rbppaTAb/VnJIEXBW+ImiT33hqnr/kFbp/gcOBrqcmcSQwIazAMjUYutbrCRXiAvAhpuvpRMtqA7rAzBUkdNBpVBupaBd85SLqYGEF/jpvSPR79dcigQqWOBftecyTpFWsV7vwmJww8uyMyMCb+\ +f2Aagjla5XTIlB26o/Xt9ek+Ych5os5YWze1Q3xwG216iIkX3i9QJkHSgHBi3k6dfeFT5XQBTI1CPjm9BPu0AP/3JcQh6kDinc5gKZ9sixIrEtTzZd1yfHOK6oSWvX1800txRerJsAPBjFTCIRGo7a0ZZSJwywjY\ +bcggnRyqjj02IUmK6hkLPXgqHYNwqrC8jZB/5myhz0woemOf6gD8Nu5bJb4WQimJZmvC4AczQz87ID4jM4hhfSrzAJ+pLV6uM8HsAGCaZ4Ho7Vol2fFCg62ElgaFDNm7lpwnVLhbROyiPOB9LshZyXLRw8zW2XJY\ +dCtyHnB70HTuWChwjEh7o4UHccacwnvyTBVsqOFO/xWWOgnYdzRFxdt6hcyMFCxKzakEQWL2kiRHYQkG7pwnkliflShfB7DVnyxKfZqPOOGvVFzmcZDNghzhSBdBFpebk2Q0C/TpGXL8waLMZqW+T3memvMdILo6\ +z9XpA1pKER247P1komblpgs7EULNG4ZYtIKpOoR91i1o8hYGmAWbQJ1k9jW0FrIrDzoCQkVU5DbLDt2iUzCEkwvszCQGX0HjlCEOM5rZ5FwTFVNBicstdsayW/wpLP70APh/QUmvtp3cR2aFpzh+51ufd8uCmVLJ\ +JoAEdXCHf0d97s3VIRKQd9Ehr/sZqWmHaBB9Y81Zzs5luQhyYAx9ihTAtHwU6Yils0AgJshHpwlViRTxC6cJi8IXElW4BLMrMglub2y55HmZuz1i7bmjoKpr3nanb2U/GvL3AHmZhfJqS8pMKmL/Bh3T9Iyzm2Z7\ +7TRkxNktHuYOkJpC9qfV5KESobkP/oHbj7ccLNKdT2i3NudnGDHdcIuxBUaGXAVazBY5X1iqYt6TG+nZW8zigNSYCDI6UfoIsFwmhOzYZf+A9ZtE8pSzW53/Ax4venApB8GZBJp768NCmw8H7hifJRy7F39h7O4I\ +720h1LkXSuRLqb2Zq5vQ1e3eHImrnWH3Zx1nXRvRxLcIKrGyClgINLLPQguff2Kff1BlRSPmH6oMiAoFY2uqbPqZIyTFlSSGuSFlwqtKfJDUUR/8TEv9EE0DTR5yphOpj8z1hGt3Mlb8bmcCos1ODjdsGQS9SHpO\ +nbebjl616lT9MYAJxQWtoWQJugpKkgOGdq7dX2EncWZvRnVXbYSxGehTnZzEIitSJwRd9E9iSQDgKx06ZcSf+SfmdRrCJc3d4cfueFhHKiw5ZXdX+P9jk1bKrB0RS+hk2VG0/J+v5v/5CuY3HCdE5ECsL4uBY8FI\ +W5HI78BUwTNaKxGzoO6Gdlx1yRs1qsCxLmCsZVwAXBdA8wtY4fZFAO6gmX6OjL3xiMY473EGaXZiDh5QGdGDLcbs52ofmeRg9yAmHKlrwu1DWolz6jo3jsLtd63vqM2HUcEZ4bo1MySSwlhPxdtE4kzKhtr2lbcX\ +kMnyl3jpBUfbbaugLsAEVE3TmuVcP66iswpDyDuwA6JBy/USasZAJe/AYVIpvcJ9PUQdFkiYvk87DL8DgrmF4jxMm1dJQb80q7HWbFLtHmqACp3aF1KmyHaxyWZcfmfIRqDlSUSEsp7wbj0txJquicr9yhV+tYVT\ +K569BXcqgqqglLajGwgfi7RnZKs/xcjOr7ewrFyxmjWlTcrfamHbj7awNz5Fw7zlbUx2jdC1rFdZ2ewvtLL6j7eyrFLiZUML2fQ+70zExjnewWhodCIGNqN6dXVywknMzBaOY2btPVlB7dFdVWs9y4fK7eQVOrVo\ +dnchw1O2E3BMAa9FJsSf27KBFQa2nxwZeaqS6jleid86f+gVD8ReDQ/bFgwho2uSrZWf5EW+8/1k2FbOIYYrbAWpxxNSZLA2uoovlmjD8WQVWdpMqc60rXbDHpkij0yR6khDUlMmToKBEqpaf0/CMvR1osyXw4Uj\ +HJogEIvqHcrlsnC+EAdI6DMW+vzkbWFeQSgu/7SlaOvDuAMMXjFbiU/UaKP1j8fnbAmfZ1xsXD0Kr4xL4LHCqoUu4HrImG29+uwytzkUVd1/73l5OS76VAw5lqudYlD5DmbDGtDKIvuddS6dhxlitqdGQ4JeHMQA\ +qOzbsJsx9o/npD0UTwYotqUUhz85WpEkxDKSugWbF9krISAJeMssAxVHVSlIphL/NvhVlEdLW/VcNb4e/AdevKmgnVXgLalsg0ev6gMGQrYWIhRzfZXOXkNnlfexS7bkRQLldW39IacwHqhrl/KOh+raeju3eX9s\ +6CGyeiXlHfW8w7LnESY9Z1C0spfi9b26FU6f5It8l4EolkrkvTvwFUy2jZ7AHaEGxkzWlEI9ZNRKMtJwbaBSJxPW6VSPf/KD+APpK/YH3JGNvmOg8hOsIb3vpFcjfdlf6bkEdh3bsDxIRFZ+xE0m4QS59gEsDPgu\ +St8cYNrNZlqKVFTOAUcvlbmVAP5pkynr+wKkf3o85hvVa9lMM5uVUG7YcD7DcljxB3DYkLeiVe4B4s47fFCPP+geVL578ORK9yCdcB19iYW0q/XlGVecXMlQM5+h+g4mHVro9KUk95yTgOq/ZUDLzIbggp7MsQO5\ +h8wOV7qH+0LsdIWHcIVWnNJxMlobWubdA9xbmZXrU1oWvAMlsJtqLPGDyFhlr92phaqefTyLLZWS9bmsYgcXHY0/ltGq6/XYK1BiZrGkwfJeB8oweHpMdgOdrRM8n3rWBxEHFhDL+ssK4+eICh9NF8HBmQA8llCe\ +YAh0imNjNBCX29H+6GtRgU/vjcgp2z64D6eIsJZVav8MDrHzgpLjeKx070VAFUVQzBGZ9aKaf7+aMN6eflMsgm0vzt9BHwE3vZUbjVyvaHvNi+5VdRGiQV6U22hpRc6r6ogAheDCHr+ciXtUcaagnt3znytsKmnG\ +XyT4IP7iEMQmkxBI1B4zfclVM3joisYnoFqsAZeHCh+qN4fspysXzZWlK3SjU20QkUDmHl3pnMtD0KH4kbjVVWbdwSAM95M+Os+5QzBRJDZ/w3mWqxI+4z8lFDPeRu5vqM+S4xhSLvO3j0HD0p72Dm8NESIO/08Q\ +obN+sRoVwK8o0Jo7I/9p28A75BG4wHsGC/2jom5QPSCgqmof8ERsmnB6DPEzrppBe1rKWntQ41Z+ubNWVK6SV19NSjBiKaZDS6wIIuexW3inCOpiASID3lf6C/z6gUIEjY8w+wM/xu+5Sg5cQ85PQahixpxNytkF\ +QpwhAV8CYRQ42uVTokuLKsE8hVrVMVXN9oplM66AtLmvX9l3k11p8wuVzbp9/00mireviAfVSu+Z+sd3pDdAhOxT2JktD1e8SK56kV71YnzVi+yqF/ngBTY0uqBlcoH+8+naFFAcEp7xJDteR+ACI1+3h7t2oO3d\ +EeBndAELadQ/CKlN9NmoQzmmKmnXvrNfnxP6n5ODbYbo7zCNO/ml1C/dlkPR3w8/XQS008vl+6dke+mQTfD52SP4vqPdt0xQ8/oOMWgVbbnzQY0caaZTVniIDYl5+A0JecNqDDgQNkVgf6mM35POR8kXduRdf1BY\ +2EnPvXDfOOU4PHhjq57lDBvsvtWNukPOwa1NrPRt5XBhKMcSWDcrLhQvt9b08eJMWmT/TXK653ZT1biSwxZYJFOjMji5wd5p9d3T70ZPv+czV8Xx4mkIetAsGL78Njty49SeYceSjeAWHzfTPLN5QFkB3ch5E8TD\ +5h6YhplnlxsRX0PupWF5bFs5WpRvwc6P8YrosbKpgbGM1ZgvoZt00ayZbPUifOvZEPth0Y09f8HeUAQnvfkr2NooA04yQ2ZDrQ25Dx5uLj80cL4RH2oBEMn+pczrneVR9Yr+wizR/D4DBrcK9D8b0Q0KmuW9MLIE\ +GBuPLe4BP94ewY4fMK22B2h5241RjQV85eYOwjoGRNtwNR4yqXemCNhjPDgq5o4Z2OOG7sBra6+0oP4hH4mq+YgSVQ5+zqUimPAtOtEVzwLOPRUGo6xbYD7WRv/lVWnmsoYHj18eH7/+8fI9QsInqlq+ZaV3rrj2\ +LxPgwy2xA7nNBPVcL10slYQtvLop5h5E4tJlBXgokQ+f2GJ/4C0wY23x4PhY7zyUE2Q4V+GSUxS6ywmoQkT3pXfKzWgoMYBEKKQn2uIp7w/SkT98F7ldQ1R5AnMc7Pev1jBxgJdnBHh5RoCXZwR3iU06IixovXIh\ +C7HICXt+sX93TbzqIhutyH/zbnvYxFNyo/WjGV8TQbs6Um3uPoR1YLlP3nv8kNWHdw/G0XnvC+1laGKKf0drkV2K9u6vUauv4IG4295Xo1P/ipqJvTnnMWdEmrv+zTzQVVNXD3bUWIr9GilxktsvakLsOTwrgoD5\ +r3c/hhyCo5rjc1Cp77GDXAHDn4ZrLE/kvY7AbdXjr6TwlU+GFRmwcqL+B5A/xX+7Lyf7tE4e6iWzGJ54bR8lkudADLSYSK8hKdGmtkuFafBH9xw4Bzwz9Qz4LGOL7JTSZtpe8C8AQOG/U2bVdteRGA/YPiNr3C1V\ +qvc5/dO2S0zjAPqGD8qKZvMep30+U3K6YDdcuoYEz2rzJT14iATv1uBtXUyEw+GOWsopdY+2UnSkAyI0VtQxN6jIly//Lqa+Gp64ZbqUji+MHneZuOQZ0XvC6fFYE+rflOI0dBDze8zALVtojAbGfCa6pS+x9LmV\ ++Be5Le0hvOiJI3LyEV7vsvmY7U5yfHONnQiUyOkjhsva982d0SiVwznN1IOAVN9OyWarnRz2ZCfGZGsUrR8lDB0epm3RsbNna9s+PygKIbzHM9NjD6wQJJ2iH4+QD4rHemc33NoR8gI1r6LiY7knST5o0O8Aa67Y\ +MNXFswdgrjt+Pz9D7ncGCg0HbDFjOQ7E3jVc86Oyb9muaufutXxHRGum/QOOcDsLaREgQ0Mpop/ped0OyTv0ndgzukkao+GSwLYS9oM43YBn3Tyxh5jN8lUe2kihv0k7rwt7bd+G8NeAd1azjULPttgD1J4BauHy\ +DP2Mz6a02srLSNDsXziGJ44QHUVPDliZig/8HBVRdHw8/Wb9mVga6JFupVj7kP4jtJJv8IYOU/x9C3qpvRXOgFa4GSvLG0d8hOSDjOEDKJesVAhppJY8DvkA89jRShA+bqZuAnsXgZybH99j3pG7T8ZiIRCm3F2l\ +FOGtMqtBw1KJG58M2gA8IhMbRSQbCsIuM8eH0jh67LgS9lbQKU59Gb1e4y4Lae1TtkPfWVy6G6+WCYVIuk3AGQvQ4JYEYNdlNAm7D/ibPnjpexWv/cap3zj3G5d+433/wkA9uECwGLb9W+Gw2lvbu92+xF+pfVZ/\ +4d0hWBRysZtyJToOrXzXDioHwC8oPdR4oPk6Rejf7ga3MuD1eVARJZlIDALYW1VliAZHrmloOahQmNLywhIK4Z8zw7Txj3zhw0pVFfA5SE3KzhX5Ppb9A95NaooVXeuG/VfKK2w/g6kOxMfI9uTTkpP/La7ytQsm\ +6kzuDiI4IiXhgyLBwBvZ2P2BpW6S4VTl4S+y76esJq6Xlle6qtVu4ktOlxt38cyPZAxwJyFhnUre0G3m+vIAZkrvHMMRP/ItES2DqePh1M8oNEcBFZteHr7kxEfZPGOZoec/wPOS9xc8aCVMwke0uY6Jdqj9gzgG\ +NUl7+rmwUKLFhMautLtu3J5hI0iV46/d5LPGu9cuXoHDyi4AIyG+A41uknlGJwflziFF1HlA66xwr9aelsOzDuPRYYRpl5QvcYswl+j441EW2gNvB35GGtJQCWvoqtg4gIChRCf0Dk+OhZiQIVOrbudLPNcKwYRN\ +EPKTvEtL0N3TS7fD4e4lXmdR2tMfF3LBjl2gVOi0LtzuOGiG+wn3c0+9RhFcl4JaKK88UqV85UtTuwO/BSt6Dkw/2lso5IRhu0LZf1gZNWIKRP0YOWfojeljqMXKUO1Q5fawDefzrXCjADV9AdIrvKiWbj8UIO7I\ +WdEnI+5TLPepOd9bS+osOoIUVR2847v9PH3Ko4yXeOViiVFIWEmXsFZ0TieS1EhFz28glPMPnovxRE/8a/ZGKsdNBZzctIedooRSszjOBp+rGW+s8ykpW4gxE/8GDuzE27gbsyURon+noP3S4JfH5zIzfk3Z6R7Q\ +8n296nvn6tk+VB+FzZs7I7yC+Pu35+UCLiJWUZ7qNM/TtHvT/Hy++MV/qLuHdXleyo3FNkuBOmTs7ZJ5ewBUYMJ/iIovOSjAu1cjr4Ha0b7JuYwIL4qtKejFRt3aN3yrMXXIvIbX4ZL38DGS1V6j4nBzeQav8YLi\ +1OFjvuySLjquSD12jX376+oRKW+y+jO68o0bsB/eKnlT8yE1RFRLEZaSS3QxJfLhSa9uoEyNV70pjG38h3yX7tczjy5YLS5di9ZDLm7UCDWKsX1zy454/umQ/u4G1KkzIE/sr7G3hqW9kmFaenixzuDobP9QpV8g\ +RGVmvdbgHmg1mBvPjEWDG/Tstbmu0buAsBzkcwZjGrXitm81+H54A3g8aCeDdjpoZ4O2HrRNv60G8Kje9yO/0fvSv0ZcnSzvcf1pf+qadvyJPHQdT13HY8N2dk07v6atP9g+/0Dr5w+0+veMr2qbD7YXH5Kda/8+\ +VW6zT8LR+Sesewh5e40WGECuBpCoARZVb7w1v3HLb/SG7R1l2/cbL/xGjyBvB5pmAGc5aJtBu0lWSIn6C6X4z9YCv1dL/F4t8nu1zO/VQte1P/FPRS6bZiUwR8mj46VjlrTU7qEsGGuNy4OtsnlLlOmt9CY7vb6P\ +nORxF3HqX/8XohBRvg==\ +"""))) +ESP32ROM.STUB_CODE = eval(zlib.decompress(base64.b64decode(b""" +eNqNWnt31LgV/yqOYfJaskeyPbZEz0IS6BBg2xIoIdDp2bFlOyFbcoDOQjgL/ezVfVnyzNDtHxNkPa/u43cf4vedZXez3LmbNDvzm94k/k9xH1oKW+XR/Eb5ptX+s/W/fn7jVEKdxsyX/i+01O2zExrFmfX/M1PD\ +foomyE8roUBFrehnhKJu6ocd7WTgzIbayvepbDh7D9bEVG2tkZe+pR35c3e+PPu4Tj9uA5vrTG7iv4tkV22+iVKHRGoX6NSlp6QONHdtxDO3cqa1dGboQCLOvnyfe8NPh7ZRYbUDofb3aQP5KbpHJO4toSZLYQjo\ +fuAbU7iJCTfpahqtp8L982NiUS+syo9gWxh65edBb3OeAk0vQdSeIDeFGRlvCqLLgdvp4bn/1BPfn0ciVtyGa01hh9PQGWQFfJvSijYbDR5fjiR9gvxc8qbm+CRlUTt1t4CNjm26wmhD/6JeIrlqRUnxw6qI18oc\ +cstE4kBKi/j78FBaJ9SNa/Ro32LYN0gK2QvcqaBxJI3hludgD08egNrp0cCu/1MmyZKlmYGJuvIWDPnJXUeTGx3aA4/rbJsb+FtOWLqgZ34vx5oBet3F+t5EezaRMC3928CP28NZjm3PelnqZnQscZqgigZBy6HP\ +cl8wnuwfzHRPj3Gju5zwSHQAUq4jCnk/W8EZ9+Llhu6K91PBnlu07YoMXtsZoZJSX/00v8T4EQ1s9iPLsfXy1mvmDx3FsM/3kcIGglo9gOKSr56PmHLOxzbpNm8M0OlF2FoWObQLQQqvb26sC69pyRiNnh2AajH+\ ++T81bnBeqKljZcvB0sHGizcvns3nfo4pZXVHHCKjfOhX+xEtXDa3iXcIOhm5AWF7DK8gFl0Al/LEE9pkCWMII0IXWbNxd1PSKVfs/R2puvvyNfwDJMNVwfDGODB2Tmi679GIvHe5f3Ib7w/zU+JEHZyWcLZuCahN\ +BP6Bqp/m18HddI7sCD2AJk2ts4DvYD9aoE8Tc9ou8i1ZBKL5qi0H31wnMY5m7BebbItngor363gc87JWt0jJVv0TKpC4GyVevNY3EZnsDvF6Sq76BGZmV/CJsjpKoZ0jZWCRNTgUu79PxxqaE+IAY5/svWF9Qa06\ +mF/z/m7K9NoRvXcIawYHHggC7EWxZaSEOK0jWcB424xjkRFjZI5jXc/He+Na2dPwPtX/2KflOcX6nPXYgG5yF/YuA4LIfvKtm5QDq0bAK2Ns3RirSfs8/vAA14K6T73+t+ZHtgTrom7wnHBf/1FubRENAFUo4Ch+\ +HBlpGXAS3H7JrgSt6NkDQPSW4xGRkA7T4p3AmuAEmd+wIa5Rka+ufZIeInyeOVJWNAg23SZaDcBe1+wTug0yhH4bBT2NrJkELUUNIb4jOrlVKQw2FGknnOjaP9KIy1he7+OPZfxxE38ASF0w1gGes4nAEZdsLFsg\ +Nhvhg1yx7ul+xjwGdfgYOIVWWt6ZX4MfMc0Fz/uO5PB2CECPPMOhM5ux20ChV/GUeOlf4JRTQS+QfSOkvbyiRRI2qvIgitAGQR06YjBdI2QEpDyLS9G/MgGBsLMBgFl3NozlUYSBXJg+h9uX74gMW5/O5h+Fkonw\ +Y+FPxCNYZ9H9sQYixPGJRAvxuNGJl3FdMVHNmnFdpVcPK0JT5zhwwNOetZsvbSo/XOd0RBfnEcyzttgsPIlHNAfaGPRlu+j1f2Mtq5A/kIGVs/k1XHhKE+vsqcBUT0cTPn6lYLLhWKuttmfzHTIyZEn/HgaTsVnW\ +a9DahavgUrXJPpnj08Bxsu874K5R5Pn3jO85EKXhXLhQq18Rx01HQdaQBG1AWoz5u/t/Ozl6TMZHwfP9AmP65SFrEKUJmG4U91cSvA3ZIWiiGeH54Sh93UgDQebw4QW5E+1QRMnKcDyTENEt4Spv0oR06eslH90x\ +2JxLZHj4r310JSZjj+LcHWz9TP8UlBPiYtBiS5dQJFXvac4HzPqZvC5O1QUth6xFc4gr8aRn6nUKPsscc0AikLAGMFvk0DARa9ke0dPinseYVTxNK5Bx1XGciCc8Jfx2OplEoeFUsOGIqemErI6ypyEkB7m7fYg3\ +3ZsheHscHGC3Fu/CarxgSooOHVGqmHtVTibJqICSM0R+z6qbDexwdhRnGk4tHAEQWJXLklugQSk046JBQuAC4Zxi6/seqAC/HV+x1c/5yKizERRgrtdSGnGDxfYbOIQZS+f3a/Mfjng3QO0GZXt1e7jXJec/5afR\ +dW84qHKkBtz7NvTqLD3iy4PbQj1xu9iHUe/pfPn2dDuEg9qVF5QM6H4W7q+GDfKGG1iegrqFXqRJfwyNXTDSKOvP9k5n4yqRdmnqj+zGmmUa0U4gdSJucziS7Wh8KsfgWcKBHUYDFQVIWsfhiiBfHzq7bhI6MVtC\ +M5hJPt3E7ML6zg6VHBSHthYvdZH9Fe/AyWzNENSXn5K+lP5OOpGf/bb0o5fxfTVO6CXjLn/HzzO+bEnQzaEpugbWK5DZClUEYRcoy/5TIMw00Q6IXn1YiBPysG0TbTv7IkRqEeDoUFdaOnEXbGDofCCTocOTwzlm\ +v0Lwj3xoybUFXqJH00z5dNCdiDDHhNmCtROTFY3OrzzwZy6lT1EfJfd42T5SapyycuAkHsujQ2FAz6jCIexCW8Hd70lOcIA2X4qn2OaIRsTJvEb1M2PvB6pYI1AsZskiJR3X5T4nqeV/ooQKfpCBGv1xFVnOKAnS\ +3TEbGkbTGbk/526zpuhgnLVagD89o7t4DHrDFhWlkDX/eqx6Xm04FGtQbvEQDhpOfMQ13LWtiHi3YR8IgnSzTvyZIOaMAhk1hPZSWAnMnl0Fne+zmM29BPU8KB4XDXR1tG1EWotIK5TeDtNU+YvUuTBKwaLYQ4aR\ +OlY0xwm9tmIp/+Tah6HC9U5HJj6UxPINcRUoXYFk3oFFj+C4P0V+ulw9rUZ+vJQ3hio6LyF2ac5MHMf6FLZ6ZNUV+TQsV+u3kLi32Q8wGQ8BW8gP+M7l41DU1BmtE89UZ5RWC2ngZWwtbD4hF7ez+5qgHmqxPRad\ +etJZO4D5Yg/qKJ6xriKLtpyCNALtzLpBszNJ6LFwa2lW04DC15bT2WqffPzgZ6ZcsYB2Id6gZJ/DDKvxuSNhpYEeLBOXicyvIsI130ZRI1kQKuPpao9qQ8SsWT5OcjC9bQMrxVWvMHNQqR/lIcbIuLkIKgdZsB9v\ +kOW7EIkhujD0GkJCMiDOvVQ4mvButj1Y0olMrATKkxUbQuFbBmuSCa2Kh9asmLPKbrTZ6Byu1TJrMQmI1c1IzMoPaZFSicIY1ivgfA24YSEitJbDpYizzym+Q0F070CdWnxjklnwlFD99GfaspMEZXwj2Ki7O+jt\ +AVX03FAl2ycn41m/fJoiGddP2d3DHWxCz3ikrRl9oNuxt5mLjmoIGMZGUcOAebEPstnYgQ0BZDmO15RahbC+T/hNBAIJK9UC39PJ50QCsjPG7WolnOrlYaLUF2BL0xD8nCGxQ0yFjynbJUtfVyHjkReUtcgAhp+t\ +OXcNUUQILnQU+2jFod/w6iMveh0nBKxcwUXVHDB2UbmhG8XqAEhwRcMeSEvhDLFj0U4ZDug5iovRDQEy1nXwjapkEIczpqtEcDSb80NPRHSYM4uK4sws4ge+NwzuikI+cM7gEyZURhX3j0XaTmr0EpOncUAOeAr3\ +ArqbhKZhDK9EA0DnJ9+Y0f007Dho2eZQv5dQv09S2afh2En01zKLW34GajBE+EA8BOTs8FXn7QfgzGeQw5f6BkI5Zz+zHtjoKQAQoOWCnNNS9QJMbPUHCvF6fjsC6MEijuOUmUvClh9IeklqDCUWcC8nfVwCa/J1\ +wXqIugZ1wPfOD+KxSIMaC73iGBt+sKrheaI2XDyCuWi57O1qgI+GH+ywA2sV78OuWMqoiTp8IhDmtuE5Ap9bohxEaqHEsMkyZtQXjgkgnyhvQKzuM/nHqkdH+Zkde0mPnVBig2IglkcH+K32XoAt3RM1OYMIo99l\ +OgC4mmxwcnElZCXAd3bvxQye3YLegaKfUZGgYUdrN5mY1CPY1K1an4P92Xo/KCkm8t1lxe+RwL0uLt2a9o/NGjBjdU7HTlAi3CYyKQnkpNy8Rq9oLj8LoQMEWZoZmWDf+0z+slpgeh0eppuCgZPXO85w+FlCEIRa\ +2QRELfWfOHQtB3c74wAHppnPcOELcK2vQJqPGEBBTpEfBwsc3+cdZ5fXC36aU+W34W12Jy7t/LrOCnm9U1JXgcLFDohrvZRCFXu4f/kbRsevJTR+dQkHoepmW6+g922IcOSBweqXUYxiLocE1ZnFLlD+Dpef8qYW\ +X0ttXMmhabDrUHElU0gheOW0FBZvfr+x8l41xNK7jLhswxiQuCxwG6OBMuYUVum+UomLTtnmAGK6nXKrDGXi0aOj2rslZ8E2LuWSnypX4tnWoTe38f+FwrkHXKOKrjec0H4luB0u04yWpoGQsJyXjNm1cyfB/6v2\ +y7+X9Uf4H2taVUVuc2WMH+mulx+/DJ1FUUJnWy9r/q9tUcF5h0fijfIqL0udffsvV73qkg==\ +"""))) + + +def _main(): + try: + main() + except FatalError as e: + print('\nA fatal error occurred: %s' % e) + sys.exit(2) + + +if __name__ == '__main__': + _main() diff --git a/dist/tools/flake8/check.sh b/dist/tools/flake8/check.sh index f8705ffe1551..1595fd7931c5 100755 --- a/dist/tools/flake8/check.sh +++ b/dist/tools/flake8/check.sh @@ -28,7 +28,8 @@ EXCLUDE="^(.+/vendor/\ |dist/tools/mcuboot\ |dist/tools/uhcpd\ |dist/tools/stm32loader\ -|dist/tools/suit_v4/suit_manifest_encoder_04)" +|dist/tools/suit_v4/suit_manifest_encoder_04)\ +|dist/tools/esptool" FILEREGEX='(\.py$|pyterm$)' FILES=$(FILEREGEX=${FILEREGEX} EXCLUDE=${EXCLUDE} changed_files) diff --git a/pkg/lwip/contrib/lwip.c b/pkg/lwip/contrib/lwip.c index 5394f4604170..49953a1eaaaf 100644 --- a/pkg/lwip/contrib/lwip.c +++ b/pkg/lwip/contrib/lwip.c @@ -38,7 +38,7 @@ #include "socket_zep_params.h" #endif -#if defined(MODULE_ESP_WIFI) && defined(CPU_ESP32) +#ifdef MODULE_ESP_WIFI #include "esp-wifi/esp_wifi_netdev.h" #endif @@ -63,7 +63,7 @@ #define LWIP_NETIF_NUMOF ARRAY_SIZE(socket_zep_params) #endif -#if defined(MODULE_ESP_WIFI) && defined(CPU_ESP32) /* is mutual exclusive with above ifdef */ +#ifdef MODULE_ESP_WIFI /* is mutual exclusive with above ifdef */ #define LWIP_NETIF_NUMOF (1) #endif @@ -87,14 +87,14 @@ static mrf24j40_t mrf24j40_devs[LWIP_NETIF_NUMOF]; static socket_zep_t socket_zep_devs[LWIP_NETIF_NUMOF]; #endif -#if defined(MODULE_ESP_WIFI) && defined(CPU_ESP32) +#ifdef MODULE_ESP_WIFI extern esp_wifi_netdev_t _esp_wifi_dev; extern void esp_wifi_setup (esp_wifi_netdev_t* dev); #endif void lwip_bootstrap(void) { - /* TODO: do for every eligable netdev */ + /* TODO: do for every eligible netdev */ #ifdef LWIP_NETIF_NUMOF #ifdef MODULE_NETDEV_TAP for (unsigned i = 0; i < LWIP_NETIF_NUMOF; i++) { @@ -132,7 +132,7 @@ void lwip_bootstrap(void) return; } } -#elif defined(MODULE_ESP_WIFI) && defined(CPU_ESP32) +#elif defined(MODULE_ESP_WIFI) esp_wifi_setup(&_esp_wifi_dev); if (netif_add(&netif[0], &_esp_wifi_dev, lwip_netdev_init, tcpip_input) == NULL) {