mirror of https://github.com/arendst/Tasmota.git
Compare commits
11 Commits
6d69b0bb41
...
6d4bc04d63
Author | SHA1 | Date |
---|---|---|
fb-pilot | 6d4bc04d63 | |
Jason2866 | 41970f7d62 | |
Jason2866 | eef4ff389f | |
s-hadinger | 1e64eaddf3 | |
s-hadinger | 466652549a | |
s-hadinger | 2a35f325b8 | |
s-hadinger | 469492a41a | |
s-hadinger | 582ca598f0 | |
s-hadinger | 91dd120aa9 | |
Norbert Richter | 5a8d713d77 | |
Jason2866 | 492c6bbda2 |
|
@ -6,6 +6,8 @@ All notable changes to this project will be documented in this file.
|
|||
## [13.4.1.2]
|
||||
### Added
|
||||
- esp32_partition_app3904k_fs3392k partition scheme for 8MB ESP32S3
|
||||
- TCP Tx En GPIO type
|
||||
- Berry `webserver.content_close()`
|
||||
|
||||
### Breaking Changed
|
||||
- ESP32-C3 OTA binary name from `tasmota32c3cdc.bin` to `tasmota32c3.bin` with USB HWCDC and fallback to serial (#21212)
|
||||
|
@ -14,12 +16,15 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
### Changed
|
||||
- uDisplay fast drawing on RGB displays
|
||||
- HDMI CEC synchronously sends messages
|
||||
|
||||
### Fixed
|
||||
- HASPmota `align` attribute and expand PNG cache
|
||||
- LVGL restore `lv_palette` functions
|
||||
- IPv6 support in safeboot
|
||||
- LVGL fix memory allocation of flush buffers
|
||||
- Berry `web_add_handler` called before `Webserver` is initialized
|
||||
- Put back wifi IPv6 workaround
|
||||
|
||||
### Removed
|
||||
- LVGL disabled vector graphics
|
||||
|
|
|
@ -40,6 +40,7 @@ class TasmotaSerial : public Stream {
|
|||
TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fallback = 0, int nwmode = 0, int buffer_size = TM_SERIAL_BUFFER_SIZE, bool invert = false);
|
||||
virtual ~TasmotaSerial();
|
||||
void setTransmitEnablePin(int tx_enable_pin);
|
||||
void clearTransmitEnablePin(void) { m_tx_enable_pin = -1; }
|
||||
|
||||
size_t setRxBufferSize(size_t size);
|
||||
size_t getRxBufferSize() { return serial_buffer_size; }
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "esp_arduino_version.h"
|
||||
|
||||
extern int b_serial_init(bvm *vm);
|
||||
extern int b_config_tx_en(bvm *vm);
|
||||
extern int b_serial_deinit(bvm *vm);
|
||||
|
||||
extern int b_serial_write(bvm *vm);
|
||||
|
@ -83,6 +84,7 @@ class be_class_serial (scope: global, name: serial) {
|
|||
SERIAL_8O2, int(SERIAL_8O2)
|
||||
|
||||
init, func(b_serial_init)
|
||||
config_tx_en, func(b_config_tx_en)
|
||||
deinit, func(b_serial_deinit)
|
||||
close, func(b_serial_deinit)
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ extern int w_webserver_content_response(bvm *vm);
|
|||
extern int w_webserver_content_send_style(bvm *vm);
|
||||
extern int w_webserver_content_flush(bvm *vm);
|
||||
extern int w_webserver_content_stop(bvm *vm);
|
||||
extern int w_webserver_content_close(bvm *vm);
|
||||
extern int w_webserver_content_button(bvm *vm);
|
||||
|
||||
extern int w_webserver_html_escape(bvm *vm);
|
||||
|
@ -153,6 +154,7 @@ module webserver (scope: global) {
|
|||
content_open, func(w_webserver_content_open)
|
||||
content_start, func(w_webserver_content_start)
|
||||
content_stop, func(w_webserver_content_stop)
|
||||
content_close, func(w_webserver_content_close)
|
||||
content_button, func(w_webserver_content_button)
|
||||
|
||||
html_escape, func(w_webserver_html_escape)
|
||||
|
|
|
@ -77,7 +77,7 @@ lib_ignore = ${esp32_defaults.lib_ignore}
|
|||
ccronexpr
|
||||
|
||||
[core32]
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.04.12/platform-espressif32.zip
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.04.13/platform-espressif32.zip
|
||||
platform_packages =
|
||||
build_unflags = ${esp32_defaults.build_unflags}
|
||||
build_flags = ${esp32_defaults.build_flags}
|
||||
|
|
|
@ -20,6 +20,17 @@ build_flags = ${env:tasmota32_base.build_flags}
|
|||
-DUSE_WIFI_RANGE_EXTENDER_NAPT
|
||||
-DOTA_URL='""'
|
||||
|
||||
; remove PSRAM support -> avoid "blinking" of GPIO 16/17 at boot
|
||||
[env:tasmota32-nopsram]
|
||||
extends = env:tasmota32
|
||||
build_unflags = ${env:tasmota32_base.build_unflags}
|
||||
-DBOARD_HAS_PSRAM
|
||||
build_flags = ${env:tasmota32_base.build_flags}
|
||||
-DFIRMWARE_TASMOTA32
|
||||
-DDISABLE_PSRAMCHECK
|
||||
-DCODE_IMAGE_STR='"tasmota32-nopsram"'
|
||||
-DOTA_URL='""'
|
||||
|
||||
[env:tasmota32s3-file]
|
||||
extends = env:tasmota32_base
|
||||
board = esp32s3-qio_qspi
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
/********************************************************************
|
||||
* Generated code, don't edit
|
||||
*
|
||||
* The keys in the array belox must be in lexicographic order
|
||||
*
|
||||
* Generated by: `python3 gpio_convert.py`
|
||||
*******************************************************************/
|
||||
|
||||
const be_const_member_t lv_gpio_constants[] = {
|
||||
|
@ -143,6 +147,15 @@ const be_const_member_t lv_gpio_constants[] = {
|
|||
{ "LEDLNK", (int32_t) GPIO_LEDLNK },
|
||||
{ "LEDLNK_INV", (int32_t) GPIO_LEDLNK_INV },
|
||||
{ "LMT01", (int32_t) GPIO_LMT01 },
|
||||
{ "LORA_BUSY", (int32_t) GPIO_LORA_BUSY },
|
||||
{ "LORA_CS", (int32_t) GPIO_LORA_CS },
|
||||
{ "LORA_DI0", (int32_t) GPIO_LORA_DI0 },
|
||||
{ "LORA_DI1", (int32_t) GPIO_LORA_DI1 },
|
||||
{ "LORA_DI2", (int32_t) GPIO_LORA_DI2 },
|
||||
{ "LORA_DI3", (int32_t) GPIO_LORA_DI3 },
|
||||
{ "LORA_DI4", (int32_t) GPIO_LORA_DI4 },
|
||||
{ "LORA_DI5", (int32_t) GPIO_LORA_DI5 },
|
||||
{ "LORA_RST", (int32_t) GPIO_LORA_RST },
|
||||
{ "LOW", LOW },
|
||||
{ "LOX_O2_RX", (int32_t) GPIO_LOX_O2_RX },
|
||||
{ "MAGIC_SWITCH", (int32_t) GPIO_MAGIC_SWITCH },
|
||||
|
@ -191,6 +204,8 @@ const be_const_member_t lv_gpio_constants[] = {
|
|||
{ "OUTPUT_OPEN_DRAIN", OUTPUT_OPEN_DRAIN },
|
||||
{ "P9813_CLK", (int32_t) GPIO_P9813_CLK },
|
||||
{ "P9813_DAT", (int32_t) GPIO_P9813_DAT },
|
||||
{ "PIPSOLAR_RX", (int32_t) GPIO_PIPSOLAR_RX },
|
||||
{ "PIPSOLAR_TX", (int32_t) GPIO_PIPSOLAR_TX },
|
||||
{ "PMS5003_RX", (int32_t) GPIO_PMS5003_RX },
|
||||
{ "PMS5003_TX", (int32_t) GPIO_PMS5003_TX },
|
||||
{ "PN532_RXD", (int32_t) GPIO_PN532_RXD },
|
||||
|
@ -218,6 +233,9 @@ const be_const_member_t lv_gpio_constants[] = {
|
|||
{ "RFSEND", (int32_t) GPIO_RFSEND },
|
||||
{ "RF_SENSOR", (int32_t) GPIO_RF_SENSOR },
|
||||
{ "RISING", RISING },
|
||||
{ "RN2XX3_RST", (int32_t) GPIO_RN2XX3_RST },
|
||||
{ "RN2XX3_RX", (int32_t) GPIO_RN2XX3_RX },
|
||||
{ "RN2XX3_TX", (int32_t) GPIO_RN2XX3_TX },
|
||||
{ "ROT1A", (int32_t) GPIO_ROT1A },
|
||||
{ "ROT1A_NP", (int32_t) GPIO_ROT1A_NP },
|
||||
{ "ROT1B", (int32_t) GPIO_ROT1B },
|
||||
|
@ -290,6 +308,7 @@ const be_const_member_t lv_gpio_constants[] = {
|
|||
{ "TASMOTACLIENT_TXD", (int32_t) GPIO_TASMOTACLIENT_TXD },
|
||||
{ "TCP_RX", (int32_t) GPIO_TCP_RX },
|
||||
{ "TCP_TX", (int32_t) GPIO_TCP_TX },
|
||||
{ "TCP_TX_EN", (int32_t) GPIO_TCP_TX_EN },
|
||||
{ "TELEINFO_ENABLE", (int32_t) GPIO_TELEINFO_ENABLE },
|
||||
{ "TELEINFO_RX", (int32_t) GPIO_TELEINFO_RX },
|
||||
{ "TFMINIPLUS_RX", (int32_t) GPIO_TFMINIPLUS_RX },
|
||||
|
@ -303,6 +322,9 @@ const be_const_member_t lv_gpio_constants[] = {
|
|||
{ "TM1638CLK", (int32_t) GPIO_TM1638CLK },
|
||||
{ "TM1638DIO", (int32_t) GPIO_TM1638DIO },
|
||||
{ "TM1638STB", (int32_t) GPIO_TM1638STB },
|
||||
{ "TS_IRQ", (int32_t) GPIO_TS_IRQ },
|
||||
{ "TS_RST", (int32_t) GPIO_TS_RST },
|
||||
{ "TS_SPI_CS", (int32_t) GPIO_TS_SPI_CS },
|
||||
{ "TUYAMCUBR_RX", (int32_t) GPIO_TUYAMCUBR_RX },
|
||||
{ "TUYAMCUBR_TX", (int32_t) GPIO_TUYAMCUBR_TX },
|
||||
{ "TUYA_RX", (int32_t) GPIO_TUYA_RX },
|
||||
|
@ -334,8 +356,6 @@ const be_const_member_t lv_gpio_constants[] = {
|
|||
{ "ZIGBEE_RST", (int32_t) GPIO_ZIGBEE_RST },
|
||||
{ "ZIGBEE_RX", (int32_t) GPIO_ZIGBEE_RX },
|
||||
{ "ZIGBEE_TX", (int32_t) GPIO_ZIGBEE_TX },
|
||||
{ "PIPSOLAR_RX", (int32_t) GPIO_PIPSOLAR_RX },
|
||||
{ "PIPSOLAR_TX", (int32_t) GPIO_PIPSOLAR_TX },
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -219,6 +219,7 @@ enum UserSelectablePins {
|
|||
GPIO_LORA_CS, GPIO_LORA_RST, GPIO_LORA_BUSY, GPIO_LORA_DI0, GPIO_LORA_DI1, GPIO_LORA_DI2, GPIO_LORA_DI3, GPIO_LORA_DI4, GPIO_LORA_DI5, // LoRa SPI
|
||||
GPIO_TS_SPI_CS, GPIO_TS_RST, GPIO_TS_IRQ, // SPI for Universal Touch Screen
|
||||
GPIO_RN2XX3_TX, GPIO_RN2XX3_RX, GPIO_RN2XX3_RST, // RN2XX3 LoRaWan node Serial interface
|
||||
GPIO_TCP_TX_EN, // TCP to serial bridge, EN pin
|
||||
GPIO_SENSOR_END };
|
||||
|
||||
// Error as warning to rethink GPIO usage with max 2045
|
||||
|
@ -485,6 +486,7 @@ const char kSensorNames[] PROGMEM =
|
|||
D_GPIO_LORA_CS "|" D_GPIO_LORA_RST "|" D_GPIO_LORA_BUSY "|" D_GPIO_LORA_DI "0|" D_GPIO_LORA_DI "1|" D_GPIO_LORA_DI "2|" D_GPIO_LORA_DI "3|" D_GPIO_LORA_DI "4|" D_GPIO_LORA_DI "5|"
|
||||
D_GPIO_TS_SPI_CS "|" D_GPIO_TS_RST "|" D_GPIO_TS_IRQ "|"
|
||||
D_GPIO_RN2XX3_TX "|" D_GPIO_RN2XX3_RX "|" D_GPIO_RN2XX3_RST "|"
|
||||
D_SENSOR_TCP_TXD_EN "|"
|
||||
;
|
||||
|
||||
const char kSensorNamesFixed[] PROGMEM =
|
||||
|
@ -983,6 +985,7 @@ const uint16_t kGpioNiceList[] PROGMEM = {
|
|||
#ifdef USE_TCP_BRIDGE
|
||||
AGPIO(GPIO_TCP_TX), // TCP Serial bridge
|
||||
AGPIO(GPIO_TCP_RX), // TCP Serial bridge
|
||||
AGPIO(GPIO_TCP_TX_EN), // TCP Serial bridge EN
|
||||
#endif
|
||||
#ifdef USE_ZIGBEE
|
||||
AGPIO(GPIO_ZIGBEE_TX), // Zigbee Serial interface
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 Tx"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 Rx"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH - MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH - MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP - TX"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP - RX"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 - TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 - RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -909,6 +909,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -908,6 +908,7 @@
|
|||
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
|
||||
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
|
||||
#define D_SENSOR_TCP_TXD "TCP Tx"
|
||||
#define D_SENSOR_TCP_TXD_EN "TCP Tx En"
|
||||
#define D_SENSOR_TCP_RXD "TCP Rx"
|
||||
#define D_SENSOR_IEM3000_TX "iEM3000 TX"
|
||||
#define D_SENSOR_IEM3000_RX "iEM3000 RX"
|
||||
|
|
|
@ -40,27 +40,23 @@ const static char kWifiPhyMode[] PROGMEM = "low rate|11b|11g|HT20|HT40|HE20"; //
|
|||
#endif
|
||||
|
||||
// See libraries\ESP32\examples\ResetReason.ino
|
||||
#if ESP_IDF_VERSION_MAJOR > 3 // IDF 4+
|
||||
#include "esp_chip_info.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 // ESP32-S2
|
||||
#include "esp32s2/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3 // ESP32-S3
|
||||
#include "esp32s3/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C2 // ESP32-C2
|
||||
#include "esp32c2/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3
|
||||
#include "esp32c3/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C6 // ESP32-C6
|
||||
#include "esp32c6/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2 // ESP32-H2
|
||||
#include "esp32h2/rom/rtc.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/rtc.h"
|
||||
#include "esp_chip_info.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 // ESP32-S2
|
||||
#include "esp32s2/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3 // ESP32-S3
|
||||
#include "esp32s3/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C2 // ESP32-C2
|
||||
#include "esp32c2/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3
|
||||
#include "esp32c3/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C6 // ESP32-C6
|
||||
#include "esp32c6/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2 // ESP32-H2
|
||||
#include "esp32h2/rom/rtc.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
|
||||
// Set the Stacksize for Arduino core. Default is 8192, some builds may need a bigger one
|
||||
|
@ -204,12 +200,7 @@ void NvsInfo(void) {
|
|||
|
||||
// See Esp.cpp
|
||||
#include "Esp.h"
|
||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||
// esp_spi_flash.h is deprecated, please use spi_flash_mmap.h instead
|
||||
#include "spi_flash_mmap.h"
|
||||
#else
|
||||
#include "esp_spi_flash.h"
|
||||
#endif
|
||||
#include "spi_flash_mmap.h"
|
||||
#include <memory>
|
||||
#include <soc/soc.h>
|
||||
#include <soc/efuse_reg.h>
|
||||
|
@ -220,39 +211,34 @@ extern "C" {
|
|||
}
|
||||
#include "esp_system.h"
|
||||
#include "esp_flash.h"
|
||||
#if ESP_IDF_VERSION_MAJOR > 3 // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/spi_flash.h"
|
||||
#define ESP_FLASH_IMAGE_BASE 0x1000 // Flash offset containing magic flash size and spi mode
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 // ESP32-S2
|
||||
#include "esp32s2/rom/spi_flash.h"
|
||||
#define ESP_FLASH_IMAGE_BASE 0x1000 // Flash offset containing magic flash size and spi mode
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3 // ESP32-S3
|
||||
#include "esp32s3/rom/spi_flash.h"
|
||||
#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32s3 is located at 0x0000
|
||||
#elif CONFIG_IDF_TARGET_ESP32C2 // ESP32-C2
|
||||
#include "esp32c2/rom/spi_flash.h"
|
||||
#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32c2 is located at 0x0000
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3
|
||||
#include "esp32c3/rom/spi_flash.h"
|
||||
#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32c3 is located at 0x0000
|
||||
#elif CONFIG_IDF_TARGET_ESP32C6 // ESP32-C6
|
||||
#include "esp32c6/rom/spi_flash.h"
|
||||
#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32c6 is located at 0x0000
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2 // ESP32-H2
|
||||
#include "esp32h2/rom/spi_flash.h"
|
||||
#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32h2 is located at 0x0000
|
||||
#else
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/spi_flash.h"
|
||||
#define ESP_FLASH_IMAGE_BASE 0x1000 // Flash offset containing magic flash size and spi mode
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 // ESP32-S2
|
||||
#include "esp32s2/rom/spi_flash.h"
|
||||
#define ESP_FLASH_IMAGE_BASE 0x1000 // Flash offset containing magic flash size and spi mode
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3 // ESP32-S3
|
||||
#include "esp32s3/rom/spi_flash.h"
|
||||
#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32s3 is located at 0x0000
|
||||
#elif CONFIG_IDF_TARGET_ESP32C2 // ESP32-C2
|
||||
#include "esp32c2/rom/spi_flash.h"
|
||||
#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32c2 is located at 0x0000
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3
|
||||
#include "esp32c3/rom/spi_flash.h"
|
||||
#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32c3 is located at 0x0000
|
||||
#elif CONFIG_IDF_TARGET_ESP32C6 // ESP32-C6
|
||||
#include "esp32c6/rom/spi_flash.h"
|
||||
#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32c6 is located at 0x0000
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2 // ESP32-H2
|
||||
#include "esp32h2/rom/spi_flash.h"
|
||||
#define ESP_FLASH_IMAGE_BASE 0x0000 // Esp32h2 is located at 0x0000
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/spi_flash.h"
|
||||
#define ESP_FLASH_IMAGE_BASE 0x1000
|
||||
#endif
|
||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||
#include "bootloader_common.h"
|
||||
#endif
|
||||
|
||||
#include "bootloader_common.h"
|
||||
|
||||
uint32_t EspProgramSize(const char *label) {
|
||||
const esp_partition_t *part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, label);
|
||||
if (!part) {
|
||||
|
@ -462,7 +448,7 @@ uint32_t ESP_getFlashChipMagicSize(void) {
|
|||
}
|
||||
|
||||
uint32_t ESP_magicFlashChipSize(uint8_t spi_size) {
|
||||
/*
|
||||
/*
|
||||
switch(spi_size & 0x0F) {
|
||||
case 0x0: // 8 MBit (1MB)
|
||||
return 1048576;
|
||||
|
@ -477,7 +463,7 @@ uint32_t ESP_magicFlashChipSize(uint8_t spi_size) {
|
|||
case 0x5: // 256 MBit (32MB)
|
||||
return 33554432;
|
||||
default: // fail so return (1KB)
|
||||
return 1024;
|
||||
return 1024;
|
||||
}
|
||||
*/
|
||||
// When spi_size is bigger than 11 will return 0 (0x100000000 = 0x00000000)
|
||||
|
@ -590,14 +576,10 @@ extern "C" {
|
|||
// `psramFound()` can return true even if no PSRAM is actually installed
|
||||
// This new version also checks `esp_spiram_is_initialized` to know if the PSRAM is initialized
|
||||
bool FoundPSRAM(void) {
|
||||
#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
|
||||
#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || DISABLE_PSRAMCHECK
|
||||
return psramFound();
|
||||
#else
|
||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||
return psramFound() && esp_psram_is_initialized();
|
||||
#else
|
||||
return psramFound() && esp_spiram_is_initialized();
|
||||
#endif
|
||||
return psramFound() && esp_psram_is_initialized();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -774,9 +756,6 @@ typedef struct {
|
|||
- Peripherals include capacitive touch sensors, Hall sensor, SD card interface, Ethernet, high-speed SPI, UART, I2S and I2C
|
||||
*/
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
#if (ESP_IDF_VERSION_MAJOR < 5)
|
||||
pkg_version = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG) & 0x7;
|
||||
#endif
|
||||
|
||||
// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("HDW: ESP32 Model %d, Revision %d, Core %d"), chip_info.model, chip_revision, chip_info.cores);
|
||||
|
||||
|
@ -816,9 +795,6 @@ typedef struct {
|
|||
- Availability of common cloud connectivity agents and common product features shortens the time to market
|
||||
*/
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S2
|
||||
#if (ESP_IDF_VERSION_MAJOR < 5)
|
||||
pkg_version = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_3_REG, EFUSE_FLASH_VERSION) & 0xF;
|
||||
#endif
|
||||
uint32_t psram_ver = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_3_REG, EFUSE_PSRAM_VERSION);
|
||||
pkg_version += ((psram_ver & 0xF) * 100);
|
||||
|
||||
|
@ -846,9 +822,6 @@ typedef struct {
|
|||
- Rich set of peripheral interfaces and GPIOs, ideal for various scenarios and complex applications
|
||||
*/
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C3
|
||||
#if (ESP_IDF_VERSION_MAJOR < 5)
|
||||
pkg_version = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_3_REG, EFUSE_PKG_VERSION) & 0x7;
|
||||
#endif
|
||||
switch (pkg_version) {
|
||||
case 0: return F("ESP32-C3"); // Max 160MHz, Single core, QFN 5*5, ESP32-C3-WROOM-02, ESP32-C3-DevKitC-02
|
||||
// case 1: return F("ESP32-C3FH4"); // Max 160MHz, Single core, QFN 5*5, 4MB embedded flash, ESP32-C3-MINI-1, ESP32-C3-DevKitM-1
|
||||
|
@ -872,12 +845,10 @@ typedef struct {
|
|||
- Reliable security features ensured by RSA-based secure boot, AES-XTS-based flash encryption, the innovative digital signature and the HMAC peripheral, “World Controller”
|
||||
*/
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S3
|
||||
#if (ESP_IDF_VERSION_MAJOR >= 5)
|
||||
switch (pkg_version) {
|
||||
case 0: return F("ESP32-S3"); // QFN56
|
||||
case 1: return F("ESP32-S3-PICO-1"); // LGA56
|
||||
}
|
||||
#endif
|
||||
#endif // CONFIG_IDF_TARGET_ESP32S3
|
||||
return F("ESP32-S3"); // Max 240MHz, Dual core, QFN 7*7, ESP32-S3-WROOM-1, ESP32-S3-DevKitC-1
|
||||
}
|
||||
|
@ -989,29 +960,13 @@ String WifiGetPhyMode(void) {
|
|||
* Thanks to DigitalAlchemist
|
||||
\*********************************************************************************************/
|
||||
|
||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||
#include <esp_random.h>
|
||||
#endif
|
||||
|
||||
// Based on code from https://raw.githubusercontent.com/espressif/esp-idf/master/components/esp32/hw_random.c
|
||||
uint32_t HwRandom(void) {
|
||||
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||
// See for more info on the HW RNG:
|
||||
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/system/random.html
|
||||
return esp_random();
|
||||
#else
|
||||
#define _RAND_ADDR 0x3FF75144UL
|
||||
static uint32_t last_ccount = 0;
|
||||
uint32_t ccount;
|
||||
uint32_t result = 0;
|
||||
do {
|
||||
ccount = ESP.getCycleCount();
|
||||
result ^= *(volatile uint32_t *)_RAND_ADDR;
|
||||
} while (ccount - last_ccount < 64);
|
||||
last_ccount = ccount;
|
||||
return result ^ *(volatile uint32_t *)_RAND_ADDR;
|
||||
#undef _RAND_ADDR
|
||||
#endif // ESP_IDF_VERSION_MAJOR >= 5
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
|
|
@ -1469,6 +1469,19 @@ void WifiEvents(arduino_event_t *event) {
|
|||
IPv6isLocal(addr) ? PSTR("Local") : PSTR("Global"), addr.toString(true).c_str());
|
||||
}
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
||||
// workaround for the race condition in LWIP, see https://github.com/espressif/arduino-esp32/pull/9016#discussion_r1451774885
|
||||
{
|
||||
uint32_t i = 5; // try 5 times only
|
||||
while (esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_STA)) != ESP_OK) {
|
||||
delay(1);
|
||||
if (i-- == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif // USE_IPV6
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
{
|
||||
|
|
|
@ -151,6 +151,10 @@ void TCPInit(void) {
|
|||
}
|
||||
TCPSerial = new TasmotaSerial(Pin(GPIO_TCP_RX), Pin(GPIO_TCP_TX), TasmotaGlobal.seriallog_level ? 1 : 2, 0, TCP_BRIDGE_BUF_SIZE); // set a receive buffer of 256 bytes
|
||||
tcp_serial = TCPSerial->begin(Settings->tcp_baudrate * 1200, ConvertSerialConfig(0x7F & Settings->tcp_config));
|
||||
if (PinUsed(GPIO_TCP_TX_EN)) {
|
||||
TCPSerial->setTransmitEnablePin(Pin(GPIO_TCP_TX_EN));
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_TCP "TCP Bridge EN is used on Pin %d"), Pin(GPIO_TCP_TX_EN));
|
||||
}
|
||||
if (tcp_serial) {
|
||||
if (TCPSerial->hardwareSerial()) {
|
||||
ClaimSerial();
|
||||
|
|
|
@ -1,772 +0,0 @@
|
|||
/*
|
||||
xdrv_42_i2s_audio.ino - Audio dac support for Tasmota
|
||||
|
||||
Copyright (C) 2021 Gerhard Mutz and Theo Arends
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if ESP8266 || (ESP_IDF_VERSION_MAJOR < 5)
|
||||
#if (defined(USE_I2S_AUDIO) || defined(USE_TTGO_WATCH) || defined(USE_M5STACK_CORE2) || defined(ESP32S3_BOX))
|
||||
/*********************************************************************************************\
|
||||
* I2S support using an external DAC or a speaker connected to GPIO03 using a transistor
|
||||
*
|
||||
* Uses fixed GPIOs for ESP8266:
|
||||
* I2S Out Data GPIO03 (Rx)
|
||||
* I2S Out Bit Clock GPIO15
|
||||
* I2S Out Word Select GPIO02
|
||||
* I2S In Data GPIO12
|
||||
* I2S In Bit Clock GPIO13
|
||||
* I2S In Word Select GPIO14
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XDRV_42 42
|
||||
|
||||
#define USE_I2S_EXTERNAL_DAC 1
|
||||
//#define USE_I2S_NO_DAC // Add support for transistor-based output without DAC
|
||||
//#define USE_I2S_WEBRADIO // Add support for web radio
|
||||
//#define USE_I2S_SAY_TIME // Add support for english speaking clock
|
||||
//#define USE_I2S_RTTTL // Add support for Rtttl playback
|
||||
//#define USE_LSB // Add support for LSBJ chips, e.g. TM8211/PT8211
|
||||
// Microphone support
|
||||
//#define USE_I2S_MIC // Add support for I2S microphone
|
||||
//#define MIC_CHANNELS 1 // 1 = mono (I2S_CHANNEL_FMT_ONLY_RIGHT), 2 = stereo (I2S_CHANNEL_FMT_RIGHT_LEFT)
|
||||
//#define MICSRATE 32000 // Set sample rate
|
||||
//#define USE_INMP441 // Add support for INMP441 MEMS microphone
|
||||
//#define MIC_PDM // Set microphone as PDM (only on ESP32)
|
||||
//#define USE_SHINE // Use MP3 encoding (only on ESP32 with PSRAM)
|
||||
//#define MP3_MIC_STREAM // Add support for streaming microphone via http (only on ESP32 with PSRAM)
|
||||
//#define MP3_STREAM_PORT 81 // Choose MP3 stream port (default = 81)
|
||||
//#define I2S_BRIDGE // Add support for UDP PCM audio bridge
|
||||
//#define I2S_BRIDGE_PORT 6970 // Set bridge port (default = 6970)
|
||||
|
||||
#include "AudioFileSourcePROGMEM.h"
|
||||
#include "AudioFileSourceID3.h"
|
||||
#include "AudioGeneratorMP3.h"
|
||||
#ifdef USE_I2S_NO_DAC
|
||||
#include "AudioOutputI2SNoDAC.h" // Transistor-driven lower quality connected to RX pin
|
||||
#else
|
||||
#include "AudioOutputI2S.h" // External I2S DAC IC
|
||||
#endif // USE_I2S_NO_DAC
|
||||
#include <ESP8266SAM.h>
|
||||
#include "AudioFileSourceFS.h"
|
||||
#ifdef USE_I2S_SAY_TIME
|
||||
#include "AudioGeneratorTalkie.h"
|
||||
#endif // USE_I2S_SAY_TIME
|
||||
#include "AudioFileSourceICYStream.h"
|
||||
#include "AudioFileSourceBuffer.h"
|
||||
#include "AudioGeneratorAAC.h"
|
||||
|
||||
#ifdef ESP32
|
||||
#include <driver/i2s.h>
|
||||
#endif
|
||||
|
||||
#undef AUDIO_PWR_ON
|
||||
#undef AUDIO_PWR_OFF
|
||||
#define AUDIO_PWR_ON
|
||||
#define AUDIO_PWR_OFF
|
||||
|
||||
#ifdef ESP8266
|
||||
#define i2s_port_t uint8_t
|
||||
#endif
|
||||
|
||||
#define MODE_MIC 1
|
||||
#define MODE_SPK 2
|
||||
|
||||
#ifndef MICSRATE
|
||||
#define MICSRATE 32000
|
||||
#endif
|
||||
|
||||
|
||||
typedef union {
|
||||
uint8_t data;
|
||||
struct {
|
||||
uint8_t master : 1;
|
||||
uint8_t enabled : 1;
|
||||
uint8_t swap_mic : 1;
|
||||
uint8_t mode : 2;
|
||||
};
|
||||
} BRIDGE_MODE;
|
||||
|
||||
|
||||
struct AUDIO_I2S_t {
|
||||
uint8_t is2_volume; // should be in settings
|
||||
i2s_port_t i2s_port;
|
||||
int8_t mclk = -1;
|
||||
int8_t bclk = -1;
|
||||
int8_t ws = -1;
|
||||
int8_t dout = -1;
|
||||
int8_t din = -1;
|
||||
AudioGeneratorMP3 *mp3 = nullptr;
|
||||
AudioFileSourceFS *file;
|
||||
#ifdef USE_I2S_NO_DAC
|
||||
AudioOutputI2SNoDAC *out;
|
||||
#else
|
||||
AudioOutputI2S *out;
|
||||
#endif // USE_I2S_NO_DAC
|
||||
AudioFileSourceID3 *id3;
|
||||
AudioGeneratorMP3 *decoder = NULL;
|
||||
void *mp3ram = NULL;
|
||||
#ifdef USE_I2S_WEBRADIO
|
||||
AudioFileSourceICYStream *ifile = NULL;
|
||||
AudioFileSourceBuffer *buff = NULL;
|
||||
char wr_title[64];
|
||||
void *preallocateBuffer = NULL;
|
||||
void *preallocateCodec = NULL;
|
||||
uint32_t retryms = 0;
|
||||
#endif // USE_I2S_WEBRADIO
|
||||
|
||||
#ifdef ESP32
|
||||
TaskHandle_t mp3_task_h;
|
||||
TaskHandle_t mic_task_h;
|
||||
#endif // ESP32
|
||||
uint32_t mic_size;
|
||||
uint32_t mic_rate;
|
||||
uint8_t *mic_buff;
|
||||
char mic_path[32];
|
||||
uint8_t mic_channels;
|
||||
File fwp;
|
||||
uint8_t mic_stop;
|
||||
int8_t mic_error;
|
||||
int8_t mic_mclk = -1;
|
||||
int8_t mic_bclk = -1;
|
||||
int8_t mic_ws = -1;
|
||||
int8_t mic_din = -1;
|
||||
int8_t mic_dout = -1;
|
||||
uint8_t mic_gain = 1;
|
||||
bool use_stream = false;
|
||||
i2s_port_t mic_port;
|
||||
|
||||
|
||||
#ifdef USE_SHINE
|
||||
uint32_t recdur;
|
||||
uint8_t stream_active;
|
||||
uint8_t stream_enable;
|
||||
WiFiClient client;
|
||||
ESP8266WebServer *MP3Server;
|
||||
#endif
|
||||
|
||||
uint8_t mode;
|
||||
|
||||
#ifdef I2S_BRIDGE
|
||||
BRIDGE_MODE bridge_mode;
|
||||
WiFiUDP i2s_bridge_udp;
|
||||
WiFiUDP i2s_bridgec_udp;
|
||||
IPAddress i2s_bridge_ip;
|
||||
TaskHandle_t i2s_bridge_h;
|
||||
int8_t ptt_pin = -1;
|
||||
#endif
|
||||
|
||||
|
||||
} audio_i2s;
|
||||
|
||||
#ifndef MIC_CHANNELS
|
||||
#define MIC_CHANNELS 1
|
||||
#endif
|
||||
|
||||
#ifdef USE_TTGO_WATCH
|
||||
#undef AUDIO_PWR_ON
|
||||
#undef AUDIO_PWR_OFF
|
||||
#define AUDIO_PWR_ON TTGO_audio_power(true);
|
||||
#define AUDIO_PWR_OFF TTGO_audio_power(false);
|
||||
#endif // USE_TTGO_WATCH
|
||||
|
||||
#ifdef USE_M5STACK_CORE2
|
||||
// leave this predefined currently
|
||||
#undef AUDIO_PWR_ON
|
||||
#undef AUDIO_PWR_OFF
|
||||
#define AUDIO_PWR_ON Core2AudioPower(true);
|
||||
#define AUDIO_PWR_OFF Core2AudioPower(false);
|
||||
#undef DAC_IIS_BCK
|
||||
#undef DAC_IIS_WS
|
||||
#undef DAC_IIS_DOUT
|
||||
#undef DAC_IIS_DIN
|
||||
#define DAC_IIS_BCK 12
|
||||
#define DAC_IIS_WS 0
|
||||
#define DAC_IIS_DOUT 2
|
||||
#define DAC_IIS_DIN 34
|
||||
#undef MICSRATE
|
||||
#define MICSRATE 32000
|
||||
#undef MIC_CHANNELS
|
||||
#define MIC_CHANNELS 1
|
||||
#endif // USE_M5STACK_CORE2
|
||||
|
||||
|
||||
#ifdef ESP32S3_BOX
|
||||
#undef AUDIO_PWR_ON
|
||||
#undef AUDIO_PWR_OFF
|
||||
#define AUDIO_PWR_ON S3boxAudioPower(true);
|
||||
#define AUDIO_PWR_OFF S3boxAudioPower(false);
|
||||
#undef MIC_CHANNELS
|
||||
#define MIC_CHANNELS 2
|
||||
#endif // ESP32S3_BOX
|
||||
|
||||
extern FS *ufsp;
|
||||
extern FS *ffsp;
|
||||
|
||||
#ifdef ESP8266
|
||||
const int preallocateBufferSize = 5*1024;
|
||||
const int preallocateCodecSize = 29192; // MP3 codec max mem needed
|
||||
#endif // ESP8266
|
||||
|
||||
#ifdef ESP32
|
||||
const int preallocateBufferSize = 16*1024;
|
||||
const int preallocateCodecSize = 29192; // MP3 codec max mem needed
|
||||
//const int preallocateCodecSize = 85332; // AAC+SBR codec max mem needed
|
||||
#endif // ESP32
|
||||
|
||||
enum : int { APLL_AUTO = -1, APLL_ENABLE = 1, APLL_DISABLE = 0 };
|
||||
enum : int { EXTERNAL_I2S = 0, INTERNAL_DAC = 1, INTERNAL_PDM = 2 };
|
||||
|
||||
#ifdef ESP8266
|
||||
#define I2S_MCLK_MULTIPLE_128 0
|
||||
#endif
|
||||
|
||||
void sayTime(int hour, int minutes);
|
||||
void Cmd_MicRec(void);
|
||||
void Cmd_wav2mp3(void);
|
||||
void Cmd_Time(void);
|
||||
#ifdef USE_I2S_RTTTL
|
||||
void Rtttl(char *buffer);
|
||||
void Cmd_I2SRtttl(void);
|
||||
#endif
|
||||
|
||||
void copy_micpars(uint32_t port) {
|
||||
audio_i2s.mic_mclk = audio_i2s.mclk;
|
||||
audio_i2s.mic_bclk = audio_i2s.bclk;
|
||||
audio_i2s.mic_ws = audio_i2s.ws;
|
||||
audio_i2s.mic_dout = audio_i2s.dout;
|
||||
audio_i2s.mic_din = audio_i2s.din;
|
||||
audio_i2s.mic_port = (i2s_port_t)port;
|
||||
}
|
||||
|
||||
int32_t I2S_Init_0(void) {
|
||||
|
||||
audio_i2s.i2s_port = (i2s_port_t)0;
|
||||
audio_i2s.mic_port = (i2s_port_t)0;
|
||||
|
||||
#if USE_I2S_EXTERNAL_DAC
|
||||
// use i2s
|
||||
#if (defined(USE_I2S_NO_DAC) && defined(DAC_IIS_DOUT)) || (defined(DAC_IIS_BCK) && defined(DAC_IIS_WS) && defined(DAC_IIS_DOUT))
|
||||
audio_i2s.i2s_port = (i2s_port_t)0;
|
||||
#ifdef USE_I2S_NO_DAC
|
||||
audio_i2s.out = new AudioOutputI2SNoDAC();
|
||||
#else
|
||||
audio_i2s.out = new AudioOutputI2S();
|
||||
#endif
|
||||
|
||||
audio_i2s.bclk = DAC_IIS_BCK;
|
||||
audio_i2s.ws = DAC_IIS_WS;
|
||||
audio_i2s.dout = DAC_IIS_DOUT;
|
||||
audio_i2s.din = DAC_IIS_DIN;
|
||||
|
||||
copy_micpars(0);
|
||||
|
||||
#else
|
||||
#ifdef USE_I2S_NO_DAC
|
||||
if (PinUsed(GPIO_I2S_DOUT)) {
|
||||
#else
|
||||
if (PinUsed(GPIO_I2S_BCLK) && PinUsed(GPIO_I2S_WS) && PinUsed(GPIO_I2S_DOUT)) {
|
||||
#endif // USE_I2S_NO_DAC
|
||||
audio_i2s.i2s_port = (i2s_port_t)0;
|
||||
#ifdef USE_I2S_NO_DAC
|
||||
audio_i2s.out = new AudioOutputI2SNoDAC();
|
||||
#else
|
||||
//audio_i2s.out = new AudioOutputI2S(audio_i2s.i2s_port);
|
||||
audio_i2s.out = new AudioOutputI2S(audio_i2s.i2s_port, EXTERNAL_I2S, 8, APLL_DISABLE, I2S_MCLK_MULTIPLE_128, 12000000);
|
||||
#endif // USE_I2S_NO_DAC
|
||||
audio_i2s.mclk = Pin(GPIO_I2S_MCLK);
|
||||
audio_i2s.bclk = Pin(GPIO_I2S_BCLK);
|
||||
audio_i2s.ws = Pin(GPIO_I2S_WS);
|
||||
audio_i2s.dout = Pin(GPIO_I2S_DOUT);
|
||||
audio_i2s.din = Pin(GPIO_I2S_DIN);
|
||||
|
||||
copy_micpars(0);
|
||||
|
||||
// check if 2 ports used, use second for micro
|
||||
if (PinUsed(GPIO_I2S_BCLK, 1) && PinUsed(GPIO_I2S_WS, 1) && PinUsed(GPIO_I2S_DIN, 1)) {
|
||||
audio_i2s.mic_bclk = -1;
|
||||
audio_i2s.mic_bclk = Pin(GPIO_I2S_BCLK, 1);
|
||||
audio_i2s.mic_ws = Pin(GPIO_I2S_WS, 1);
|
||||
audio_i2s.mic_dout = -1;
|
||||
audio_i2s.mic_din = Pin(GPIO_I2S_DIN, 1);
|
||||
audio_i2s.mic_port = (i2s_port_t)1;
|
||||
}
|
||||
} else if (PinUsed(GPIO_I2S_BCLK, 1) && PinUsed(GPIO_I2S_WS, 1) && PinUsed(GPIO_I2S_DOUT, 1)) {
|
||||
audio_i2s.i2s_port = (i2s_port_t)1;
|
||||
#ifdef USE_I2S_NO_DAC
|
||||
audio_i2s.out = new AudioOutputI2SNoDAC();
|
||||
#else
|
||||
//audio_i2s.out = new AudioOutputI2S(audio_i2s.i2s_port);
|
||||
audio_i2s.out = new AudioOutputI2S(audio_i2s.i2s_port, EXTERNAL_I2S, 8, APLL_DISABLE, I2S_MCLK_MULTIPLE_128, 12000000);
|
||||
#endif // USE_I2S_NO_DAC
|
||||
audio_i2s.mclk = Pin(GPIO_I2S_MCLK, 1);
|
||||
audio_i2s.bclk = Pin(GPIO_I2S_BCLK, 1);
|
||||
audio_i2s.ws = Pin(GPIO_I2S_WS, 1);
|
||||
audio_i2s.dout = Pin(GPIO_I2S_DOUT, 1);
|
||||
audio_i2s.din = Pin(GPIO_I2S_DIN, 1);
|
||||
|
||||
copy_micpars(1);
|
||||
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
#ifdef ESP8266
|
||||
// esp8266 have fixed pins
|
||||
if ((audio_i2s.bclk != 15) || (audio_i2s.ws != 2) || (audio_i2s.dout != 3)) {
|
||||
return -2;
|
||||
}
|
||||
#endif // ESP8266
|
||||
#endif // defined(DAC_IIS_BCK)
|
||||
|
||||
audio_i2s.out->SetPinout(audio_i2s.bclk, audio_i2s.ws, audio_i2s.dout, audio_i2s.mclk, audio_i2s.din);
|
||||
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("Init audio I2S: port=%d, bclk=%d, ws=%d, dout=%d, mclk=%d, din=%d"), audio_i2s.i2s_port, audio_i2s.bclk, audio_i2s.ws, audio_i2s.dout, audio_i2s.mclk, audio_i2s.din);
|
||||
if (audio_i2s.mic_port != 0) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("Init audio I2S mic: port=%d, bclk=%d, ws=%d, din=%d"), audio_i2s.mic_port, audio_i2s.mic_bclk, audio_i2s.mic_ws, audio_i2s.mic_din);
|
||||
}
|
||||
|
||||
#ifdef USE_I2S_LSB
|
||||
audio_i2s.out->SetLsbJustified(true);
|
||||
#endif // Allow supporting LSBJ chips, e.g. TM8211/PT8211
|
||||
|
||||
#else
|
||||
|
||||
#ifdef USE_I2S_NO_DAC
|
||||
audio_i2s.out = new AudioOutputI2SNoDAC();
|
||||
#else
|
||||
audio_i2s.out = new AudioOutputI2S(0, 1); // Internal DAC port 0
|
||||
#endif // USE_I2S_NO_DAC
|
||||
|
||||
#endif // USE_I2S_EXTERNAL_DAC
|
||||
|
||||
audio_i2s.mode = MODE_SPK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void I2S_Init(void) {
|
||||
|
||||
if (I2S_Init_0()) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(ESP32) && defined(ESP32S3_BOX)
|
||||
S3boxInit();
|
||||
#endif
|
||||
|
||||
#ifdef USE_W8960
|
||||
W8960_Init1();
|
||||
#endif
|
||||
|
||||
audio_i2s.is2_volume = 10;
|
||||
audio_i2s.out->SetGain(((float)audio_i2s.is2_volume / 100.0) * 4.0);
|
||||
audio_i2s.out->begin();
|
||||
audio_i2s.out->stop();
|
||||
audio_i2s.mp3ram = nullptr;
|
||||
|
||||
#ifdef ESP32
|
||||
if (UsePSRAM()) {
|
||||
audio_i2s.mp3ram = heap_caps_malloc(preallocateCodecSize, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
}
|
||||
|
||||
#ifdef USE_I2S_WEBRADIO
|
||||
if (UsePSRAM()) {
|
||||
audio_i2s.preallocateBuffer = heap_caps_malloc(preallocateBufferSize, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
audio_i2s.preallocateCodec = heap_caps_malloc(preallocateCodecSize, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
} else {
|
||||
audio_i2s.preallocateBuffer = malloc(preallocateBufferSize);
|
||||
audio_i2s.preallocateCodec = malloc(preallocateCodecSize);
|
||||
}
|
||||
if (!audio_i2s.preallocateBuffer || !audio_i2s.preallocateCodec) {
|
||||
//Serial.printf_P(PSTR("FATAL ERROR: Unable to preallocate %d bytes for app\n"), preallocateBufferSize+preallocateCodecSize);
|
||||
}
|
||||
#endif // USE_I2S_WEBRADIO
|
||||
|
||||
audio_i2s.mic_channels = MIC_CHANNELS;
|
||||
audio_i2s.mic_rate = MICSRATE;
|
||||
|
||||
#ifdef USE_I2S_COMMON_IO
|
||||
i2s_set_clk(audio_i2s.mic_port, audio_i2s.mic_rate, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_STEREO);
|
||||
#endif
|
||||
|
||||
#endif // ESP32
|
||||
|
||||
}
|
||||
|
||||
#ifdef ESP32
|
||||
void mp3_task(void *arg) {
|
||||
while (1) {
|
||||
while (audio_i2s.mp3->isRunning()) {
|
||||
if (!audio_i2s.mp3->loop()) {
|
||||
audio_i2s.mp3->stop();
|
||||
mp3_delete();
|
||||
audio_i2s.out->stop();
|
||||
if (audio_i2s.mp3_task_h) {
|
||||
vTaskDelete(audio_i2s.mp3_task_h);
|
||||
audio_i2s.mp3_task_h = 0;
|
||||
}
|
||||
//mp3_task_h=nullptr;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // ESP32
|
||||
|
||||
#ifdef USE_I2S_WEBRADIO
|
||||
void MDCallback(void *cbData, const char *type, bool isUnicode, const char *str) {
|
||||
const char *ptr = reinterpret_cast<const char *>(cbData);
|
||||
(void) isUnicode; // Punt this ball for now
|
||||
(void) ptr;
|
||||
if (strstr_P(type, PSTR("Title"))) {
|
||||
strncpy(audio_i2s.wr_title, str, sizeof(audio_i2s.wr_title));
|
||||
audio_i2s.wr_title[sizeof(audio_i2s.wr_title)-1] = 0;
|
||||
//AddLog(LOG_LEVEL_INFO,PSTR("WR-Title: %s"),wr_title);
|
||||
} else {
|
||||
// Who knows what to do? Not me!
|
||||
}
|
||||
}
|
||||
|
||||
void StatusCallback(void *cbData, int code, const char *string) {
|
||||
const char *ptr = reinterpret_cast<const char *>(cbData);
|
||||
(void) code;
|
||||
(void) ptr;
|
||||
//strncpy_P(status, string, sizeof(status)-1);
|
||||
//status[sizeof(status)-1] = 0;
|
||||
}
|
||||
|
||||
void Webradio(const char *url) {
|
||||
if (audio_i2s.decoder || audio_i2s.mp3) return;
|
||||
if (!audio_i2s.out) return;
|
||||
AUDIO_PWR_ON
|
||||
audio_i2s.ifile = new AudioFileSourceICYStream(url);
|
||||
audio_i2s.ifile->RegisterMetadataCB(MDCallback, NULL);
|
||||
audio_i2s.buff = new AudioFileSourceBuffer(audio_i2s.ifile, audio_i2s.preallocateBuffer, preallocateBufferSize);
|
||||
audio_i2s.buff->RegisterStatusCB(StatusCallback, NULL);
|
||||
audio_i2s.decoder = new AudioGeneratorMP3(audio_i2s.preallocateCodec, preallocateCodecSize);
|
||||
audio_i2s.decoder->RegisterStatusCB(StatusCallback, NULL);
|
||||
audio_i2s.decoder->begin(audio_i2s.buff, audio_i2s.out);
|
||||
if (!audio_i2s.decoder->isRunning()) {
|
||||
// Serial.printf_P(PSTR("Can't connect to URL"));
|
||||
StopPlaying();
|
||||
// strcpy_P(status, PSTR("Unable to connect to URL"));
|
||||
audio_i2s.retryms = millis() + 2000;
|
||||
}
|
||||
|
||||
xTaskCreatePinnedToCore(mp3_task2, "MP3-2", 8192, NULL, 3, &audio_i2s.mp3_task_h, 1);
|
||||
}
|
||||
|
||||
void mp3_task2(void *arg){
|
||||
while (1) {
|
||||
if (audio_i2s.decoder && audio_i2s.decoder->isRunning()) {
|
||||
if (!audio_i2s.decoder->loop()) {
|
||||
StopPlaying();
|
||||
//retryms = millis() + 2000;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StopPlaying() {
|
||||
|
||||
if (audio_i2s.mp3_task_h) {
|
||||
vTaskDelete(audio_i2s.mp3_task_h);
|
||||
audio_i2s.mp3_task_h = nullptr;
|
||||
}
|
||||
|
||||
if (audio_i2s.decoder) {
|
||||
audio_i2s.decoder->stop();
|
||||
delete audio_i2s.decoder;
|
||||
audio_i2s.decoder = NULL;
|
||||
}
|
||||
|
||||
if (audio_i2s.buff) {
|
||||
audio_i2s.buff->close();
|
||||
delete audio_i2s.buff;
|
||||
audio_i2s.buff = NULL;
|
||||
}
|
||||
|
||||
if (audio_i2s.ifile) {
|
||||
audio_i2s.ifile->close();
|
||||
delete audio_i2s.ifile;
|
||||
audio_i2s.ifile = NULL;
|
||||
}
|
||||
AUDIO_PWR_OFF
|
||||
}
|
||||
|
||||
void Cmd_WebRadio(void) {
|
||||
if (!audio_i2s.out) return;
|
||||
|
||||
if (audio_i2s.decoder) {
|
||||
StopPlaying();
|
||||
}
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
Webradio(XdrvMailbox.data);
|
||||
ResponseCmndChar(XdrvMailbox.data);
|
||||
} else {
|
||||
ResponseCmndChar_P(PSTR("Stopped"));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
const char HTTP_WEBRADIO[] PROGMEM =
|
||||
"{s}" "I2S_WR-Title" "{m}%s{e}";
|
||||
|
||||
void I2S_WR_Show(bool json) {
|
||||
if (audio_i2s.decoder) {
|
||||
if (json) {
|
||||
ResponseAppend_P(PSTR(",\"WebRadio\":{\"Title\":\"%s\"}"), audio_i2s.wr_title);
|
||||
} else {
|
||||
WSContentSend_PD(HTTP_WEBRADIO,audio_i2s.wr_title);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
#endif // USE_I2S_WEBRADIO
|
||||
|
||||
|
||||
#ifdef ESP32
|
||||
void Play_mp3(const char *path) {
|
||||
#ifdef USE_UFILESYS
|
||||
if (audio_i2s.decoder || audio_i2s.mp3) return;
|
||||
if (!audio_i2s.out) return;
|
||||
|
||||
bool I2S_Task;
|
||||
|
||||
if (*path=='+') {
|
||||
I2S_Task = true;
|
||||
path++;
|
||||
} else {
|
||||
I2S_Task = false;
|
||||
}
|
||||
|
||||
FS *mp3fsp = ufsp;
|
||||
|
||||
if (!strncmp(path, "/ffs", 4)) {
|
||||
path += 4;
|
||||
mp3fsp = ffsp;
|
||||
}
|
||||
|
||||
if (!mp3fsp->exists(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
AUDIO_PWR_ON
|
||||
|
||||
audio_i2s.file = new AudioFileSourceFS(*mp3fsp, path);
|
||||
|
||||
audio_i2s.id3 = new AudioFileSourceID3(audio_i2s.file);
|
||||
|
||||
if (audio_i2s.mp3ram) {
|
||||
audio_i2s.mp3 = new AudioGeneratorMP3(audio_i2s.mp3ram, preallocateCodecSize);
|
||||
} else {
|
||||
audio_i2s.mp3 = new AudioGeneratorMP3();
|
||||
}
|
||||
audio_i2s.mp3->begin(audio_i2s.id3, audio_i2s.out);
|
||||
|
||||
if (I2S_Task) {
|
||||
xTaskCreatePinnedToCore(mp3_task, "MP3", 8192, NULL, 3, &audio_i2s.mp3_task_h, 1);
|
||||
} else {
|
||||
#define MP3_TIMEOUT 30000
|
||||
uint32_t tout = millis();
|
||||
while (audio_i2s.mp3->isRunning()) {
|
||||
if (!audio_i2s.mp3->loop()) {
|
||||
audio_i2s.mp3->stop();
|
||||
break;
|
||||
}
|
||||
OsWatchLoop();
|
||||
if (millis()-tout > MP3_TIMEOUT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
audio_i2s.out->stop();
|
||||
mp3_delete();
|
||||
}
|
||||
|
||||
#endif // USE_UFILESYS
|
||||
}
|
||||
|
||||
void mp3_delete(void) {
|
||||
delete audio_i2s.file;
|
||||
delete audio_i2s.id3;
|
||||
delete audio_i2s.mp3;
|
||||
audio_i2s.mp3=nullptr;
|
||||
AUDIO_PWR_OFF
|
||||
}
|
||||
#endif // ESP32
|
||||
|
||||
void Say(char *text) {
|
||||
|
||||
if (!audio_i2s.out) return;
|
||||
|
||||
AUDIO_PWR_ON
|
||||
|
||||
audio_i2s.out->begin();
|
||||
ESP8266SAM *sam = new ESP8266SAM;
|
||||
sam->Say(audio_i2s.out, text);
|
||||
delete sam;
|
||||
audio_i2s.out->stop();
|
||||
|
||||
AUDIO_PWR_OFF
|
||||
}
|
||||
|
||||
|
||||
const char kI2SAudio_Commands[] PROGMEM = "I2S|"
|
||||
"Say|Gain"
|
||||
#ifdef USE_I2S_SAY_TIME
|
||||
"|Time"
|
||||
#endif // USE_I2S_SAY_TIME
|
||||
#ifdef USE_I2S_RTTTL
|
||||
"|Rtttl"
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
"|Play"
|
||||
#ifdef USE_I2S_WEBRADIO
|
||||
"|WR"
|
||||
#endif // USE_I2S_WEBRADIO
|
||||
#if defined(USE_SHINE) && ( (defined(USE_I2S_AUDIO) && defined(USE_I2S_MIC)) || defined(USE_M5STACK_CORE2) || defined(ESP32S3_BOX) )
|
||||
"|REC"
|
||||
"|MGain"
|
||||
#if defined(USE_SHINE) && defined(MP3_MIC_STREAM)
|
||||
"|STREAM"
|
||||
#endif // MP3_MIC_STREAM
|
||||
#ifdef I2S_BRIDGE
|
||||
"|BRIDGE"
|
||||
#endif // I2S_BRIDGE
|
||||
#endif // USE_SHINE
|
||||
#endif // ESP32
|
||||
;
|
||||
|
||||
void (* const I2SAudio_Command[])(void) PROGMEM = {
|
||||
&Cmd_Say, &Cmd_Gain
|
||||
#ifdef USE_I2S_SAY_TIME
|
||||
,&Cmd_Time
|
||||
#endif // USE_I2S_SAY_TIME
|
||||
#ifdef USE_I2S_RTTTL
|
||||
,&Cmd_I2SRtttl
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
,&Cmd_Play
|
||||
#ifdef USE_I2S_WEBRADIO
|
||||
,&Cmd_WebRadio
|
||||
#endif // USE_I2S_WEBRADIO
|
||||
#if defined(USE_SHINE) && ( (defined(USE_I2S_AUDIO) && defined(USE_I2S_MIC)) || defined(USE_M5STACK_CORE2) || defined(ESP32S3_BOX) )
|
||||
,&Cmd_MicRec
|
||||
,&Cmd_MicGain
|
||||
#if defined(USE_SHINE) && defined(MP3_MIC_STREAM)
|
||||
,&Cmd_MP3Stream
|
||||
#endif // MP3_MIC_STREAM
|
||||
#ifdef I2S_BRIDGE
|
||||
,&Cmd_I2SBridge
|
||||
#endif // I2S_BRIDGE
|
||||
#endif // USE_SHINE
|
||||
#endif // ESP32
|
||||
};
|
||||
|
||||
void Cmd_Play(void) {
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
Play_mp3(XdrvMailbox.data);
|
||||
}
|
||||
ResponseCmndChar(XdrvMailbox.data);
|
||||
}
|
||||
|
||||
void Cmd_Gain(void) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) {
|
||||
if (audio_i2s.out) {
|
||||
audio_i2s.is2_volume=XdrvMailbox.payload;
|
||||
audio_i2s.out->SetGain(((float)(audio_i2s.is2_volume-2)/100.0)*4.0);
|
||||
}
|
||||
}
|
||||
ResponseCmndNumber(audio_i2s.is2_volume);
|
||||
}
|
||||
|
||||
void Cmd_Say(void) {
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
Say(XdrvMailbox.data);
|
||||
}
|
||||
ResponseCmndChar(XdrvMailbox.data);
|
||||
}
|
||||
|
||||
#ifdef USE_I2S_RTTTL
|
||||
void Cmd_I2SRtttl(void) {
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
Rtttl(XdrvMailbox.data);
|
||||
}
|
||||
ResponseCmndChar(XdrvMailbox.data);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
void i2s_mp3_loop(void);
|
||||
void i2s_mp3_init(void);
|
||||
void MP3ShowStream(void);
|
||||
|
||||
bool Xdrv42(uint32_t function) {
|
||||
bool result = false;
|
||||
|
||||
switch (function) {
|
||||
case FUNC_COMMAND:
|
||||
result = DecodeCommand(kI2SAudio_Commands, I2SAudio_Command);
|
||||
break;
|
||||
case FUNC_INIT:
|
||||
I2S_Init();
|
||||
break;
|
||||
case FUNC_WEB_ADD_MAIN_BUTTON:
|
||||
//MP3ShowStream();
|
||||
break;
|
||||
case FUNC_LOOP:
|
||||
#if defined(USE_SHINE) && defined(MP3_MIC_STREAM)
|
||||
i2s_mp3_loop();
|
||||
#endif
|
||||
#if defined(I2S_BRIDGE) && ( (defined(USE_I2S_AUDIO) && defined(USE_I2S_MIC)) || defined(USE_M5STACK_CORE2) || defined(ESP32S3_BOX) )
|
||||
i2s_bridge_loop();
|
||||
#endif
|
||||
break;
|
||||
case FUNC_WEB_ADD_HANDLER:
|
||||
#if defined(USE_SHINE) && defined(MP3_MIC_STREAM)
|
||||
audio_i2s.stream_enable = 1;
|
||||
i2s_mp3_init(1);
|
||||
#endif
|
||||
#if defined(I2S_BRIDGE) && ( (defined(USE_I2S_AUDIO) && defined(USE_I2S_MIC)) || defined(USE_M5STACK_CORE2) || defined(ESP32S3_BOX) )
|
||||
I2SBridgeInit();
|
||||
#endif
|
||||
break;
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
#ifdef USE_I2S_WEBRADIO
|
||||
case FUNC_WEB_SENSOR:
|
||||
I2S_WR_Show(false);
|
||||
break;
|
||||
#endif // USE_I2S_WEBRADIO
|
||||
#endif // USE_WEBSERVER
|
||||
#ifdef USE_I2S_WEBRADIO
|
||||
case FUNC_JSON_APPEND:
|
||||
I2S_WR_Show(true);
|
||||
break;
|
||||
#endif // USE_I2S_WEBRADIO
|
||||
|
||||
case FUNC_ACTIVE:
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_I2S_AUDIO
|
||||
#endif // ESP8266 || (ESP_IDF_VERSION_MAJOR < 5)
|
|
@ -1,335 +0,0 @@
|
|||
/*
|
||||
xdrv_42_i2s_audio.ino - Audio dac support for Tasmota
|
||||
|
||||
Copyright (C) 2021 Gerhard Mutz and Theo Arends
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#if defined(ESP32) && (ESP_IDF_VERSION_MAJOR < 5)
|
||||
#if ( (defined(USE_I2S_AUDIO) && defined(USE_I2S_MIC)) || defined(USE_M5STACK_CORE2) || defined(ESP32S3_BOX) )
|
||||
|
||||
uint32_t SpeakerMic(uint8_t spkr) {
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
#ifndef USE_I2S_COMMON_IO
|
||||
|
||||
if (audio_i2s.mode == spkr) {
|
||||
return 0;
|
||||
}
|
||||
if (spkr == MODE_SPK) {
|
||||
|
||||
if (audio_i2s.i2s_port == audio_i2s.mic_port) {
|
||||
if (audio_i2s.mode != MODE_SPK) {
|
||||
i2s_driver_uninstall(audio_i2s.mic_port);
|
||||
}
|
||||
I2S_Init_0();
|
||||
audio_i2s.out->SetGain(((float)(audio_i2s.is2_volume - 2) / 100.0) * 4.0);
|
||||
audio_i2s.out->stop();
|
||||
}
|
||||
audio_i2s.mode = spkr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// set micro
|
||||
if (audio_i2s.i2s_port == audio_i2s.mic_port) {
|
||||
// close audio out
|
||||
if (audio_i2s.out) {
|
||||
audio_i2s.out->stop();
|
||||
delete audio_i2s.out;
|
||||
audio_i2s.out = nullptr;
|
||||
}
|
||||
if (audio_i2s.mode == MODE_SPK) {
|
||||
i2s_driver_uninstall(audio_i2s.i2s_port);
|
||||
}
|
||||
}
|
||||
|
||||
// config mic
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = (i2s_mode_t)(I2S_MODE_MASTER),
|
||||
.sample_rate = audio_i2s.mic_rate,
|
||||
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
|
||||
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
|
||||
.communication_format = I2S_COMM_FORMAT_I2S,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
//.dma_buf_count = 8,
|
||||
.dma_buf_count = 2,
|
||||
//.dma_buf_len = 128,
|
||||
.dma_buf_len = 1024,
|
||||
.use_apll = 0, // Use audio PLL
|
||||
.tx_desc_auto_clear = true,
|
||||
.fixed_mclk = 12000000,
|
||||
.mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT, // I2S_MCLK_MULTIPLE_128
|
||||
.bits_per_chan = I2S_BITS_PER_CHAN_16BIT
|
||||
};
|
||||
|
||||
if (audio_i2s.mic_channels == 1) {
|
||||
i2s_config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT;
|
||||
} else {
|
||||
i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT;
|
||||
}
|
||||
|
||||
#ifdef USE_I2S_MIC
|
||||
// Mic L/R to GND
|
||||
#ifdef USE_INMP441
|
||||
i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX );
|
||||
i2s_config.communication_format = I2S_COMM_FORMAT_I2S;
|
||||
i2s_config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
|
||||
#elif MIC_PDM
|
||||
i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM);
|
||||
#else
|
||||
i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX);
|
||||
i2s_config.communication_format = I2S_COMM_FORMAT_STAND_I2S;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ESP32S3_BOX
|
||||
i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX);
|
||||
i2s_config.communication_format = I2S_COMM_FORMAT_STAND_I2S;
|
||||
#endif
|
||||
|
||||
#ifdef USE_M5STACK_CORE2
|
||||
i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM);
|
||||
#endif
|
||||
|
||||
|
||||
err += i2s_driver_install(audio_i2s.mic_port, &i2s_config, 0, NULL);
|
||||
|
||||
i2s_pin_config_t tx_pin_config;
|
||||
|
||||
tx_pin_config.mck_io_num = audio_i2s.mic_mclk;
|
||||
tx_pin_config.bck_io_num = audio_i2s.mic_bclk;
|
||||
tx_pin_config.ws_io_num = audio_i2s.mic_ws;
|
||||
tx_pin_config.data_out_num = audio_i2s.mic_dout;
|
||||
tx_pin_config.data_in_num = audio_i2s.mic_din;
|
||||
|
||||
err += i2s_set_pin(audio_i2s.mic_port, &tx_pin_config);
|
||||
|
||||
i2s_channel_t mode = I2S_CHANNEL_MONO;
|
||||
if (audio_i2s.mic_channels > 1) {
|
||||
mode = I2S_CHANNEL_STEREO;
|
||||
}
|
||||
err += i2s_set_clk(audio_i2s.mic_port, audio_i2s.mic_rate, I2S_BITS_PER_SAMPLE_16BIT, mode);
|
||||
|
||||
#endif // USE_I2S_COMMON_IO
|
||||
|
||||
audio_i2s.mode = spkr;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef USE_SHINE
|
||||
|
||||
#include <layer3.h>
|
||||
#include <types.h>
|
||||
|
||||
// micro to mp3 file or stream
|
||||
void mic_task(void *arg){
|
||||
int8_t error = 0;
|
||||
uint8_t *ucp;
|
||||
int written;
|
||||
shine_config_t config;
|
||||
shine_t s = nullptr;
|
||||
uint16_t samples_per_pass;
|
||||
File mp3_out = (File)nullptr;
|
||||
int16_t *buffer = nullptr;
|
||||
uint16_t bytesize;
|
||||
uint16_t bwritten;
|
||||
uint32_t ctime;
|
||||
|
||||
if (!audio_i2s.use_stream) {
|
||||
mp3_out = ufsp->open(audio_i2s.mic_path, "w");
|
||||
if (!mp3_out) {
|
||||
error = 1;
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
if (!audio_i2s.stream_active) {
|
||||
error = 2;
|
||||
audio_i2s.use_stream = 0;
|
||||
goto exit;
|
||||
}
|
||||
audio_i2s.client.flush();
|
||||
audio_i2s.client.setTimeout(3);
|
||||
audio_i2s.client.print("HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: audio/mpeg;\r\n\r\n");
|
||||
|
||||
// Webserver->send(200, "application/octet-stream", "");
|
||||
//"Content-Type: audio/mp3;\r\n\r\n");
|
||||
}
|
||||
|
||||
shine_set_config_mpeg_defaults(&config.mpeg);
|
||||
|
||||
if (audio_i2s.mic_channels == 1) {
|
||||
config.mpeg.mode = MONO;
|
||||
} else {
|
||||
config.mpeg.mode = STEREO;
|
||||
}
|
||||
config.mpeg.bitr = 128;
|
||||
config.wave.samplerate = audio_i2s.mic_rate;
|
||||
config.wave.channels = (channels)audio_i2s.mic_channels;
|
||||
|
||||
if (shine_check_config(config.wave.samplerate, config.mpeg.bitr) < 0) {
|
||||
error = 3;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
s = shine_initialise(&config);
|
||||
if (!s) {
|
||||
error = 4;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
samples_per_pass = shine_samples_per_pass(s);
|
||||
bytesize = samples_per_pass * 2 * audio_i2s.mic_channels;
|
||||
|
||||
buffer = (int16_t*)malloc(bytesize);
|
||||
if (!buffer) {
|
||||
error = 5;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ctime = TasmotaGlobal.uptime;
|
||||
|
||||
while (!audio_i2s.mic_stop) {
|
||||
uint32_t bytes_read;
|
||||
i2s_read(audio_i2s.mic_port, (char *)buffer, bytesize, &bytes_read, (100 / portTICK_RATE_MS));
|
||||
|
||||
if (audio_i2s.mic_gain > 1) {
|
||||
// set gain
|
||||
for (uint32_t cnt = 0; cnt < bytes_read / 2; cnt++) {
|
||||
buffer[cnt] *= audio_i2s.mic_gain;
|
||||
}
|
||||
}
|
||||
ucp = shine_encode_buffer_interleaved(s, buffer, &written);
|
||||
|
||||
if (!audio_i2s.use_stream) {
|
||||
bwritten = mp3_out.write(ucp, written);
|
||||
if (bwritten != written) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
audio_i2s.client.write((const char*)ucp, written);
|
||||
|
||||
if (!audio_i2s.client.connected()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
audio_i2s.recdur = TasmotaGlobal.uptime - ctime;
|
||||
}
|
||||
|
||||
ucp = shine_flush(s, &written);
|
||||
|
||||
if (!audio_i2s.use_stream) {
|
||||
mp3_out.write(ucp, written);
|
||||
} else {
|
||||
audio_i2s.client.write((const char*)ucp, written);
|
||||
}
|
||||
|
||||
|
||||
exit:
|
||||
if (s) {
|
||||
shine_close(s);
|
||||
}
|
||||
if (mp3_out) {
|
||||
mp3_out.close();
|
||||
}
|
||||
if (buffer) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
if (audio_i2s.use_stream) {
|
||||
audio_i2s.client.stop();
|
||||
}
|
||||
|
||||
SpeakerMic(MODE_SPK);
|
||||
audio_i2s.mic_stop = 0;
|
||||
audio_i2s.mic_error = error;
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("mp3task result code: %d"), error);
|
||||
audio_i2s.mic_task_h = 0;
|
||||
audio_i2s.recdur = 0;
|
||||
audio_i2s.stream_active = 0;
|
||||
vTaskDelete(NULL);
|
||||
|
||||
}
|
||||
|
||||
int32_t i2s_record_shine(char *path) {
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
if (audio_i2s.mic_port == 0) {
|
||||
if (audio_i2s.decoder || audio_i2s.mp3) return 0;
|
||||
}
|
||||
|
||||
err = SpeakerMic(MODE_MIC);
|
||||
if (err) {
|
||||
if (audio_i2s.mic_port == 0) {
|
||||
SpeakerMic(MODE_SPK);
|
||||
}
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("mic init error: %d"), err);
|
||||
return err;
|
||||
}
|
||||
|
||||
strlcpy(audio_i2s.mic_path, path, sizeof(audio_i2s.mic_path));
|
||||
|
||||
audio_i2s.mic_stop = 0;
|
||||
|
||||
uint32_t stack = 4096;
|
||||
|
||||
audio_i2s.use_stream = !strcmp(audio_i2s.mic_path, "stream.mp3");
|
||||
|
||||
if (audio_i2s.use_stream) {
|
||||
stack = 8000;
|
||||
}
|
||||
|
||||
err = xTaskCreatePinnedToCore(mic_task, "MIC", stack, NULL, 3, &audio_i2s.mic_task_h, 1);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void Cmd_MicRec(void) {
|
||||
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
if (!strncmp(XdrvMailbox.data, "-?", 2)) {
|
||||
Response_P("{\"I2SREC-duration\":%d}", audio_i2s.recdur);
|
||||
} else {
|
||||
i2s_record_shine(XdrvMailbox.data);
|
||||
ResponseCmndChar(XdrvMailbox.data);
|
||||
}
|
||||
} else {
|
||||
if (audio_i2s.mic_task_h) {
|
||||
// stop task
|
||||
audio_i2s.mic_stop = 1;
|
||||
while (audio_i2s.mic_stop) {
|
||||
delay(1);
|
||||
}
|
||||
ResponseCmndChar_P(PSTR("Stopped"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif // USE_SHINE
|
||||
|
||||
|
||||
// mic gain in factor not percent
|
||||
void Cmd_MicGain(void) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 256)) {
|
||||
audio_i2s.mic_gain = XdrvMailbox.payload;
|
||||
}
|
||||
ResponseCmndNumber(audio_i2s.mic_gain);
|
||||
}
|
||||
|
||||
#endif // USE_I2S_AUDIO
|
||||
#endif // ESP32 && (ESP_IDF_VERSION_MAJOR < 5)
|
|
@ -1,64 +0,0 @@
|
|||
|
||||
#if defined(ESP32) && (ESP_IDF_VERSION_MAJOR < 5)
|
||||
#if defined(USE_SHINE) && ( (defined(USE_I2S_AUDIO) && defined(USE_I2S_MIC)) || defined(USE_M5STACK_CORE2) || defined(ESP32S3_BOX) )
|
||||
|
||||
#ifdef MP3_MIC_STREAM
|
||||
|
||||
#ifndef MP3_STREAM_PORT
|
||||
#define MP3_STREAM_PORT 81
|
||||
#endif
|
||||
|
||||
|
||||
void Stream_mp3(void) {
|
||||
if (!audio_i2s.stream_enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (audio_i2s.stream_active) {
|
||||
return;
|
||||
}
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("I2S: Handle mp3server"));
|
||||
audio_i2s.stream_active = 1;
|
||||
audio_i2s.client = audio_i2s.MP3Server->client();
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("I2S: Create client"));
|
||||
i2s_record_shine((char*)"stream.mp3");
|
||||
}
|
||||
|
||||
void i2s_mp3_loop(void) {
|
||||
if (audio_i2s.MP3Server) {
|
||||
audio_i2s.MP3Server->handleClient();
|
||||
}
|
||||
}
|
||||
|
||||
void i2s_mp3_init(uint32_t on) {
|
||||
if (on) {
|
||||
if (!audio_i2s.MP3Server) {
|
||||
audio_i2s.MP3Server = new ESP8266WebServer(MP3_STREAM_PORT);
|
||||
audio_i2s.MP3Server->on(PSTR("/stream.mp3"), Stream_mp3);
|
||||
audio_i2s.MP3Server->on(PSTR("/stream.m3a"), Stream_mp3);
|
||||
audio_i2s.MP3Server->begin();
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("MP3: server created on port: %d "), MP3_STREAM_PORT);
|
||||
}
|
||||
} else {
|
||||
if (audio_i2s.MP3Server) {
|
||||
audio_i2s.MP3Server->stop();
|
||||
delete audio_i2s.MP3Server;
|
||||
audio_i2s.MP3Server = nullptr;
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("MP3: server deleted"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Cmd_MP3Stream(void) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) {
|
||||
audio_i2s.stream_enable = XdrvMailbox.payload;
|
||||
}
|
||||
i2s_mp3_init(audio_i2s.stream_enable);
|
||||
ResponseCmndNumber(audio_i2s.stream_enable);
|
||||
}
|
||||
#endif // MP3_MIC_STREAM
|
||||
|
||||
|
||||
#endif // USE_SHINE
|
||||
#endif // defined(ESP32) && (ESP_IDF_VERSION_MAJOR < 5)
|
|
@ -70,6 +70,22 @@ extern "C" {
|
|||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
// Berry: `config_tx_en(tx_en_gpio:int) -> nil`
|
||||
int32_t b_config_tx_en(struct bvm *vm);
|
||||
int32_t b_config_tx_en(struct bvm *vm) {
|
||||
be_getmember(vm, 1, ".p");
|
||||
TasmotaSerial * ser = (TasmotaSerial *) be_tocomptr(vm, -1);
|
||||
if (ser) {
|
||||
int32_t tx_en = be_toint(vm, 2);
|
||||
if (tx_en >= 0) {
|
||||
ser->setTransmitEnablePin(tx_en);
|
||||
} else {
|
||||
ser->clearTransmitEnablePin();
|
||||
}
|
||||
}
|
||||
be_return_nil(vm);
|
||||
}
|
||||
|
||||
// Berry: `deinit(void)`
|
||||
int32_t b_serial_deinit(struct bvm *vm);
|
||||
int32_t b_serial_deinit(struct bvm *vm) {
|
||||
|
|
|
@ -249,6 +249,14 @@ extern "C" {
|
|||
be_return_nil(vm);
|
||||
}
|
||||
|
||||
// Berry: `webserver.content_close() -> nil`
|
||||
//
|
||||
int32_t w_webserver_content_close(struct bvm *vm);
|
||||
int32_t w_webserver_content_close(struct bvm *vm) {
|
||||
WSContentEnd();
|
||||
be_return_nil(vm);
|
||||
}
|
||||
|
||||
// Berry: `webserver.content_button([button:int]) -> nil`
|
||||
// Default button is BUTTON_MAIN
|
||||
//
|
||||
|
|
|
@ -899,7 +899,7 @@ bool Xdrv52(uint32_t function)
|
|||
#ifdef USE_ETHERNET
|
||||
network_up = network_up || EthernetHasIP();
|
||||
#endif
|
||||
if (network_up) { // if network is already up, send a synthetic event to trigger web handlers
|
||||
if (network_up && (Webserver != NULL)) { // if network is already up, send a synthetic event to trigger web handlers
|
||||
callBerryEventDispatcher(PSTR("web_add_handler"), nullptr, 0, nullptr);
|
||||
berry.web_add_handler_done = true;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,9 @@ void HDMI_OnReady(class CEC_Device* self, int logical_address) {
|
|||
|
||||
void HDMI_OnReceive(class CEC_Device *self, int32_t from, int32_t to, uint8_t* buf, size_t len, bool ack)
|
||||
{
|
||||
AddLog(LOG_LEVEL_DEBUG, "CEC: Packet received: (%1X->%1X) %1X%1X%*_H %s", from, to, from, to, len, buf, ack ? PSTR("ACK") : PSTR("NAK"));
|
||||
if (HighestLogLevel() >= LOG_LEVEL_DEBUG) {
|
||||
AddLog(LOG_LEVEL_DEBUG, "CEC: Packet received: (%1X->%1X) %1X%1X%*_H %s", from, to, from, to, len, buf, ack ? PSTR("ACK") : PSTR("NAK"));
|
||||
}
|
||||
|
||||
Response_P(PSTR("{\"HdmiReceived\":{\"From\":%i,\"To\":%i,\"Data\":\"%*_H\"}}"), from, to, len, buf);
|
||||
if (to == self->getLogicalAddress() || to == 0x0F) {
|
||||
|
@ -55,7 +57,9 @@ void HDMI_OnReceive(class CEC_Device *self, int32_t from, int32_t to, uint8_t* b
|
|||
void HDMI_OnTransmit(class CEC_Device *self, uint8_t* buf, size_t len, bool ack)
|
||||
{
|
||||
// This is called after a frame is transmitted.
|
||||
AddLog(LOG_LEVEL_DEBUG, "CEC: Packet sent: %*_H %s", len, buf, ack ? PSTR("ACK") : PSTR("NAK"));
|
||||
if (HighestLogLevel() >= LOG_LEVEL_DEBUG) {
|
||||
AddLog(LOG_LEVEL_DEBUG, "CEC: Packet sent: %*_H %s", len, buf, ack ? PSTR("ACK") : PSTR("NAK"));
|
||||
}
|
||||
}
|
||||
|
||||
// singleton for HDMI CEC object, could be expanded if we manage multiple HDMI in parallel
|
||||
|
@ -110,8 +114,13 @@ void CmndHDMISendRaw(void) {
|
|||
RemoveSpace(XdrvMailbox.data);
|
||||
SBuffer buf = SBuffer::SBufferFromHex(XdrvMailbox.data, strlen(XdrvMailbox.data));
|
||||
if (buf.len() > 0 && buf.len() < 16) {
|
||||
HDMI_CEC_device->transmitRaw(buf.buf(), buf.len());
|
||||
ResponseCmndDone();
|
||||
bool success = HDMI_CEC_device->transmitRaw(buf.buf(), buf.len());
|
||||
if (success) {
|
||||
HDMI_CEC_device->run();
|
||||
ResponseCmndDone();
|
||||
} else {
|
||||
ResponseCmndChar_P(PSTR("Sending failed"));
|
||||
}
|
||||
} else {
|
||||
ResponseCmndChar_P(PSTR("Buffer too large"));
|
||||
}
|
||||
|
@ -155,8 +164,13 @@ void CmndHDMISend(void) {
|
|||
const char * payload = root.getStr(PSTR("Data"));
|
||||
SBuffer buf = SBuffer::SBufferFromHex(payload, strlen(payload));
|
||||
if (buf.len() > 0 && buf.len() < 15) {
|
||||
HDMI_CEC_device->transmitFrame(to, buf.buf(), buf.len());
|
||||
ResponseCmndDone();
|
||||
bool success = HDMI_CEC_device->transmitFrame(to, buf.buf(), buf.len());
|
||||
if (success) {
|
||||
HDMI_CEC_device->run();
|
||||
ResponseCmndDone();
|
||||
} else {
|
||||
ResponseCmndChar_P(PSTR("Sending failed"));
|
||||
}
|
||||
} else {
|
||||
if (buf.len() == 0) {
|
||||
ResponseCmndChar_P(PSTR("Buffer empty"));
|
||||
|
@ -168,8 +182,13 @@ void CmndHDMISend(void) {
|
|||
// Hex
|
||||
SBuffer buf = SBuffer::SBufferFromHex(XdrvMailbox.data, strlen(XdrvMailbox.data));
|
||||
if (buf.len() > 0 && buf.len() < 15) {
|
||||
HDMI_CEC_device->transmitFrame(0, buf.buf(), buf.len());
|
||||
ResponseCmndDone();
|
||||
bool success = HDMI_CEC_device->transmitFrame(0, buf.buf(), buf.len());
|
||||
if (success) {
|
||||
HDMI_CEC_device->run();
|
||||
ResponseCmndDone();
|
||||
} else {
|
||||
ResponseCmndChar_P(PSTR("Sending failed"));
|
||||
}
|
||||
} else {
|
||||
if (buf.len() == 0) {
|
||||
ResponseCmndChar_P(PSTR("Buffer empty"));
|
||||
|
@ -239,7 +258,9 @@ bool ReadEdid256(uint8_t *buf) {
|
|||
// Return 0x0000 if not found
|
||||
uint16_t HDMIGetPhysicalAddress(void) {
|
||||
uint8_t buf[256] = {0};
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("CEC: trying to read physical address"));
|
||||
if (HighestLogLevel() >= LOG_LEVEL_DEBUG) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("CEC: trying to read physical address"));
|
||||
}
|
||||
if (ReadEdid256(buf)) { return 0x0000; } // unable to get an address
|
||||
|
||||
uint8_t edid_extensions = buf[126];
|
||||
|
@ -269,7 +290,9 @@ uint16_t HDMIGetPhysicalAddress(void) {
|
|||
// 030C00 for "HDMI Licensing, LLC"
|
||||
if (buf[idx+1] == 0x03 && buf[idx+2] == 0x0C && buf[idx+3] == 0x00) {
|
||||
uint16_t addr = (buf[idx+4] << 8) | buf[idx+5];
|
||||
AddLog(LOG_LEVEL_DEBUG, "CEC: physical address found: 0x%04X", addr);
|
||||
if (HighestLogLevel() >= LOG_LEVEL_DEBUG) {
|
||||
AddLog(LOG_LEVEL_DEBUG, "CEC: physical address found: 0x%04X", addr);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
@ -277,7 +300,9 @@ uint16_t HDMIGetPhysicalAddress(void) {
|
|||
idx += 1 + number_of_bytes;
|
||||
}
|
||||
|
||||
AddLog(LOG_LEVEL_DEBUG, "CEC: physical address not found");
|
||||
if (HighestLogLevel() >= LOG_LEVEL_DEBUG) {
|
||||
AddLog(LOG_LEVEL_DEBUG, "CEC: physical address not found");
|
||||
}
|
||||
return 0x0000; // TODO
|
||||
}
|
||||
|
||||
|
|
|
@ -238,14 +238,14 @@ enum NeoPoolRegister {
|
|||
// MISC page (0x06xx) - Contains the configuration parameters for the screen controllers (language, colours, sound, etc).
|
||||
MBF_PAR_UICFG_MACHINE = 0x0600, // 0x0600* Machine type (see MBV_PAR_MACH_* and kNeoPoolMachineNames[])
|
||||
MBF_PAR_UICFG_LANGUAGE, // 0x0601* Selected language (see MBV_PAR_LANG_*)
|
||||
MBF_PAR_UICFG_BACKLIGHT, // 0x0602* Display backlight (see MBV_PAR_BACKLIGHT_*)
|
||||
MBF_PAR_UICFG_BACKLIGHT, // 0x0602* Display backlight function (see MBV_PAR_BACKLIGHT_*)
|
||||
MBF_PAR_UICFG_SOUND, // 0x0603* mask Audible alerts (see MBMSK_PAR_SOUND_*)
|
||||
MBF_PAR_UICFG_PASSWORD, // 0x0604* System password encoded in BCD
|
||||
MBF_PAR_UICFG_VISUAL_OPTIONS, // 0x0605* mask Stores the different display options for the user interface menus (bitmask). Some bits allow you to hide options that are normally visible (bits 0 to 3) while other bits allow you to show options that are normally hidden (bits 9 to 15)
|
||||
MBF_PAR_UICFG_VISUAL_OPTIONS_EXT, // 0x0606* mask This register stores additional display options for the user interface menus (see MBMSK_VOE_*)
|
||||
MBF_PAR_UICFG_MACH_VISUAL_STYLE, // 0x0607* mask This register is an expansion of register 0x0600 and 0x0605. The lower part of the register (8 bits LSB) is used to store the type of color selected when in register 0x600 has been specified that the machine is of type "generic". Colors and styles correspond to those listed in record 0x600 MBF_PAR_UICFG_MACHINE. The upper part (8-bit MSB) contains extra bits MBMSK_VS_FORCE_UNITS_GRH, MBMSK_VS_FORCE_UNITS_PERCENTAGE and MBMSK_ELECTROLISIS
|
||||
MBF_PAR_UICFG_MACH_NAME_BOLD = 0x0608, // 0x0608 Machine name bold part title displayed during startup (if machine type is generic). Note: Only lowercase letters (a-z) can be used. 4 register ASCIIZ string with up to 8 characters
|
||||
MBF_PAR_UICFG_MACH_NAME_LIGHT = 0x060C, // 0x060C Machine name normal intensity part title displayed during startup (if machine type is generic). Note: Only lowercase letters (a-z) can be used. 4 register ASCIIZ string with up to 8 characters
|
||||
MBF_PAR_UICFG_MACH_VISUAL_STYLE, // 0x0607* mask This register is an expansion of register MBF_PAR_UICFG_MACHINE and MBF_PAR_UICFG_VISUAL_OPTIONS. If MBF_PAR_UICFG_MACHINE is MBV_PAR_MACH_GENERIC then the lower part (8 bits LSB) is used to store the type of color selected. Colors and styles correspond to those listed in MBF_PAR_UICFG_MACHINE (see MBV_PAR_MACH_*). The upper part (8-bit MSB) contains extra bits MBMSK_VS_FORCE_UNITS_GRH, MBMSK_VS_FORCE_UNITS_PERCENTAGE and MBMSK_ELECTROLISIS
|
||||
MBF_PAR_UICFG_MACH_NAME_BOLD = 0x0608, // 0x0608 Machine name bold part title displayed during startup if MBF_PAR_UICFG_MACHINE is MBV_PAR_MACH_GENERIC. Note: Only lowercase letters (a-z) can be used. 4 register (0x608 to 0x60B) ASCIIZ string with up to 8 characters
|
||||
MBF_PAR_UICFG_MACH_NAME_LIGHT = 0x060C, // 0x060C Machine name normal intensity part title displayed during startup if MBF_PAR_UICFG_MACHINE is MBV_PAR_MACH_GENERIC. Note: Only lowercase letters (a-z) can be used. 4 register (0x060C to 0x060F) ASCIIZ string with up to 8 characters
|
||||
MBF_PAR_UICFG_MACH_NAME_AUX1 = 0x0610, // 0x0610 Aux1 relay name: 5 register ASCIIZ string with up to 10 characters
|
||||
MBF_PAR_UICFG_MACH_NAME_AUX2 = 0x0615, // 0x0615 Aux2 relay name: 5 register ASCIIZ string with up to 10 characters
|
||||
MBF_PAR_UICFG_MACH_NAME_AUX3 = 0x061A, // 0x061A Aux3 relay name: 5 register ASCIIZ string with up to 10 characters
|
||||
|
@ -546,6 +546,13 @@ enum NeoPoolConstAndBitMask {
|
|||
MBMSK_VS_FORCE_UNITS_GRH = 0x2000, // 13 Display the hydrolysis/electrolysis in units of grams per hour (gr/h).
|
||||
MBMSK_VS_FORCE_UNITS_PERCENTAGE = 0x4000, // 14 Display the hydrolysis/electrolysis in percentage units (%).
|
||||
MBMSK_ELECTROLISIS = 0x8000, // 15 Display the word electrolysis instead of hydrolysis in generic mode.
|
||||
// To determine the type of units are used to display the hydrolysis/electrolysis:
|
||||
// 1. If MBMSK_VS_FORCE_UNITS_PERCENTAGE bit is set, "%" is displayed
|
||||
// 2. If MBMSK_VS_FORCE_UNITS_GRH bit is set, "gr/h" is displayed
|
||||
// 3. If neither of the above two bits is set:
|
||||
// a. If MBF_PAR_UICFG_MACHINE is MBV_PAR_MACH_HIDROLIFE or MBV_PAR_MACH_BIONET, then "gr/h" is displayed
|
||||
// b. If MBF_PAR_UICFG_MACHINE is MBV_PAR_MACH_GENERIC and MBMSK_ELECTROLISIS bit is set, "gr/h" is displayed.
|
||||
// c. If none of the above cases apply, "%" is displayed.
|
||||
|
||||
// MBF_POWER_MODULE_REG_*
|
||||
MBV_POWER_MODULE_REG_INFO = 0, // ! set of 26-byte power module register stores an ASCIIZ string containing the subversion and timestamp of the module, e. g. ".57\nMay 26 2020\n01:08:10\n\0"
|
||||
|
@ -1328,6 +1335,7 @@ void NeoPool250msSetStatus(bool status)
|
|||
neopool_poll = status;
|
||||
|
||||
if (!status) {
|
||||
NeoPoolModbus->flush();
|
||||
// clear rec buffer from possible prev periodical communication
|
||||
uint32_t timeoutMS = millis() + 100 * NEOPOOL_READ_TIMEOUT; // Max delay before we timeout
|
||||
while (NeoPoolModbus->available() && millis() < timeoutMS) {
|
||||
|
|
|
@ -22,9 +22,9 @@ with open(lv_module_file) as f:
|
|||
l_raw = l_raw.strip(" \t\n\r") # remove leading or trailing spaces
|
||||
if l_raw.startswith("//"):
|
||||
lv_module.append( [ None, l_raw ] ) # if key in None then add comment line
|
||||
l_raw = re.sub('//.*$', '', l_raw) # remove trailing comments
|
||||
l_raw = re.sub('\s+', '', l_raw) # remove all spaces
|
||||
l_raw = re.sub(',.*$', '', l_raw) # remove comma and anything after it
|
||||
l_raw = re.sub(r'//.*$', '', l_raw) # remove trailing comments
|
||||
l_raw = re.sub(r'\s+', '', l_raw) # remove all spaces
|
||||
l_raw = re.sub(r',.*$', '', l_raw) # remove comma and anything after it
|
||||
if (len(l_raw) == 0): continue
|
||||
|
||||
k_v = l_raw.split("=")
|
||||
|
@ -35,7 +35,7 @@ with open(lv_module_file) as f:
|
|||
k = k_v[0]
|
||||
if k.startswith("_"):
|
||||
continue # skip any label starting with '_'
|
||||
k = re.sub('^LV_', '', k) # remove remove any LV_ prefix
|
||||
k = re.sub(r'^LV_', '', k) # remove remove any LV_ prefix
|
||||
v = None
|
||||
if len(k_v) == 2: # value is included
|
||||
v = k_v[1]
|
||||
|
@ -53,6 +53,10 @@ with open(lv_module_file) as f:
|
|||
sys.stdout = open(out_prefix + be_gpio_defines, 'w')
|
||||
print("/********************************************************************")
|
||||
print(" * Generated code, don't edit")
|
||||
print(" * ")
|
||||
print(" * The keys in the array belox must be in lexicographic order")
|
||||
print(" * ")
|
||||
print(" * Generated by: `python3 gpio_convert.py`")
|
||||
print(" *******************************************************************/")
|
||||
|
||||
print("""
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// Enum values for GPIOs
|
||||
// This is manually updated to have an appropriate name in Berry
|
||||
// Convert using `python3 gpio_convert.py`
|
||||
|
||||
LOW
|
||||
HIGH
|
||||
|
@ -199,6 +201,7 @@ KEY1_TC = GPIO_KEY1_TC
|
|||
BL0940_RX = GPIO_BL0940_RX
|
||||
TCP_TX = GPIO_TCP_TX
|
||||
TCP_RX = GPIO_TCP_RX
|
||||
TCP_TX_EN = GPIO_TCP_TX_EN
|
||||
ETH_PHY_POWER = GPIO_ETH_PHY_POWER
|
||||
ETH_PHY_MDC = GPIO_ETH_PHY_MDC
|
||||
ETH_PHY_MDIO = GPIO_ETH_PHY_MDIO
|
||||
|
@ -344,4 +347,23 @@ MAGIC_SWITCH = GPIO_MAGIC_SWITCH
|
|||
PIPSOLAR_TX = GPIO_PIPSOLAR_TX
|
||||
PIPSOLAR_RX = GPIO_PIPSOLAR_RX
|
||||
|
||||
LORA_CS = GPIO_LORA_CS
|
||||
LORA_RST = GPIO_LORA_RST
|
||||
LORA_BUSY = GPIO_LORA_BUSY
|
||||
LORA_DI0 = GPIO_LORA_DI0
|
||||
LORA_DI1 = GPIO_LORA_DI1
|
||||
LORA_DI2 = GPIO_LORA_DI2
|
||||
LORA_DI3 = GPIO_LORA_DI3
|
||||
LORA_DI4 = GPIO_LORA_DI4
|
||||
LORA_DI5 = GPIO_LORA_DI5
|
||||
|
||||
TS_SPI_CS = GPIO_TS_SPI_CS
|
||||
TS_RST = GPIO_TS_RST
|
||||
TS_IRQ = GPIO_TS_IRQ
|
||||
|
||||
RN2XX3_TX = GPIO_RN2XX3_TX
|
||||
RN2XX3_RX = GPIO_RN2XX3_RX
|
||||
RN2XX3_RST = GPIO_RN2XX3_RST
|
||||
|
||||
|
||||
SENSOR_END = GPIO_SENSOR_END
|
||||
|
|
Loading…
Reference in New Issue