Compare commits

...

11 Commits

Author SHA1 Message Date
fb-pilot 6d4bc04d63
Merge branch 'arendst:development' into development 2024-04-25 21:47:26 +02:00
Jason2866 41970f7d62
Disable psram check to avoid "blinking" of GPIO 16/17 at startup (#21282)
* add `DISABLE_PSRAMCHECK`

* remove code before IDF 5

* add no psram env
2024-04-25 20:19:20 +02:00
Jason2866 eef4ff389f
Delete IDF 4.4 based i2s code (#21188)
* Delete tasmota/tasmota_xdrv_driver/xdrv_42_2_i2s_mp3stream.ino

* Delete tasmota/tasmota_xdrv_driver/xdrv_42_0_i2s_audio.ino

* Delete tasmota/tasmota_xdrv_driver/xdrv_42_1_i2s_mp3mic.ino
2024-04-25 13:41:47 +02:00
s-hadinger 1e64eaddf3
Berry `webserver.content_close()` (#21276) 2024-04-25 12:50:43 +02:00
s-hadinger 466652549a
Fix faulty printing of IPv4 2024-04-25 11:23:27 +02:00
s-hadinger 2a35f325b8
Put back wifi IPv6 workaround (#21274) 2024-04-25 10:28:42 +02:00
s-hadinger 469492a41a
Berry `web_add_handler` called before `Webserver` is initialized (#21272) 2024-04-25 09:08:24 +02:00
s-hadinger 582ca598f0
HDMI CEC synchronously sends messages (#21270) 2024-04-24 20:06:13 +02:00
s-hadinger 91dd120aa9
TCP Tx En GPIO type (#21269) 2024-04-24 19:53:01 +02:00
Norbert Richter 5a8d713d77
NeoPool prevent possible multiple bus requests (#21267)
* Update NeoPool register desc

* NeoPool prevent possible multiple bus requests
2024-04-24 17:44:26 +02:00
Jason2866 492c6bbda2
Platform 2024.04.13 (#21264) 2024-04-24 13:04:01 +02:00
48 changed files with 241 additions and 1286 deletions

View File

@ -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

View File

@ -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; }

View File

@ -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)

View File

@ -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)

View File

@ -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}

View File

@ -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

View File

@ -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 },
};

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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
}
/********************************************************************************************/

View File

@ -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:
{

View File

@ -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();

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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) {

View File

@ -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
//

View File

@ -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;
}

View File

@ -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
}

View File

@ -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) {

View File

@ -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("""

View File

@ -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