diff --git a/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h b/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h index 5006b6c2f0..b0a7a7e577 100644 --- a/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h +++ b/Sming/Arch/Esp32/Components/driver/include/driver/hw_timer.h @@ -10,7 +10,7 @@ #pragma once -#if defined(SUBARCH_ESP32) || defined(SUBARCH_ESP32S2) +#if defined(SUBARCH_ESP32) #define FRC_TIMER_ENABLED #endif @@ -158,8 +158,12 @@ __forceinline uint32_t hw_timer1_read(void) * *************************************/ +#ifdef FRC_TIMER_ENABLED constexpr uint32_t HW_TIMER2_CLKDIV = TIMER_CLKDIV_1; constexpr uint32_t HW_TIMER2_CLK = HW_TIMER_BASE_CLK >> HW_TIMER2_CLKDIV; +#else +constexpr uint32_t HW_TIMER2_CLK = 1000000; +#endif /** * @brief Read current timer2 value diff --git a/Sming/Arch/Esp32/Components/driver/uart.cpp b/Sming/Arch/Esp32/Components/driver/uart.cpp index 20acf62d43..72968a664e 100644 --- a/Sming/Arch/Esp32/Components/driver/uart.cpp +++ b/Sming/Arch/Esp32/Components/driver/uart.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include // These conflict with enumerated types defined in IDF - values are same though #undef UART_PARITY_NONE @@ -36,29 +38,59 @@ */ #define DEFAULT_RX_HEADROOM (32 - RX_FIFO_HEADROOM) -// Determines whether to use APB or REF_TICK as clock source -constexpr bool uart_use_apb_clock{true}; - static int s_uart_debug_nr = UART_NO; // Keep track of interrupt enable state for each UART static uint8_t isrMask; -struct smg_uart_hardware_t { - volatile uart_dev_t& dev; - const uart_signal_conn_t& conn; - uint8_t tx_pin_default; - uint8_t rx_pin_default; +struct smg_uart_pins_t { + uint8_t tx; + uint8_t rx; }; -constexpr smg_uart_hardware_t uartHardware[UART_COUNT] = { - {UART0, uart_periph_signal[0], 1, 3}, - {UART1, uart_periph_signal[1], 10, 9}, +#ifdef SUBARCH_ESP32 +#define UART0_PIN_DEFAULT UART_NUM_0_TXD_DIRECT_GPIO_NUM, UART_NUM_0_RXD_DIRECT_GPIO_NUM +#define UART1_PIN_DEFAULT 18, 19 // Defaults conflict with flash +#define UART2_PIN_DEFAULT UART_NUM_2_TXD_DIRECT_GPIO_NUM, UART_NUM_2_RXD_DIRECT_GPIO_NUM +#elif defined(SUBARCH_ESP32C3) +#define UART0_PIN_DEFAULT 21, 20 +#define UART1_PIN_DEFAULT UART_NUM_1_TXD_DIRECT_GPIO_NUM, UART_NUM_1_RXD_DIRECT_GPIO_NUM +#elif defined(SUBARCH_ESP32S2) +#define UART0_PIN_DEFAULT 43, 44 +#define UART1_PIN_DEFAULT UART_NUM_1_TXD_DIRECT_GPIO_NUM, UART_NUM_1_RXD_DIRECT_GPIO_NUM +#elif defined(SUBARCH_ESP32S3) +#define UART0_PIN_DEFAULT 43, 44 +#define UART1_PIN_DEFAULT UART_NUM_1_TXD_DIRECT_GPIO_NUM, UART_NUM_1_RXD_DIRECT_GPIO_NUM +#define UART2_PIN_DEFAULT UART_NUM_2_TXD_DIRECT_GPIO_NUM, UART_NUM_2_RXD_DIRECT_GPIO_NUM +#else +static_assert(false, "Must define default UART pins for selected ESP_VARIANT"); +#endif + +constexpr smg_uart_pins_t defaultPins[UART_COUNT] = { + {UART0_PIN_DEFAULT}, + {UART1_PIN_DEFAULT}, #if UART_COUNT > 2 - {UART2, uart_periph_signal[2], 17, 16}, + {UART2_PIN_DEFAULT}, #endif }; +uart_dev_t* IRAM_ATTR getDevice(uint8_t uart_nr) +{ + if(uart_nr == 0) { + return &UART0; + } + if(uart_nr == 1) { + return &UART1; + } +#if UART_COUNT > 2 + if(uart_nr == 2) { + return &UART2; + } +#endif + assert(false); + return nullptr; +} + // Keep a reference to all created UARTS struct smg_uart_instance_t { smg_uart_t* uart; @@ -68,34 +100,22 @@ struct smg_uart_instance_t { static smg_uart_instance_t uartInstances[UART_COUNT]; -#if SUBARCH_ESP32 -#define FIFO(dev) dev.fifo.rw_byte -#else -#define FIFO(dev) dev.ahb_fifo.rw_byte -#endif - -// Get number of characters in receive FIFO -__forceinline static uint8_t uart_rxfifo_count(uint8_t nr) -{ - return uartHardware[nr].dev.status.rxfifo_cnt; -} - // Get number of characters in transmit FIFO -__forceinline static uint8_t uart_txfifo_count(uint8_t nr) +__forceinline static size_t uart_txfifo_count(uart_dev_t* dev) { - return uartHardware[nr].dev.status.txfifo_cnt; + return dev->status.txfifo_cnt; } // Get available free characters in transmit FIFO -__forceinline static uint8_t uart_txfifo_free(uint8_t nr) +__forceinline static size_t uart_txfifo_free(uart_dev_t* dev) { - return UART_TX_FIFO_SIZE - uart_txfifo_count(nr) - 1; + return UART_TX_FIFO_SIZE - uart_txfifo_count(dev) - 1; } // Return true if transmit FIFO is full -__forceinline static bool uart_txfifo_full(uint8_t nr) +__forceinline static bool uart_txfifo_full(uart_dev_t* dev) { - return uart_txfifo_count(nr) >= (UART_TX_FIFO_SIZE - 1); + return uart_txfifo_count(dev) >= (UART_TX_FIFO_SIZE - 1); } /** @brief Invoke a port callback, if one has been registered @@ -189,7 +209,9 @@ static bool realloc_buffer(SerialBuffer*& buffer, size_t new_size) return true; } - auto new_buf = new SerialBuffer; + // Avoid allocating in SPIRAM + auto mem = heap_caps_malloc(sizeof(SerialBuffer), MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL); + auto new_buf = new(mem) SerialBuffer; if(new_buf != nullptr && new_buf->resize(new_size) == new_size) { buffer = new_buf; return true; @@ -264,22 +286,14 @@ size_t smg_uart_read(smg_uart_t* uart, void* buffer, size_t size) // Top up from hardware FIFO if(is_physical(uart)) { - auto& hw = uartHardware[uart->uart_nr]; - while(read < size && uart_rxfifo_count(uart->uart_nr) != 0) { - buf[read++] = FIFO(hw.dev); - } + auto dev = getDevice(uart->uart_nr); + auto len = std::min(uint32_t(size - read), uart_ll_get_rxfifo_len(dev)); + uart_ll_read_rxfifo(dev, &buf[read], len); + read += len; // FIFO full may have been disabled if buffer overflowed, re-enabled it now - decltype(uart_dev_t::int_clr) clr{}; - clr.rxfifo_full = true; - clr.rxfifo_tout = true; - clr.rxfifo_ovf = true; - hw.dev.int_clr.val = clr.val; - decltype(uart_dev_t::int_ena) ena{}; - ena.rxfifo_full = true; - ena.rxfifo_tout = true; - ena.rxfifo_ovf = true; - hw.dev.int_ena.val = ena.val; + uart_ll_clr_intsts_mask(dev, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT | UART_INTR_RXFIFO_OVF); + uart_ll_ena_intr_mask(dev, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT | UART_INTR_RXFIFO_OVF); } return read; @@ -293,7 +307,8 @@ size_t smg_uart_rx_available(smg_uart_t* uart) smg_uart_disable_interrupts(); - size_t avail = is_physical(uart) ? uart_rxfifo_count(uart->uart_nr) : 0; + auto dev = getDevice(uart->uart_nr); + size_t avail = is_physical(uart) ? uart_ll_get_rxfifo_len(dev) : 0; if(uart->rx_buffer != nullptr) { avail += uart->rx_buffer->available(); @@ -314,11 +329,10 @@ static void IRAM_ATTR uart_isr(smg_uart_instance_t* inst) } auto uart = inst->uart; - auto uart_nr = uart->uart_nr; - auto& hw = uartHardware[uart_nr]; + auto dev = getDevice(uart->uart_nr); decltype(uart_dev_t::int_st) usis; - usis.val = hw.dev.int_st.val; + usis.val = dev->int_st.val; // If status is clear there's no interrupt to service on this UART if(usis.val == 0) { @@ -336,13 +350,15 @@ static void IRAM_ATTR uart_isr(smg_uart_instance_t* inst) // Read as much data as possible from the RX FIFO into buffer if(uart->rx_buffer != nullptr) { - size_t avail = uart_rxfifo_count(uart_nr); + size_t avail = uart_ll_get_rxfifo_len(dev); size_t space = uart->rx_buffer->getFreeSpace(); read = (avail <= space) ? avail : space; space -= read; + uint8_t buf[UART_RX_FIFO_SIZE]; + uart_ll_read_rxfifo(dev, buf, read); + uint8_t* ptr = buf; while(read-- != 0) { - uint8_t c = FIFO(hw.dev); - uart->rx_buffer->writeChar(c); + uart->rx_buffer->writeChar(*ptr++); } // Don't call back until buffer is (almost) full @@ -356,13 +372,9 @@ static void IRAM_ATTR uart_isr(smg_uart_instance_t* inst) * The interrupt gets re-enabled by a call to uart_read() or uart_flush() */ if(usis.rxfifo_ovf) { - hw.dev.int_ena.rxfifo_ovf = false; + uart_ll_disable_intr_mask(dev, UART_INTR_RXFIFO_OVF); } else if(read == 0) { - decltype(uart_dev_t::int_ena) ena{}; - ena.val = hw.dev.int_ena.val; - ena.rxfifo_full = true; - ena.rxfifo_tout = true; - hw.dev.int_ena.val = ena.val; + uart_ll_ena_intr_mask(dev, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT); } } @@ -370,18 +382,20 @@ static void IRAM_ATTR uart_isr(smg_uart_instance_t* inst) if(usis.txfifo_empty) { // Dump as much data as we can from buffer into the TX FIFO if(uart->tx_buffer != nullptr) { - size_t space = uart_txfifo_free(uart_nr); + size_t space = uart_txfifo_free(dev); size_t avail = uart->tx_buffer->available(); - size_t count = (avail <= space) ? avail : space; - while(count-- != 0) { - FIFO(hw.dev) = uart->tx_buffer->readChar(); + size_t count = std::min(avail, space); + uint8_t buf[count]; + for(unsigned i = 0; i < count; ++i) { + buf[i] = uart->tx_buffer->readChar(); } + uart_ll_write_txfifo(dev, buf, count); } // If TX FIFO remains empty then we must disable TX FIFO EMPTY interrupt to stop it recurring. - if(uart_txfifo_count(uart_nr) == 0) { + if(uart_txfifo_count(dev) == 0) { // The interrupt gets re-enabled by uart_write() - hw.dev.int_ena.txfifo_empty = false; + uart_ll_disable_intr_mask(dev, UART_INTR_TXFIFO_EMPTY); } else { // We've topped up TX FIFO so defer callback until next time status.txfifo_empty = false; @@ -397,7 +411,7 @@ static void IRAM_ATTR uart_isr(smg_uart_instance_t* inst) } // Final step is to clear status flags - hw.dev.int_clr.val = usis.val; + dev->int_clr.val = usis.val; } void smg_uart_start_isr(smg_uart_t* uart) @@ -406,19 +420,14 @@ void smg_uart_start_isr(smg_uart_t* uart) return; } - decltype(uart_dev_t::conf1) conf1{}; decltype(uart_dev_t::int_ena) int_ena{}; - auto& hw = uartHardware[uart->uart_nr]; + auto dev = getDevice(uart->uart_nr); + dev->conf1.val = 0; if(smg_uart_rx_enabled(uart)) { - conf1.rxfifo_full_thrhd = 120; -#if SUBARCH_ESP32 - conf1.rx_tout_thrhd = 2; -#else - hw.dev.mem_conf.rx_tout_thrhd = 2; -#endif - conf1.rx_tout_en = true; + uart_ll_set_rxfifo_full_thr(dev, 120); + uart_ll_set_rx_tout(dev, 10); /* * There is little benefit in generating interrupts on errors, instead these @@ -441,16 +450,16 @@ void smg_uart_start_isr(smg_uart_t* uart) */ // TX FIFO empty interrupt only gets enabled via uart_write function() - // conf1.txfifo_empty_thrhd = 0; + uart_ll_set_txfifo_empty_thr(dev, 10); } - hw.dev.conf1.val = conf1.val; - hw.dev.int_clr.val = 0x0007ffff; - hw.dev.int_ena.val = int_ena.val; + dev->int_clr.val = 0x0007ffff; + dev->int_ena.val = int_ena.val; smg_uart_disable_interrupts(); auto& inst = uartInstances[uart->uart_nr]; - esp_intr_alloc(hw.conn.irq, ESP_INTR_FLAG_LOWMED, intr_handler_t(uart_isr), &inst, &inst.handle); + auto& conn = uart_periph_signal[uart->uart_nr]; + esp_intr_alloc(conn.irq, ESP_INTR_FLAG_IRAM, intr_handler_t(uart_isr), &inst, &inst.handle); smg_uart_restore_interrupts(); bitSet(isrMask, uart->uart_nr); } @@ -471,13 +480,13 @@ size_t smg_uart_write(smg_uart_t* uart, const void* buffer, size_t size) if(isPhysical) { // If TX buffer not in use or it's empty then write directly to hardware FIFO if(uart->tx_buffer == nullptr || uart->tx_buffer->isEmpty()) { - auto& hw = uartHardware[uart->uart_nr]; - while(written < size && !uart_txfifo_full(uart->uart_nr)) { - FIFO(hw.dev) = buf[written++]; - } + auto dev = getDevice(uart->uart_nr); + auto len = std::min(size - written, uart_txfifo_free(dev)); + uart_ll_write_txfifo(dev, &buf[written], len); + written += len; // Enable TX FIFO EMPTY interrupt - hw.dev.int_clr.txfifo_empty = true; - hw.dev.int_ena.txfifo_empty = true; + uart_ll_clr_intsts_mask(dev, UART_INTR_TXFIFO_EMPTY); + uart_ll_ena_intr_mask(dev, UART_INTR_TXFIFO_EMPTY); } } @@ -506,7 +515,7 @@ size_t smg_uart_tx_free(smg_uart_t* uart) smg_uart_disable_interrupts(); - size_t space = is_physical(uart) ? uart_txfifo_free(uart->uart_nr) : 0; + size_t space = is_physical(uart) ? uart_txfifo_free(getDevice(uart->uart_nr)) : 0; if(uart->tx_buffer != nullptr) { space += uart->tx_buffer->getFreeSpace(); } @@ -531,7 +540,8 @@ void smg_uart_wait_tx_empty(smg_uart_t* uart) } if(is_physical(uart)) { - while(uart_txfifo_count(uart->uart_nr) != 0) + auto dev = getDevice(uart->uart_nr); + while(uart_txfifo_count(dev) != 0) system_soft_wdt_feed(); } } @@ -540,8 +550,8 @@ void smg_uart_set_break(smg_uart_t* uart, bool state) { uart = get_physical(uart); if(uart != nullptr) { - auto& hw = uartHardware[uart->uart_nr]; - hw.dev.conf0.txd_brk = state; + auto dev = getDevice(uart->uart_nr); + dev->conf0.txd_brk = state; } } @@ -559,15 +569,15 @@ uint8_t smg_uart_get_status(smg_uart_t* uart) // Read raw status register directly from real uart, masking out non-error bits uart = get_physical(uart); if(uart != nullptr) { - auto& hw = uartHardware[uart->uart_nr]; + auto dev = getDevice(uart->uart_nr); decltype(uart_dev_t::int_raw) int_raw; - int_raw.val = hw.dev.int_raw.val; + int_raw.val = dev->int_raw.val; status.brk_det |= int_raw.brk_det; status.rxfifo_ovf |= int_raw.rxfifo_ovf; status.frm_err |= int_raw.frm_err; status.parity_err |= int_raw.parity_err; // Clear errors - hw.dev.int_clr.val = status.val; + dev->int_clr.val = status.val; } smg_uart_restore_interrupts(); } @@ -594,45 +604,24 @@ void smg_uart_flush(smg_uart_t* uart, smg_uart_mode_t mode) } if(is_physical(uart)) { - auto& hw = uartHardware[uart->uart_nr]; + auto dev = getDevice(uart->uart_nr); if(flushTx) { // Prevent TX FIFO EMPTY interrupts - don't need them until uart_write is called again - hw.dev.int_ena.txfifo_empty = false; - hw.dev.conf0.txfifo_rst = true; - hw.dev.conf0.txfifo_rst = false; + uart_ll_disable_intr_mask(dev, UART_INTR_TXFIFO_EMPTY); + uart_ll_txfifo_rst(dev); } // If receive overflow occurred then these interrupts will be masked if(flushRx) { -#if SUBARCH_ESP32 - // Hardware issue: we can not use `rxfifo_rst` to reset the hw rxfifo - while(true) { - auto fifo_cnt = hw.dev.status.rxfifo_cnt; - decltype(uart_dev_t::mem_rx_status) stat; - stat.val = hw.dev.mem_rx_status.val; - if(fifo_cnt == 0 && (stat.rd_addr == stat.wr_addr)) { - break; - } - - (void)FIFO(hw.dev); - } -#else - hw.dev.conf0.rxfifo_rst = true; - hw.dev.conf0.rxfifo_rst = false; -#endif + uart_ll_rxfifo_rst(dev); decltype(uart_dev_t::int_clr) int_clr; int_clr.val = 0x0007ffff; int_clr.txfifo_empty = false; // Leave this one - hw.dev.int_clr.val = int_clr.val; - - decltype(uart_dev_t::int_ena) int_ena; - int_ena.val = hw.dev.int_ena.val; - int_ena.rxfifo_full = true; - int_ena.rxfifo_tout = true; - int_ena.rxfifo_ovf = true; - hw.dev.int_ena.val = int_ena.val; + dev->int_clr.val = int_clr.val; + + uart_ll_ena_intr_mask(dev, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT | UART_INTR_RXFIFO_OVF); } } @@ -645,27 +634,13 @@ uint32_t smg_uart_set_baudrate_reg(int uart_nr, uint32_t baud_rate) return 0; } - auto& hw = uartHardware[uart_nr]; + auto dev = getDevice(uart_nr); -#if SOC_UART_SUPPORT_XTAL_CLK -#define UART_ALT_CLK UART_SCLK_XTAL -#define UART_ALT_CLK_FREQ XTAL_CLK_FREQ -#else -#define UART_ALT_CLK UART_SCLK_REF_TICK -#define UART_ALT_CLK_FREQ REF_CLK_FREQ -#endif - - uint32_t sclk_freq = uart_use_apb_clock ? APB_CLK_FREQ : UART_ALT_CLK_FREQ; - uint32_t clk_div = 16U * sclk_freq / baud_rate; - // The baud-rate configuration register is divided into - // an integer part and a fractional part. - hw.dev.clk_div.div_int = clk_div / 16U; - hw.dev.clk_div.div_frag = clk_div % 16U; - // Configure the UART source clock. - uart_ll_set_sclk(&hw.dev, uart_use_apb_clock ? UART_SCLK_APB : UART_ALT_CLK); + uart_ll_set_sclk(dev, UART_SCLK_APB); + uart_ll_set_baudrate(dev, baud_rate); // Return the actual baud rate in use - return 16U * sclk_freq / clk_div; + return uart_ll_get_baudrate(dev); } uint32_t smg_uart_set_baudrate(smg_uart_t* uart, uint32_t baud_rate) @@ -694,14 +669,12 @@ smg_uart_t* smg_uart_init_ex(const smg_uart_config_t& cfg) return nullptr; } - auto uart = new smg_uart_t; + auto mem = heap_caps_malloc(sizeof(smg_uart_t), MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL); + auto uart = new(mem) smg_uart_t{}; if(uart == nullptr) { return nullptr; } - auto& hw = uartHardware[cfg.uart_nr]; - - memset(uart, 0, sizeof(smg_uart_t)); uart->uart_nr = cfg.uart_nr; uart->mode = cfg.mode; uart->options = cfg.options; @@ -718,15 +691,9 @@ smg_uart_t* smg_uart_init_ex(const smg_uart_config_t& cfg) delete uart; return nullptr; } - - // HardwareSerial default pin is 1 for all ports - check - if(cfg.uart_nr != 0 && tx_pin == 1) { - tx_pin = hw.tx_pin_default; - } else { - tx_pin = (tx_pin == UART_PIN_DEFAULT) ? hw.tx_pin_default : cfg.tx_pin; - } + rx_pin = (cfg.rx_pin == UART_PIN_DEFAULT) ? defaultPins[cfg.uart_nr].rx : cfg.rx_pin; } else { - tx_pin = UART_PIN_NO_CHANGE; + rx_pin = UART_PIN_NO_CHANGE; } if(smg_uart_tx_enabled(uart)) { @@ -735,21 +702,35 @@ smg_uart_t* smg_uart_init_ex(const smg_uart_config_t& cfg) delete uart; return nullptr; } - - rx_pin = (cfg.rx_pin == UART_PIN_DEFAULT) ? hw.rx_pin_default : cfg.rx_pin; + tx_pin = (tx_pin == UART_PIN_DEFAULT) ? defaultPins[cfg.uart_nr].tx : cfg.tx_pin; } else { - rx_pin = UART_PIN_NO_CHANGE; + tx_pin = UART_PIN_NO_CHANGE; } // OK, buffers allocated so setup hardware smg_uart_detach(cfg.uart_nr); smg_uart_set_pins(uart, tx_pin, rx_pin); - periph_module_reset(hw.conn.module); - periph_module_enable(hw.conn.module); + auto& conn = uart_periph_signal[cfg.uart_nr]; + + periph_module_enable(conn.module); + + auto dev = getDevice(cfg.uart_nr); + +// Workaround for ESP32C3: enable core reset before enabling uart module clock to prevent uart output garbage value. +#if SOC_UART_REQUIRE_CORE_RESET + uart_ll_set_reset_core(dev, true); + periph_module_reset(conn.module); + uart_ll_set_reset_core(dev, false); +#else + periph_module_reset(conn.module); +#endif + + uart_ll_set_mode(dev, UART_MODE_UART); + uart_ll_set_tx_idle_num(dev, 0); // Bottom 8 bits identical to esp8266 - hw.dev.conf0.val = (hw.dev.conf0.val & 0xFFFFFF00) | cfg.config; + dev->conf0.val = (dev->conf0.val & 0xFFFFFF00) | cfg.config; smg_uart_set_baudrate(uart, cfg.baudrate); smg_uart_flush(uart); @@ -775,8 +756,8 @@ void smg_uart_uninit(smg_uart_t* uart) smg_uart_set_debug(UART_NO); } - auto& hw = uartHardware[uart->uart_nr]; - periph_module_disable(hw.conn.module); + auto& conn = uart_periph_signal[uart->uart_nr]; + periph_module_disable(conn.module); uartInstances[uart->uart_nr].uart = nullptr; delete uart->rx_buffer; @@ -801,50 +782,7 @@ smg_uart_t* smg_uart_init(uint8_t uart_nr, uint32_t baudrate, uint32_t config, s void smg_uart_swap(smg_uart_t* uart, int tx_pin) { - /* - if(uart == nullptr) { - return; - } - - switch(uart->uart_nr) { - case UART0: - uart0_pin_restore(uart->tx_pin); - uart0_pin_restore(uart->rx_pin); - - if(uart->tx_pin == 1 || uart->tx_pin == 2 || uart->rx_pin == 3) { - if(smg_uart_tx_enabled(uart)) { - uart->tx_pin = 15; - } - - if(smg_uart_rx_enabled(uart)) { - uart->rx_pin = 13; - } - - SET_PERI_REG_MASK(UART_SWAP_REG, UART_SWAP0); - } else { - if(smg_uart_tx_enabled(uart)) { - uart->tx_pin = (tx_pin == 2) ? 2 : 1; - } - - if(smg_uart_rx_enabled(uart)) { - uart->rx_pin = 3; - } - - CLEAR_PERI_REG_MASK(UART_SWAP_REG, UART_SWAP0); - } - - uart0_pin_select(uart->tx_pin); - uart0_pin_select(uart->rx_pin); - break; - - case UART1: - // Currently no swap possible! See GPIO pins used by UART - break; - - default: - break; - } -*/ + // Not implemented } bool smg_uart_set_tx(smg_uart_t* uart, int tx_pin) @@ -866,12 +804,12 @@ bool smg_uart_set_pins(smg_uart_t* uart, int tx_pin, int rx_pin) return false; } - auto& hw = uartHardware[uart->uart_nr]; + auto& conn = uart_periph_signal[uart->uart_nr]; if(tx_pin != UART_PIN_NO_CHANGE) { PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[tx_pin], PIN_FUNC_GPIO); gpio_set_level(gpio_num_t(tx_pin), true); - gpio_matrix_out(tx_pin, hw.conn.tx_sig, false, false); + gpio_matrix_out(tx_pin, conn.tx_sig, false, false); uart->tx_pin = tx_pin; } @@ -879,7 +817,7 @@ bool smg_uart_set_pins(smg_uart_t* uart, int tx_pin, int rx_pin) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[rx_pin], PIN_FUNC_GPIO); gpio_set_pull_mode(gpio_num_t(rx_pin), GPIO_PULLUP_ONLY); gpio_set_direction(gpio_num_t(rx_pin), GPIO_MODE_INPUT); - gpio_matrix_in(rx_pin, hw.conn.rx_sig, false); + gpio_matrix_in(rx_pin, conn.rx_sig, false); } return true; @@ -921,10 +859,10 @@ void smg_uart_detach(int uart_nr) bitClear(isrMask, uart_nr); } - auto& hw = uartHardware[uart_nr]; - hw.dev.conf1.val = 0; - hw.dev.int_clr.val = 0x0007ffff; - hw.dev.int_ena.val = 0; + auto dev = getDevice(uart_nr); + dev->conf1.val = 0; + dev->int_clr.val = 0x0007ffff; + dev->int_ena.val = 0; smg_uart_restore_interrupts(); } @@ -937,10 +875,10 @@ void smg_uart_detach_all() esp_intr_free(inst.handle); inst.handle = nullptr; } - auto& hw = uartHardware[uart_nr]; - hw.dev.conf1.val = 0; - hw.dev.int_clr.val = 0x0007ffff; - hw.dev.int_ena.val = 0; + auto dev = getDevice(uart_nr); + dev->conf1.val = 0; + dev->int_clr.val = 0x0007ffff; + dev->int_ena.val = 0; } isrMask = 0; } diff --git a/Sming/Arch/Esp32/Components/esp32/component.mk b/Sming/Arch/Esp32/Components/esp32/component.mk index d1347f05e2..70ccb9f217 100644 --- a/Sming/Arch/Esp32/Components/esp32/component.mk +++ b/Sming/Arch/Esp32/Components/esp32/component.mk @@ -7,17 +7,13 @@ COMPONENT_DEPENDS := libc COMPONENT_SRCDIRS := src COMPONENT_INCDIRS := src/include include -# Set to build all components, otherwise just the core ones -CACHE_VARS += SDK_FULL_BUILD -SDK_FULL_BUILD ?= 0 - # Applications can provide file with custom SDK configuration settings CACHE_VARS += SDK_CUSTOM_CONFIG COMPONENT_RELINK_VARS += DISABLE_NETWORK DISABLE_WIFI -SDK_BUILD_BASE := $(COMPONENT_BUILD_BASE)/$(ESP_VARIANT)/sdk -SDK_COMPONENT_LIBDIR := $(COMPONENT_BUILD_BASE)/$(ESP_VARIANT)/lib +SDK_BUILD_BASE := $(COMPONENT_BUILD_BASE)/sdk +SDK_COMPONENT_LIBDIR := $(COMPONENT_BUILD_BASE)/lib SDKCONFIG_H := $(SDK_BUILD_BASE)/config/sdkconfig.h @@ -41,12 +37,10 @@ SDK_INCDIRS := \ bootloader_support/include_bootloader \ driver/$(ESP_VARIANT)/include \ driver/include \ - efuse/include \ - efuse/$(ESP_VARIANT)/include \ + esp_pm/include \ esp_rom/include/$(ESP_VARIANT) \ esp_rom/include \ $(ESP_VARIANT)/include \ - espcoredump/include \ esp_timer/include \ soc/include \ soc/$(ESP_VARIANT)/include \ @@ -54,48 +48,24 @@ SDK_INCDIRS := \ log/include \ nvs_flash/include \ freertos/include \ - esp_ringbuf/include \ esp_event/include \ - tcpip_adapter/include \ lwip/lwip/src/include \ lwip/port/esp32/include \ - lwip/include/apps \ - lwip/include/apps/sntp \ - mbedtls/mbedtls/include \ - mbedtls/port/include \ - mdns/include \ - mdns/private_include \ + newlib/platform_include \ spi_flash/include \ - ulp/include \ - vfs/include \ - xtensa-debug-module/include \ wpa_supplicant/include \ wpa_supplicant/port/include \ - app_trace/include \ - app_update/include \ - smartconfig_ack/include \ esp_hw_support/include \ hal/include \ hal/$(ESP_VARIANT)/include \ - esp_system/include - -ifeq ($(SDK_FULL_BUILD),1) -SDK_INCDIRS += \ - console \ - pthread/include \ - sdmmc/include -endif - -SDK_INCDIRS += \ + esp_system/include \ esp_common/include \ esp_adc_cal/include \ esp_netif/include \ esp_eth/include \ - esp_event/private_include \ esp_wifi/include \ esp_wifi/esp32/include \ lwip/include/apps/sntp \ - spi_flash/private_include \ wpa_supplicant/include/esp_supplicant ifdef IDF_TARGET_ARCH_RISCV @@ -109,33 +79,6 @@ SDK_INCDIRS += \ freertos/port/xtensa/include endif -ifeq ($(CONFIG_BT_NIMBLE_ENABLED),y) -SDK_INCDIRS += \ - bt/include \ - bt/common/osi/include \ - bt/common/btc/include \ - bt/common/include \ - bt/host/nimble/nimble/porting/nimble/include \ - bt/host/nimble/port/include \ - bt/host/nimble/nimble/nimble/include \ - bt/host/nimble/nimble/nimble/host/include \ - bt/host/nimble/nimble/nimble/host/services/ans/include \ - bt/host/nimble/nimble/nimble/host/services/bas/include \ - bt/host/nimble/nimble/nimble/host/services/gap/include \ - bt/host/nimble/nimble/nimble/host/services/gatt/include \ - bt/host/nimble/nimble/nimble/host/services/ias/include \ - bt/host/nimble/nimble/nimble/host/services/lls/include \ - bt/host/nimble/nimble/nimble/host/services/tps/include \ - bt/host/nimble/nimble/nimble/host/util/include \ - bt/host/nimble/nimble/nimble/host/store/ram/include \ - bt/host/nimble/nimble/nimble/host/store/config/include \ - bt/host/nimble/nimble/porting/npl/freertos/include \ - bt/host/nimble/nimble/ext/tinycrypt/include \ - bt/host/nimble/esp-hci/include -endif - -SDK_INCDIRS += \ - newlib/platform_include COMPONENT_INCDIRS += \ $(dir $(SDKCONFIG_H)) \ @@ -148,7 +91,6 @@ SDK_COMPONENTS := \ cxx \ driver \ efuse \ - esp-tls \ $(ESP_VARIANT) \ esp_common \ esp_event \ @@ -156,7 +98,6 @@ SDK_COMPONENTS := \ esp_hw_support \ esp_ipc \ esp_pm \ - esp_ringbuf \ esp_rom \ esp_system \ esp_timer \ @@ -167,12 +108,9 @@ SDK_COMPONENTS := \ log \ newlib \ nvs_flash \ - protobuf-c \ - protocomm \ pthread \ soc \ - spi_flash \ - vfs + spi_flash ifneq ($(DISABLE_NETWORK),1) SDK_COMPONENTS += \ @@ -200,34 +138,6 @@ else SDK_COMPONENTS += xtensa endif -ifeq ($(SDK_FULL_BUILD),1) -SDK_COMPONENTS += \ - app_trace \ - asio \ - bt \ - coap \ - console \ - esp_http_client \ - esp_http_server \ - esp_https_ota \ - esp_local_ctrl \ - esp_websocket_client \ - expat \ - fatfs \ - freemodbus \ - idf_test \ - jsmn \ - json \ - libsodium \ - mdns \ - mqtt \ - nghttp \ - sdmmc \ - ulp \ - unity \ - wear_levelling -endif - SDK_ESP_WIFI_LIBS := \ coexist \ core \ @@ -306,14 +216,8 @@ EXTRA_LDFLAGS := \ -Wl,--undefined=uxTopUsedPriority \ $(LDFLAGS_$(ESP_VARIANT)) -FLASH_BOOT_LOADER := $(SDK_BUILD_BASE)/bootloader/bootloader.bin -FLASH_BOOT_CHUNKS := 0x1000=$(FLASH_BOOT_LOADER) - SDK_DEFAULT_PATH := $(COMPONENT_PATH)/sdk - -##@SDK - -SDK_PROJECT_PATH := $(COMPONENT_PATH)/project/$(ESP_VARIANT) +SDK_PROJECT_PATH := $(COMPONENT_PATH)/project/$(ESP_VARIANT)/$(BUILD_TYPE) SDK_CONFIG_DEFAULTS := $(SDK_PROJECT_PATH)/sdkconfig.defaults SDKCONFIG_MAKEFILE := $(SDK_PROJECT_PATH)/sdkconfig @@ -322,18 +226,14 @@ ifeq ($(MAKE_DOCS),) endif export SDKCONFIG_MAKEFILE # sub-makes (like bootloader) will reuse this path +FLASH_BOOT_LOADER := $(SDK_BUILD_BASE)/bootloader/bootloader.bin +FLASH_BOOT_CHUNKS := $(CONFIG_BOOTLOADER_OFFSET_IN_FLASH)=$(FLASH_BOOT_LOADER) + $(SDK_BUILD_BASE) $(SDK_COMPONENT_LIBDIR): $(Q) mkdir -p $@ SDK_COMPONENT_LIBS := $(foreach c,$(SDK_COMPONENTS),$(SDK_COMPONENT_LIBDIR)/lib$c.a) -SDK_BUILD_COMPLETE := $(SDK_BUILD_BASE)/.complete - -CUSTOM_TARGETS += checksdk - -.PHONY: checksdk -checksdk: $(SDK_PROJECT_PATH) $(SDK_BUILD_COMPLETE) - SDK_BUILD = $(ESP32_PYTHON) $(IDF_PATH)/tools/idf.py -C $(SDK_PROJECT_PATH) -B $(SDK_BUILD_BASE) -G Ninja # For misc.mk / copylibs @@ -341,19 +241,21 @@ export SDK_BUILD_BASE export SDK_COMPONENT_LIBDIR export SDK_COMPONENTS -$(SDK_BUILD_COMPLETE): $(SDKCONFIG_H) $(SDKCONFIG_MAKEFILE) - $(Q) $(SDK_BUILD) reconfigure +CUSTOM_TARGETS += checksdk + +.PHONY: checksdk +checksdk: $(SDK_PROJECT_PATH) $(SDKCONFIG_H) $(SDKCONFIG_MAKEFILE) $(Q) $(NINJA) -C $(SDK_BUILD_BASE) bootloader app $(Q) $(MAKE) --no-print-directory -C $(SDK_DEFAULT_PATH) -f misc.mk copylibs - touch $(SDK_BUILD_COMPLETE) $(SDKCONFIG_H) $(SDKCONFIG_MAKEFILE) $(SDK_COMPONENT_LIBS): $(SDK_PROJECT_PATH) $(SDK_CONFIG_DEFAULTS) | $(SDK_BUILD_BASE) $(SDK_COMPONENT_LIBDIR) + $(Q) $(SDK_BUILD) reconfigure $(SDK_PROJECT_PATH): $(Q) mkdir -p $@ $(Q) cp -r $(SDK_DEFAULT_PATH)/project/* $@ -$(SDK_COMPONENT_LIBS): $(SDK_BUILD_COMPLETE) +$(SDK_COMPONENT_LIBS): checksdk SDK_CONFIG_FILES := \ common \ @@ -376,23 +278,27 @@ $(SDK_CONFIG_DEFAULTS): $(SDK_CUSTOM_CONFIG_PATH) $(if $(wildcard $f),cat $f >> $@;) \ ) +##@Configuration + PHONY: sdk-menuconfig sdk-menuconfig: $(SDK_CONFIG_DEFAULTS) | $(SDK_BUILD_BASE) ##Configure SDK options $(Q) $(SDK_BUILD) menuconfig - $(Q) rm -f $(SDK_BUILD_COMPLETE) - @echo Now run 'make esp32-build' + @echo Now run 'make' -.PHONY: sdk-defconfig -sdk-defconfig: $(SDKCONFIG_H) ##Create default SDK config files +##@Cleaning .PHONY: sdk-config-clean sdk-config-clean: esp32-clean ##Wipe SDK configuration and revert to defaults $(Q) rm -rf $(SDK_PROJECT_PATH) +##@Help + .PHONY: sdk-help sdk-help: ##Get SDK build options $(Q) $(SDK_BUILD) --help +##@Tools + .PHONY: sdk sdk: ##Pass options to IDF builder, e.g. `make sdk -- --help` or `make sdk menuconfig` $(Q) $(SDK_BUILD) $(filter-out sdk,$(MAKECMDGOALS)) diff --git a/Sming/Arch/Esp32/Components/esp32/sdk/config/common b/Sming/Arch/Esp32/Components/esp32/sdk/config/common index 929616cf60..4ac31502b3 100644 --- a/Sming/Arch/Esp32/Components/esp32/sdk/config/common +++ b/Sming/Arch/Esp32/Components/esp32/sdk/config/common @@ -26,3 +26,11 @@ CONFIG_ESP_TIMER_TASK_STACK_SIZE=16384 CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=8192 CONFIG_ESP_TIMER_IMPL_FRC2=y +# Disable VFS +CONFIG_VFS_SUPPORT_IO=n +CONFIG_VFS_SUPPORT_DIR=n +CONFIG_VFS_SUPPORT_SELECT=n +CONFIG_VFS_SUPPORT_TERMIOS=n + +# Debugging +CONFIG_ESP_SYSTEM_PANIC_GDBSTUB=y diff --git a/Sming/Arch/Esp32/Components/esp32/sdk/project/CMakeLists.txt b/Sming/Arch/Esp32/Components/esp32/sdk/project/CMakeLists.txt index bd18c8ced4..08d09bf1c8 100644 --- a/Sming/Arch/Esp32/Components/esp32/sdk/project/CMakeLists.txt +++ b/Sming/Arch/Esp32/Components/esp32/sdk/project/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.5) set(IDF_TARGET "$ENV{ESP_VARIANT}") +set(COMPONENTS $ENV{SDK_COMPONENTS} esptool_py main) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(Sming) diff --git a/Sming/Arch/Esp32/Components/esp32/src/clk.c b/Sming/Arch/Esp32/Components/esp32/src/clk.c new file mode 100644 index 0000000000..ca0bd2fee6 --- /dev/null +++ b/Sming/Arch/Esp32/Components/esp32/src/clk.c @@ -0,0 +1,60 @@ +#include "include/esp_clk.h" +#include +#include + +#if CONFIG_IDF_TARGET_ESP32 +typedef esp_pm_config_esp32_t pm_config_t; +#elif CONFIG_IDF_TARGET_ESP32C3 +typedef esp_pm_config_esp32c3_t pm_config_t; +#elif CONFIG_IDF_TARGET_ESP32S2 +typedef esp_pm_config_esp32s2_t pm_config_t; +#elif CONFIG_IDF_TARGET_ESP32S3 +typedef esp_pm_config_esp32s3_t pm_config_t; +#endif + +int esp_clk_cpu_freq(void); + +static esp_pm_lock_handle_t handle; + +bool system_update_cpu_freq(uint32_t freq) +{ + pm_config_t config = {}; + esp_err_t err = esp_pm_get_configuration(&config); + if(err != ESP_OK) { + debug_e("[PM] Failed to read PM config %u", err); + } else if(config.max_freq_mhz == freq) { + return true; + } + + if(handle == NULL) { + esp_err_t err = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "sming", &handle); + if(err != ESP_OK) { + debug_e("[PM] Failed to create lock"); + return false; + } + } else { + // Reverts PM to default settings + esp_pm_lock_release(handle); + } + + config.max_freq_mhz = config.min_freq_mhz = freq; + err = esp_pm_configure(&config); + if(err != ESP_OK) { + debug_e("[PM] Failed to set CPU to %u MHz", freq); + m_printHex("CFG", &config, sizeof(config), -1, 16); + return false; + } + + err = esp_pm_lock_acquire(handle); + if(err != ESP_OK) { + debug_e("[PM] Failed to lock CPU to %u MHz", freq); + return false; + } + + return true; +} + +uint32_t system_get_cpu_freq(void) +{ + return esp_clk_cpu_freq() / MHZ; +} diff --git a/Sming/Arch/Esp32/Components/esp32/src/include/esp_clk.h b/Sming/Arch/Esp32/Components/esp32/src/include/esp_clk.h index eaed0750d9..e34c31504a 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/include/esp_clk.h +++ b/Sming/Arch/Esp32/Components/esp32/src/include/esp_clk.h @@ -2,6 +2,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -13,20 +14,8 @@ extern "C" { #define SYS_CPU_160MHZ 160 #define SYS_CPU_240MHZ 240 -__forceinline bool system_update_cpu_freq(uint8_t freq) -{ - if(freq != SYS_CPU_80MHZ && freq != SYS_CPU_160MHZ && freq != SYS_CPU_240MHZ) { - return false; - } - - ets_update_cpu_frequency(freq); - return true; -} - -__forceinline uint32_t system_get_cpu_freq(void) -{ - return ets_get_cpu_frequency(); -} +bool system_update_cpu_freq(uint32_t freq); +uint32_t system_get_cpu_freq(void); __forceinline static uint32_t esp_get_ccount() { diff --git a/Sming/Arch/Esp32/Components/esp32/src/include/esp_systemapi.h b/Sming/Arch/Esp32/Components/esp32/src/include/esp_systemapi.h index 1d785f83b9..04897d7545 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/include/esp_systemapi.h +++ b/Sming/Arch/Esp32/Components/esp32/src/include/esp_systemapi.h @@ -44,13 +44,12 @@ /** @brief Disable interrupts * @retval Current interrupt level - * @note Hardware timer is unaffected if operating in non-maskable mode */ #define noInterrupts() portENTER_CRITICAL_NESTED() /** @brief Enable interrupts */ -#define interrupts() portEXIT_CRITICAL_NESTED(0) +#define interrupts() portENABLE_INTERRUPTS() /** @brief Restore interrupts to level saved from previous noInterrupts() call */ diff --git a/Sming/Arch/Esp32/Components/esp32/src/startup.cpp b/Sming/Arch/Esp32/Components/esp32/src/startup.cpp index d185c93ed7..13908fa2e9 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/startup.cpp +++ b/Sming/Arch/Esp32/Components/esp32/src/startup.cpp @@ -68,6 +68,8 @@ void main(void*) smg_uart_detach_all(); + esp_log_set_vprintf(m_vprintf); + #ifndef DISABLE_WIFI esp_init_flash(); esp_init_wifi(); diff --git a/Sming/Arch/Esp32/Components/esp32/src/system.cpp b/Sming/Arch/Esp32/Components/esp32/src/system.cpp index 29cc7a3333..fd0ce1fdee 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/system.cpp +++ b/Sming/Arch/Esp32/Components/esp32/src/system.cpp @@ -1,6 +1,7 @@ #include #include #include +#include extern "C" uint32_t system_get_time(void) { @@ -67,3 +68,18 @@ uint32_t system_get_chip_id() memcpy(&id, &baseMac[2], sizeof(id)); return id; } + +/* + * Building without WiFi sometimes leaves these functions undefined. + */ + +unsigned long WEAK_ATTR os_random(void) +{ + return esp_random(); +} + +int WEAK_ATTR os_get_random(unsigned char* buf, size_t len) +{ + esp_fill_random(buf, len); + return 0; +} diff --git a/Sming/Arch/Esp32/Components/esp32/src/tasks.cpp b/Sming/Arch/Esp32/Components/esp32/src/tasks.cpp index 49d8e28386..9cacd1000e 100644 --- a/Sming/Arch/Esp32/Components/esp32/src/tasks.cpp +++ b/Sming/Arch/Esp32/Components/esp32/src/tasks.cpp @@ -13,7 +13,7 @@ class TaskQueue read = count = 0; } - bool post(os_signal_t sig, os_param_t par) + bool IRAM_ATTR post(os_signal_t sig, os_param_t par) { bool full = (count == length); if(!full) { @@ -62,15 +62,13 @@ bool system_os_task(os_task_t callback, uint8_t prio, os_event_t* events, uint8_ return queue != nullptr; } -bool system_os_post(uint8_t prio, os_signal_t sig, os_param_t par) +bool IRAM_ATTR system_os_post(uint8_t prio, os_signal_t sig, os_param_t par) { if(prio >= USER_TASK_PRIO_MAX) { - debug_e("TQ: Invalid priority %u", prio); return false; } auto& queue = task_queues[prio]; if(queue == nullptr) { - debug_e("TQ: Task queue %u not initialised", prio); return false; } diff --git a/Sming/Arch/Esp32/Components/gdbstub/component.mk b/Sming/Arch/Esp32/Components/gdbstub/component.mk index 6790f9d714..ef86e79a3d 100644 --- a/Sming/Arch/Esp32/Components/gdbstub/component.mk +++ b/Sming/Arch/Esp32/Components/gdbstub/component.mk @@ -1,6 +1,14 @@ DEBUG_VARS += GDBSTUB_DIR GDBSTUB_DIR := $(COMPONENT_PATH) +CACHE_VARS += COM_PORT_GDB +DEBUG_VARS += COM_SPEED_GDB +COM_PORT_GDB ?= $(COM_PORT) +COM_SPEED_GDB ?= $(COM_SPEED_SERIAL) + # Full GDB command line +DEBUG_VARS += GDBSTUB_DIR +GDBSTUB_DIR := $(COMPONENT_PATH) + CACHE_VARS += GDB_CMDLINE -GDB_CMDLINE = trap '' INT; $(GDB) -x $(ARCH_TOOLS)/gdbinit $(TARGET_OUT) +GDB_CMDLINE = trap '' INT; $(GDB) -x $(GDBSTUB_DIR)/gdbcmds -b $(COM_SPEED_GDB) -ex "target remote $(COM_PORT_GDB)" $(TARGET_OUT) diff --git a/Sming/Arch/Esp32/Components/gdbstub/gdbcmds b/Sming/Arch/Esp32/Components/gdbstub/gdbcmds new file mode 100644 index 0000000000..1a8f57677f --- /dev/null +++ b/Sming/Arch/Esp32/Components/gdbstub/gdbcmds @@ -0,0 +1,5 @@ +# Enable this if you want to log all traffic between GDB and the stub +#set remotelogfile gdb_rsp_logfile.txt + +# Display a welcome prompt +echo \nWelcome to SMING!\nType 'c' (continue) to run application\n\n diff --git a/Sming/Arch/Esp32/Components/libc/component.mk b/Sming/Arch/Esp32/Components/libc/component.mk index 67f040512b..e7bac1bcb1 100644 --- a/Sming/Arch/Esp32/Components/libc/component.mk +++ b/Sming/Arch/Esp32/Components/libc/component.mk @@ -1,4 +1,8 @@ COMPONENT_SRCDIRS := src -COMPONENT_INCDIRS := include +COMPONENT_INCDIRS := src/include -COMPONENT_DOXYGEN_INPUT := include/sys +COMPONENT_DOXYGEN_INPUT := src/include/sys + +EXTRA_LDFLAGS := \ + -Wl,-wrap,_write_r \ + -Wl,-wrap,_read_r \ diff --git a/Sming/Arch/Esp32/Components/libc/include/assert.h b/Sming/Arch/Esp32/Components/libc/src/include/assert.h similarity index 100% rename from Sming/Arch/Esp32/Components/libc/include/assert.h rename to Sming/Arch/Esp32/Components/libc/src/include/assert.h diff --git a/Sming/Arch/Esp32/Components/libc/include/esp_attr.h b/Sming/Arch/Esp32/Components/libc/src/include/esp_attr.h similarity index 100% rename from Sming/Arch/Esp32/Components/libc/include/esp_attr.h rename to Sming/Arch/Esp32/Components/libc/src/include/esp_attr.h diff --git a/Sming/Arch/Esp32/Components/libc/include/sys/pgmspace.h b/Sming/Arch/Esp32/Components/libc/src/include/sys/pgmspace.h similarity index 90% rename from Sming/Arch/Esp32/Components/libc/include/sys/pgmspace.h rename to Sming/Arch/Esp32/Components/libc/src/include/sys/pgmspace.h index 9315325204..a2c3294ebe 100644 --- a/Sming/Arch/Esp32/Components/libc/include/sys/pgmspace.h +++ b/Sming/Arch/Esp32/Components/libc/src/include/sys/pgmspace.h @@ -21,11 +21,9 @@ extern "C" { /** * @brief Simple check to determine if a pointer refers to flash memory */ -#define isFlashPtr(ptr) \ - (((uint32_t)(ptr) >= SOC_DROM_LOW && (uint32_t)(ptr) < SOC_DROM_HIGH) || \ - ((uint32_t)(ptr) >= SOC_IROM_LOW && (uint32_t)(ptr) < SOC_IROM_HIGH)) +#define isFlashPtr(ptr) ((uint32_t)(ptr) >= SOC_DROM_LOW && (uint32_t)(ptr) < SOC_DROM_HIGH) -#define PROGMEM STORE_ATTR +#define PROGMEM STORE_ATTR ICACHE_RODATA_ATTR #define PROGMEM_PSTR PROGMEM #define PSTR(str) (str) diff --git a/Sming/Arch/Esp32/Components/libc/src/replacements.c b/Sming/Arch/Esp32/Components/libc/src/replacements.c new file mode 100644 index 0000000000..04d972852b --- /dev/null +++ b/Sming/Arch/Esp32/Components/libc/src/replacements.c @@ -0,0 +1,24 @@ +/* + * Provide overrides to direct any console writes e.g. via newlib printf. + */ + +#include +#include +#include + +ssize_t __wrap__write_r(struct _reent* r, int fd, const void* data, size_t size) +{ + (void)r; + (void)fd; // Ignore, direct everything + return m_nputs(data, size); +} + +ssize_t __wrap__read_r(struct _reent* r, int fd, void* dst, size_t size) +{ + (void)r; + (void)fd; + (void)dst; + (void)size; + errno = ENOSYS; + return -1; +} diff --git a/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp b/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp index d77efdd403..0079c0c690 100644 --- a/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp +++ b/Sming/Arch/Esp32/Components/spi_flash/flashmem.cpp @@ -10,16 +10,10 @@ #include #include -#include -#include #include -#include #include #include - -#ifndef CONFIG_IDF_TARGET_ESP32C3 -#include -#endif +#include /* * Physical <-> Virtual address mapping is handled in `$IDF_COMPONENTS/spi_flash/flash_mmap.c`. @@ -28,28 +22,27 @@ */ uint32_t flashmem_get_address(const void* memptr) { -#define VADDR0_START_ADDR SOC_DROM_LOW -#define VADDR1_START_ADDR 0x40000000 - auto vaddr = reinterpret_cast(memptr); - - uint32_t page; - if(vaddr >= SOC_DROM_LOW && vaddr < SOC_DROM_HIGH) { - auto offset = vaddr - VADDR0_START_ADDR; - page = offset / SPI_FLASH_MMU_PAGE_SIZE; - } else if(vaddr >= SOC_IROM_LOW && vaddr < SOC_IROM_HIGH) { - auto offset = vaddr - VADDR1_START_ADDR; - page = 64 + (offset / SPI_FLASH_MMU_PAGE_SIZE); - } else { + if(vaddr < SOC_DROM_LOW || vaddr >= SOC_DROM_HIGH) { return 0; } + + auto offset = vaddr - SOC_MMU_VADDR0_START_ADDR; + uint32_t page = SOC_MMU_DROM0_PAGES_START + (offset / SPI_FLASH_MMU_PAGE_SIZE); #if CONFIG_IDF_TARGET_ESP32 && !CONFIG_FREERTOS_UNICORE - uint32_t entry = DPORT_SEQUENCE_REG_READ(uint32_t(&DPORT_APP_FLASH_MMU_TABLE[page])); + uint32_t entry = DPORT_APP_FLASH_MMU_TABLE[page]; #else - uint32_t entry = DPORT_SEQUENCE_REG_READ(uint32_t(&SOC_MMU_DPORT_PRO_FLASH_MMU_TABLE[page])); + uint32_t entry = SOC_MMU_DPORT_PRO_FLASH_MMU_TABLE[page]; #endif - uint32_t paddr = (entry * SPI_FLASH_MMU_PAGE_SIZE) + (vaddr & (SPI_FLASH_MMU_PAGE_SIZE - 1)); - return (entry & 0x0100) ? 0 : paddr; + + if(entry == SOC_MMU_INVALID_ENTRY_VAL) { + debug_e("Invalid flash address %p (page %u, entry 0x%08x)", memptr, page, entry); + return 0; + } + + entry &= SOC_MMU_ADDR_MASK; + uint32_t paddr = (entry * SPI_FLASH_MMU_PAGE_SIZE) + (vaddr % SPI_FLASH_MMU_PAGE_SIZE); + return paddr; } uint32_t flashmem_write(const void* from, uint32_t toaddr, uint32_t size) diff --git a/Sming/Arch/Esp32/Platform/Clocks.h b/Sming/Arch/Esp32/Platform/Clocks.h index 9a7e838b05..34484ac99b 100644 --- a/Sming/Arch/Esp32/Platform/Clocks.h +++ b/Sming/Arch/Esp32/Platform/Clocks.h @@ -38,6 +38,10 @@ using PolledTimerClock = OsTimerClock; using CpuCycleClockSlow = CpuCycleClock; using CpuCycleClockNormal = CpuCycleClock; +#ifdef SUBARCH_ESP32C3 +using CpuCycleClockFast = CpuCycleClockNormal; +#else using CpuCycleClockFast = CpuCycleClock; +#endif /** @} */ diff --git a/Sming/Arch/Esp32/README.rst b/Sming/Arch/Esp32/README.rst index 05831e40ba..3092ea6496 100644 --- a/Sming/Arch/Esp32/README.rst +++ b/Sming/Arch/Esp32/README.rst @@ -30,7 +30,7 @@ Requirements In order to be able to compile for the ESP32 architecture you should have ESP-IDF v4.3 installed. Some slight changes are required to enable code to compile correctly for C++, -so a fork has been created here https://github.com/mikee47/esp-idf/tree/sming/release%2Fv4.3 +so a fork has been created here https://github.com/mikee47/esp-idf/tree/sming/release/v4.3 which you may clone. The Sming installers do all this for you - see :doc:`/getting-started/index`. @@ -89,13 +89,14 @@ This is still at an early stage of development however basic applications should - esp32c3 - esp32s3 -If changing variant the project must be cleaned first. You can change variants like this: +You can change variants like this: ``` -make SMING_ARCH=Esp32 clean components-clean -make ESP_VARIANT=esp32c3 +make SMING_ARCH=Esp32 ESP_VARIANT=esp32c3 ``` +Each variant uses a different build directory, e.g. ``out/Esp32/esp32c3/...`` to avoid conflicts. + See :component-esp32:`esp32` for further details. diff --git a/Sming/Arch/Esp32/System/include/user_config.h b/Sming/Arch/Esp32/System/include/user_config.h index b57a7d9666..590d433248 100644 --- a/Sming/Arch/Esp32/System/include/user_config.h +++ b/Sming/Arch/Esp32/System/include/user_config.h @@ -12,10 +12,6 @@ #include // Network base API -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wsign-compare" #include -#pragma GCC diagnostic pop - #endif diff --git a/Sming/Arch/Esp32/Tools/ci/build.run.sh b/Sming/Arch/Esp32/Tools/ci/build.run.sh old mode 100755 new mode 100644 index 1d1aa4aa39..12de1fb80e --- a/Sming/Arch/Esp32/Tools/ci/build.run.sh +++ b/Sming/Arch/Esp32/Tools/ci/build.run.sh @@ -4,13 +4,10 @@ $MAKE_PARALLEL Basic_Blink Basic_WiFi HttpServer_ConfigNetwork DEBUG_VERBOSE_LEV $MAKE_PARALLEL Basic_Ssl ENABLE_SSL=Bearssl DEBUG_VERBOSE_LEVEL=3 STRICT=1 # esp32s2 -make clean components-clean $MAKE_PARALLEL Basic_Blink ESP_VARIANT=esp32s2 # esp32c3 -make clean components-clean $MAKE_PARALLEL Basic_Blink ESP_VARIANT=esp32c3 # esp32s3 -make clean components-clean $MAKE_PARALLEL Basic_Blink ESP_VARIANT=esp32s3 diff --git a/Sming/Arch/Esp32/app.mk b/Sming/Arch/Esp32/app.mk index 6f4dc23d03..db6ca31cbf 100644 --- a/Sming/Arch/Esp32/app.mk +++ b/Sming/Arch/Esp32/app.mk @@ -35,5 +35,10 @@ $(TARGET_OUT): $(COMPONENTS_AR) cat $(FW_MEMINFO_NEW); \ fi +CHIP_REV_MIN := $(CONFIG_$(call ToUpper,$(ESP_VARIANT))_REV_MIN) +ifeq ($(CHIP_REV_MIN),) +CHIP_REV_MIN := 0 +endif + $(TARGET_BIN): $(TARGET_OUT) - $(Q) $(ESPTOOL_CMDLINE) elf2image --min-rev 0 --elf-sha256-offset 0xb0 $(flashimageoptions) -o $@ $< + $(Q) $(ESPTOOL_CMDLINE) elf2image --min-rev $(CHIP_REV_MIN) --elf-sha256-offset 0xb0 $(flashimageoptions) -o $@ $< diff --git a/Sming/Arch/Esp32/build.mk b/Sming/Arch/Esp32/build.mk index 73b15f4107..3356671ea9 100644 --- a/Sming/Arch/Esp32/build.mk +++ b/Sming/Arch/Esp32/build.mk @@ -23,7 +23,7 @@ endif export IDF_TOOLS_PATH := $(call FixPath,$(IDF_TOOLS_PATH)) ifndef ESP_VARIANT -ESP_VARIANT := esp32 +override ESP_VARIANT := esp32 endif export ESP_VARIANT diff --git a/Sming/Arch/Esp8266/build.mk b/Sming/Arch/Esp8266/build.mk index 1d41353210..d3497ba66d 100644 --- a/Sming/Arch/Esp8266/build.mk +++ b/Sming/Arch/Esp8266/build.mk @@ -4,6 +4,10 @@ # ############## +ifdef ESP_VARIANT +override ESP_VARIANT := +endif + CPPFLAGS += -DARCH_ESP8266 CXXFLAGS += -fno-rtti -fno-exceptions -fno-threadsafe-statics diff --git a/Sming/Arch/Host/build.mk b/Sming/Arch/Host/build.mk index db1582468f..0f98412d23 100644 --- a/Sming/Arch/Host/build.mk +++ b/Sming/Arch/Host/build.mk @@ -4,6 +4,10 @@ # ############## +ifdef ESP_VARIANT +override ESP_VARIANT := +endif + CPPFLAGS += -DARCH_HOST TOOLSPEC := diff --git a/Sming/Components/Network/Arch/Esp32/Platform/LwipAdapter.cpp b/Sming/Components/Network/Arch/Esp32/Platform/LwipAdapter.cpp deleted file mode 100644 index 4d59e586e8..0000000000 --- a/Sming/Components/Network/Arch/Esp32/Platform/LwipAdapter.cpp +++ /dev/null @@ -1,876 +0,0 @@ -/** - A big thank you to Hristo Gochkov and his Asynchronous TCP library - Big chunks of the code are inspired from this project. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#if 0 - -#include "LwipAdapter.h" -#include -#include "esp_task_wdt.h" -extern "C" { -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "lwip/priv/tcpip_priv.h" -} - -// TODO: Tune these.... -#define CONFIG_ASYNC_TCP_RUNNING_CORE 1 -#define CONFIG_ASYNC_TCP_USE_WDT 1 - -typedef enum { - LWIP_TCP_SENT, - LWIP_TCP_RECV, - LWIP_TCP_FIN, - LWIP_TCP_ERROR, - LWIP_TCP_POLL, - LWIP_TCP_CLEAR, - LWIP_TCP_ACCEPT, - LWIP_TCP_CONNECTED, - LWIP_TCP_DNS -} lwip_event_t; - -typedef struct { - lwip_event_t event; - void* arg; - union { - struct { - tcp_pcb* pcb; - int8_t err; - } connected; - struct { - int8_t err; - } error; - struct { - tcp_pcb* pcb; - uint16_t len; - } sent; - struct { - tcp_pcb* pcb; - pbuf* pb; - int8_t err; - } recv; - struct { - tcp_pcb* pcb; - int8_t err; - } fin; - struct { - tcp_pcb* pcb; - } poll; - struct { - tcp_pcb* pcb; - int8_t err; - } accept; - struct { - const char* name; - ip_addr_t addr; - } dns; - }; -} lwip_event_packet_t; - -struct DnsLookup { - TcpConnection* con; - int port; -}; - -typedef struct { - TcpConnection* connection; - uint8_t closed; // 0 - open, 1 - closed - struct { - tcp_connected_fn callback; - } connect; - struct { - tcp_accept_fn callback; - } accept; - struct { - tcp_recv_fn callback; - } receive; - struct { - tcp_sent_fn callback; - } sent; - struct { - tcp_poll_fn callback; - } poll; - struct { - tcp_err_fn callback; - } error; - struct { - dns_found_callback callback; - DnsLookup* lookup; - } dns; - // TODO: ... -} tcp_api_arg_t; - -typedef struct { - struct tcpip_api_call_data call; - tcp_pcb* pcb; - int8_t err; - union { - struct { - const char* data; - size_t size; - uint8_t apiflags; - } write; - size_t received; - struct { - const ip_addr_t* addr; - uint16_t port; - tcp_connected_fn cb; - } connect; - struct { - const ip_addr_t* addr; - uint16_t port; - } bind; - uint8_t backlog; - }; -} tcp_api_call_t; - -// Event Logic -static xQueueHandle _async_queue; -static TaskHandle_t _async_service_task_handle = NULL; - -// TODO: remove the slots.. -//SemaphoreHandle_t _slots_lock; -//const int _number_of_closed_slots = CONFIG_LWIP_MAX_ACTIVE_TCP; -//static uint32_t _closed_slots[_number_of_closed_slots]; -//static uint32_t _closed_index = []() { -// _slots_lock = xSemaphoreCreateBinary(); -// xSemaphoreGive(_slots_lock); -// for(int i = 0; i < _number_of_closed_slots; ++i) { -// _closed_slots[i] = 1; -// } -// return 1; -//}(); - -static inline bool _init_async_event_queue() -{ - if(!_async_queue) { - _async_queue = xQueueCreate(32, sizeof(lwip_event_packet_t*)); - if(!_async_queue) { - return false; - } - } - return true; -} - -static inline bool _send_async_event(lwip_event_packet_t** e) -{ - return _async_queue && xQueueSend(_async_queue, e, portMAX_DELAY) == pdPASS; -} - -static inline bool _prepend_async_event(lwip_event_packet_t** e) -{ - return _async_queue && xQueueSendToFront(_async_queue, e, portMAX_DELAY) == pdPASS; -} - -static inline bool _get_async_event(lwip_event_packet_t** e) -{ - return _async_queue && xQueueReceive(_async_queue, e, portMAX_DELAY) == pdPASS; -} - -static bool _remove_events_with_arg(void* arg) -{ - lwip_event_packet_t* first_packet = NULL; - lwip_event_packet_t* packet = NULL; - - if(!_async_queue) { - return false; - } - //figure out which is the first packet so we can keep the order - while(!first_packet) { - if(xQueueReceive(_async_queue, &first_packet, 0) != pdPASS) { - return false; - } - //discard packet if matching - if((int)first_packet->arg == (int)arg) { - free(first_packet); - first_packet = NULL; - //return first packet to the back of the queue - } else if(xQueueSend(_async_queue, &first_packet, portMAX_DELAY) != pdPASS) { - return false; - } - } - - while(xQueuePeek(_async_queue, &packet, 0) == pdPASS && packet != first_packet) { - if(xQueueReceive(_async_queue, &packet, 0) != pdPASS) { - return false; - } - if((int)packet->arg == (int)arg) { - free(packet); - packet = NULL; - } else if(xQueueSend(_async_queue, &packet, portMAX_DELAY) != pdPASS) { - return false; - } - } - return true; -} - -static void _handle_async_event(lwip_event_packet_t* e) -{ - tcp_api_arg_t* arg = reinterpret_cast(e->arg); - - if(e->arg == NULL) { - // do nothing when arg is NULL - debug_d("event (%d) arg == NULL(org: 0x%08x): 0x%08x, Pcb State: %d", e->event, e->arg, e->recv.pcb, e->recv.pcb->state); - if(e->event == LWIP_TCP_POLL) { - debug_d("Close connection. Pcb: 0x%08x", e->poll.pcb); - async_tcp_close(e->poll.pcb); // close the connection - } - - } else if(e->event == LWIP_TCP_CLEAR) { - _remove_events_with_arg(e->arg); - } else if(e->event == LWIP_TCP_RECV) { - debug_d("-R: Pcb: 0x%08x, Arg: 0x%08x, Err: %d", e->recv.pcb, e->arg, e->recv.err); - if(arg->receive.callback) { - arg->receive.callback(arg->connection, e->recv.pcb, e->recv.pb, e->recv.err); - } - } else if(e->event == LWIP_TCP_FIN) { - debug_d("-F: Pcb: 0x%08x, Arg: 0x%08x", e->fin.pcb, e->arg); - debug_d("Close connection. Pcb: 0x%08x", e->fin.pcb); - async_tcp_close(e->fin.pcb); // close the connection - } else if(e->event == LWIP_TCP_SENT) { - debug_d("-S: Pcb: 0x%08x, Arg: 0x%08x, Callback: 0x%08x", e->sent.pcb, e->arg, arg->sent.callback); - if(arg->sent.callback) { - arg->sent.callback(arg->connection, e->sent.pcb, e->sent.len); - } - } else if(e->event == LWIP_TCP_POLL) { - debug_d("-P: Pcb: 0x%08x, Arg: 0x%08x, Callback: 0x%08x", e->poll.pcb, e->arg, arg->poll.callback); - if(arg->poll.callback) { - arg->poll.callback(arg->connection, e->poll.pcb); - } - } else if(e->event == LWIP_TCP_ERROR) { - debug_d("-E: Arg: 0x%08x, Error: %d", e->arg, e->error.err); - if(arg->error.callback) { - arg->error.callback(arg->connection, e->error.err); - } - } else if(e->event == LWIP_TCP_CONNECTED) { - debug_d("-C: Pcb: 0x%08x, Arg: 0x%08x, Callback: 0x%08x, Err: %d", e->connected.pcb, e->arg, arg->connect.callback, e->connected.err); - if(arg->connect.callback) { - arg->connect.callback(arg->connection, e->connected.pcb, e->connected.err); - } - } else if(e->event == LWIP_TCP_ACCEPT) { - debug_d("-A: Pcb: 0x%08x, Arg: 0x%08x, Callback: 0x%08x", e->accept.pcb, e->arg, arg->accept.callback); - if(arg->accept.callback) { - arg->accept.callback(arg->connection, e->accept.pcb, e->accept.err); - } - } else if(e->event == LWIP_TCP_DNS) { - debug_d("D: 0x%08x %s = %s", e->arg, e->dns.name, ipaddr_ntoa(&e->dns.addr)); - if(arg->dns.callback) { - arg->dns.callback(e->dns.name, &e->dns.addr, arg->dns.lookup); - } - delete arg; - } - free((void*)(e)); -} - -static void _async_service_task(void* pvParameters) -{ - lwip_event_packet_t* packet = NULL; - for(;;) { - if(_get_async_event(&packet)) { -#if CONFIG_ASYNC_TCP_USE_WDT - if(esp_task_wdt_add(NULL) != ESP_OK) { - debug_e("Failed to add async task to WDT"); - } -#endif - _handle_async_event(packet); -#if CONFIG_ASYNC_TCP_USE_WDT - if(esp_task_wdt_delete(NULL) != ESP_OK) { - debug_e("Failed to remove loop task from WDT"); - } -#endif - } - } - vTaskDelete(NULL); - _async_service_task_handle = NULL; -} -/* -static void _stop_async_task(){ - if(_async_service_task_handle){ - vTaskDelete(_async_service_task_handle); - _async_service_task_handle = NULL; - } -} -*/ -static bool _start_async_task() -{ - if(!_init_async_event_queue()) { - return false; - } - if(!_async_service_task_handle) { - xTaskCreatePinnedToCore(_async_service_task, "async_tcp", 8192 * 2, NULL, 3, &_async_service_task_handle, - CONFIG_ASYNC_TCP_RUNNING_CORE); - if(!_async_service_task_handle) { - return false; - } - debug_d("Starting Async Event Queue."); - } - return true; -} - -// Low-Level LwIP Functions -static int8_t _tcp_clear_events(void* arg) -{ - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_CLEAR; - e->arg = arg; - if(!_prepend_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static int8_t _tcp_connected(void* arg, tcp_pcb* pcb, int8_t err) -{ - debug_d("+C: 0x%08x", pcb); - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - - e->event = LWIP_TCP_CONNECTED; - e->arg = arg; - e->connected.pcb = pcb; - e->connected.err = err; - if(!_prepend_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static int8_t _tcp_poll(void* arg, struct tcp_pcb* pcb) -{ - debug_d("+P: 0x%08x", pcb); - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_POLL; - e->arg = arg; - e->poll.pcb = pcb; - if(!_send_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static int8_t _tcp_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* pb, int8_t err) -{ - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->arg = arg; - if(pb) { - debug_d("+R: 0x%08x", pcb); - e->event = LWIP_TCP_RECV; - e->recv.pcb = pcb; - e->recv.pb = pb; - e->recv.err = err; - } else { - debug_d("+F: 0x%08x", pcb); - e->event = LWIP_TCP_FIN; - e->fin.pcb = pcb; - e->fin.err = err; - // //close the PCB in LwIP thread - // // TODO: - //// TcpConnection::_s_lwip_fin(e->arg, e->fin.pcb, e->fin.err); - } - if(!_send_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static int8_t _tcp_sent(void* arg, struct tcp_pcb* pcb, uint16_t len) -{ - debug_d("+S: 0x%08x", pcb); - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_SENT; - e->arg = arg; - e->sent.pcb = pcb; - e->sent.len = len; - if(!_send_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static void _tcp_error(void* arg, int8_t err) -{ - debug_d("+E: 0x%08x", arg); - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_ERROR; - e->arg = arg; - e->error.err = err; - if(!_send_async_event(&e)) { - free((void*)(e)); - } -} - -static void _tcp_dns_found(const char* name, const ip_addr* ipaddr, void* arg) -{ - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - debug_d("+DNS: name=%s ipaddr=0x%08x arg=%x", name, ipaddr, arg); - e->event = LWIP_TCP_DNS; - e->arg = arg; - e->dns.name = name; - if(ipaddr) { - memcpy(&e->dns.addr, ipaddr, sizeof(struct ip_addr)); - } else { - memset(&e->dns.addr, 0, sizeof(e->dns.addr)); - } - if(!_send_async_event(&e)) { - free((void*)(e)); - } -} - -//Used to switch out from LwIP thread -static int8_t _tcp_accept(void* arg, struct tcp_pcb* newpcb, err_t err) -{ - debug_d("+A: arg: 0x%08x, new pcb: 0x%08x, error: %d", arg, newpcb, err); - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_ACCEPT; - e->arg = arg; - e->accept.pcb = newpcb; - e->accept.err = err; - if(!_prepend_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -/* - * TCP/IP API Calls - * */ - -static err_t _tcp_output_api(struct tcpip_api_call_data* api_call_msg) -{ - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = ERR_CONN; - tcp_api_arg_t* arg = reinterpret_cast(msg->pcb->callback_arg); - if(arg != nullptr && arg->closed) { - return msg->err; - } - msg->err = tcp_output(msg->pcb); - return msg->err; -} - -static esp_err_t _tcp_output(tcp_pcb* pcb) -{ - if(!pcb) { - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - tcpip_api_call(_tcp_output_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_write_api(struct tcpip_api_call_data* api_call_msg) -{ - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = ERR_CONN; - tcp_api_arg_t* arg = reinterpret_cast(msg->pcb->callback_arg); - if(arg != nullptr && arg->closed) { - return msg->err; - } - msg->err = tcp_write(msg->pcb, msg->write.data, msg->write.size, msg->write.apiflags); - return msg->err; -} - -static esp_err_t _tcp_write(tcp_pcb* pcb, const char* data, size_t size, uint8_t apiflags) -{ - if(!pcb) { - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - - msg.write.data = data; - msg.write.size = size; - msg.write.apiflags = apiflags; - tcpip_api_call(_tcp_write_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_recved_api(struct tcpip_api_call_data* api_call_msg) -{ - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = ERR_CONN; - tcp_api_arg_t* arg = reinterpret_cast(msg->pcb->callback_arg); - if(arg != nullptr && arg->closed) { - return msg->err; - } - - tcp_recved(msg->pcb, msg->received); - return msg->err; -} - -static esp_err_t _tcp_recved(tcp_pcb* pcb, size_t len) -{ - if(!pcb) { - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - - msg.received = len; - tcpip_api_call(_tcp_recved_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_close_api(struct tcpip_api_call_data* api_call_msg) -{ - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = ERR_CONN; - tcp_api_arg_t* arg = reinterpret_cast(msg->pcb->callback_arg); - if(arg != nullptr) { - if(arg->closed) { - return msg->err; - } - arg->closed = 1; - } - msg->err = tcp_close(msg->pcb); - _tcp_clear_events(msg->pcb); - return msg->err; -} - -static esp_err_t _tcp_close(tcp_pcb* pcb) -{ - if(!pcb) { - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - - tcpip_api_call(_tcp_close_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_abort_api(struct tcpip_api_call_data* api_call_msg) -{ - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = ERR_CONN; - tcp_api_arg_t* arg = reinterpret_cast(msg->pcb->callback_arg); - if(arg != nullptr) { - if(arg->closed) { - return msg->err; - } - arg->closed = 1; - } - - tcp_abort(msg->pcb); - return msg->err; -} - -static esp_err_t _tcp_abort(tcp_pcb* pcb) -{ - if(!pcb) { - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - - tcpip_api_call(_tcp_abort_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_connect_api(struct tcpip_api_call_data* api_call_msg) -{ - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = tcp_connect(msg->pcb, msg->connect.addr, msg->connect.port, _tcp_connected); - return msg->err; -} - -static esp_err_t _tcp_connect(tcp_pcb* pcb, const ip_addr_t* addr, uint16_t port, tcp_connected_fn cb) -{ - if(!pcb) { - return ESP_FAIL; - } - - tcp_api_call_t msg; - - tcp_api_arg_t* arg = reinterpret_cast(pcb->callback_arg); - if(arg != nullptr) { - debug_d("Connecting ..."); - arg->closed = 0; - arg->connect.callback = cb; - } - - msg.pcb = pcb; - - msg.connect.addr = addr; - msg.connect.port = port; - msg.connect.cb = _tcp_connected; - tcpip_api_call(_tcp_connect_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_bind_api(struct tcpip_api_call_data* api_call_msg) -{ - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = tcp_bind(msg->pcb, msg->bind.addr, msg->bind.port); - return msg->err; -} - -static esp_err_t _tcp_bind(tcp_pcb* pcb, const ip_addr_t* addr, uint16_t port) -{ - if(!pcb) { - return ESP_FAIL; - } - tcp_api_call_t msg; - msg.pcb = pcb; - tcp_api_arg_t* arg = reinterpret_cast(msg.pcb->callback_arg); - if(arg != nullptr) { - arg->closed = 0; - } - msg.bind.addr = addr; - msg.bind.port = port; - tcpip_api_call(_tcp_bind_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_listen_api(struct tcpip_api_call_data* api_call_msg) -{ - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = 0; - msg->pcb = tcp_listen_with_backlog(msg->pcb, msg->backlog); - return msg->err; -} - -static tcp_pcb* _tcp_listen_with_backlog(tcp_pcb* pcb, uint8_t backlog) -{ - if(!pcb) { - return NULL; - } - tcp_api_call_t msg; - msg.pcb = pcb; - tcp_api_arg_t* arg = reinterpret_cast(msg.pcb->callback_arg); - if(arg != nullptr) { - arg->closed = 0; - } - msg.backlog = backlog ? backlog : TCP_DEFAULT_LISTEN_BACKLOG; - tcpip_api_call(_tcp_listen_api, (struct tcpip_api_call_data*)&msg); - return msg.pcb; -} - -// High Level Functions - -tcp_pcb* async_tcp_new() -{ - return tcp_new_ip_type(IPADDR_TYPE_V4); -} - -void async_tcp_arg(struct tcp_pcb* pcb, void* arg) -{ - if(pcb == nullptr) { - return; - } - - tcp_api_arg_t* apiArgument = reinterpret_cast(pcb->callback_arg); - // delete the current argument if this is an api argument - if(apiArgument != nullptr) { - delete apiArgument; - apiArgument = nullptr; - } - - TcpConnection* connectionArg = reinterpret_cast(arg); - if(connectionArg != nullptr) { - // we have the right argument, lets wrap it - if(apiArgument == nullptr) { - apiArgument = new tcp_api_arg_t(); - memset(apiArgument, 0, sizeof(tcp_api_arg_t)); - } - apiArgument->connection = connectionArg; - debug_d("Arg: Set wrapped arg. Pcb: 0x%08x, arg: 0x%08x, connection: 0x%08x", pcb, apiArgument, arg); - tcp_arg(pcb, apiArgument); - return; - } - - // all other arguments are set as usual - debug_d("Arg: Set unknown arg. Pcb: 0x%08x, arg: 0x%08x", pcb, arg); - tcp_arg(pcb, arg); -} - -err_t async_tcp_connect(tcp_pcb* pcb, const ip_addr_t* ipaddr, u16_t port, tcp_connected_fn connected) -{ - if(!_start_async_task()) { - return ERR_ABRT; - } - - debug_d("Connecting: Pcb: 0x%08x", pcb); - - return _tcp_connect(pcb, ipaddr, port, connected); -} - -tcp_pcb* async_tcp_listen_with_backlog(struct tcp_pcb* pcb, u8_t backlog) -{ - if(!_start_async_task()) { - return nullptr; - } - - return _tcp_listen_with_backlog(pcb, backlog); -} - -err_t async_tcp_bind(struct tcp_pcb* pcb, const ip_addr_t* ipaddr, u16_t port) -{ - if(!_start_async_task()) { - return ERR_ABRT; - } - - return _tcp_bind(pcb, ipaddr, port); -} - -void async_tcp_accept(struct tcp_pcb* pcb, tcp_accept_fn callback) -{ - if(pcb == nullptr) { - return; - } - - tcp_api_arg_t* arg = reinterpret_cast(pcb->callback_arg); - if(arg == nullptr) { - debug_d("Set to direct accept callback: Pcb: 0x%08x, Arg: 0x%08x, State: %d.", pcb, pcb->callback_arg, pcb->state); - tcp_accept(pcb, callback); - return; - } - - debug_d("Accept: Pcb: 0x%08x, Callback: 0x%08x", pcb, callback); - - arg->accept.callback = callback; - tcp_accept(pcb, _tcp_accept); -} - -err_t async_tcp_write(struct tcp_pcb* pcb, const void* dataptr, u16_t len, u8_t apiflags) -{ - return _tcp_write(pcb, (const char*)dataptr, len, apiflags); -} - -void async_tcp_recved(struct tcp_pcb* pcb, u16_t len) -{ - _tcp_recved(pcb, len); -} - -err_t async_tcp_output(struct tcp_pcb* pcb) -{ - return _tcp_output(pcb); -} - -void async_tcp_abort(struct tcp_pcb* pcb) -{ - _tcp_abort(pcb); -} - -err_t async_tcp_close(struct tcp_pcb* pcb) -{ - return _tcp_close(pcb); -} - -void async_tcp_recv(struct tcp_pcb* pcb, tcp_recv_fn callback) -{ - if(pcb == nullptr) { - return; - } - - tcp_api_arg_t* arg = reinterpret_cast(pcb->callback_arg); - if(arg == nullptr) { - debug_d("Set to direct recv callback: Pcb: 0x%08x, Arg: 0x%08x, State: %d.", pcb, pcb->callback_arg, pcb->state); - tcp_recv(pcb, callback); - return; - } - - debug_d("Receive: Pcb: 0x%08x, Callback: 0x%08x", pcb, callback); - - arg->receive.callback = callback; - tcp_recv(pcb, _tcp_recv); -} - -void async_tcp_sent(struct tcp_pcb* pcb, tcp_sent_fn callback) -{ - if(pcb == nullptr) { - return; - } - - tcp_api_arg_t* arg = reinterpret_cast(pcb->callback_arg); - if(arg == nullptr) { - debug_d("Set to direct sent callback: Pcb: 0x%08x, Arg: 0x%08x, State: %d.", pcb, pcb->callback_arg, pcb->state); - tcp_sent(pcb, callback); - return; - } - - debug_d("Sent: Pcb: 0x%08x, Callback: 0x%08x", pcb, callback); - - arg->sent.callback = callback; - tcp_sent(pcb, _tcp_sent); -} - -void async_tcp_poll(struct tcp_pcb* pcb, tcp_poll_fn callback, u8_t interval) -{ - if(pcb == nullptr) { - return; - } - - tcp_api_arg_t* arg = reinterpret_cast(pcb->callback_arg); - if(arg == nullptr) { - debug_d("Set to direct poll callback: Pcb: 0x%08x, Arg: 0x%08x, State: %d.", pcb, pcb->callback_arg, pcb->state); - tcp_poll(pcb, callback, interval); - return; - } - - debug_d("Poll: Pcb: 0x%08x, Callback: 0x%08x, Interval: %d", pcb, callback, interval); - - arg->poll.callback = callback; - tcp_poll(pcb, _tcp_poll, interval); -} - -void async_tcp_err(struct tcp_pcb* pcb, tcp_err_fn callback) -{ - if(pcb == nullptr) { - return; - } - - tcp_api_arg_t* arg = reinterpret_cast(pcb->callback_arg); - if(arg == nullptr) { - debug_d("Set to direct error callback: Pcb: 0x%08x, Arg: 0x%08x, State: %d.", pcb, pcb->callback_arg, pcb->state); - tcp_err(pcb, callback); - return; - } - - debug_d("Error: Pcb: 0x%08x, Callback: 0x%08x", pcb, callback); - - arg->error.callback = callback; - tcp_err(pcb, _tcp_error); -} - -err_t async_dns_gethostbyname(const char* hostname, ip_addr_t* addr, dns_found_callback found, void* callback_arg) -{ - DnsLookup* dnsLookup = reinterpret_cast(callback_arg); - if(dnsLookup == nullptr) { - // This should not happen - return ERR_ABRT; - } - - tcp_api_arg_t* arg = new tcp_api_arg_t(); - if(arg == nullptr) { - // This should not happen - return ERR_ABRT; - } - - if(!_start_async_task()) { - delete arg; - return ERR_ABRT; - } - - arg->dns.callback = found; - arg->dns.lookup = dnsLookup; - return dns_gethostbyname(hostname, addr, _tcp_dns_found, arg); -} - -#endif // 0 diff --git a/Sming/Components/Network/Arch/Esp32/Platform/LwipAdapter.h b/Sming/Components/Network/Arch/Esp32/Platform/LwipAdapter.h deleted file mode 100644 index c891b95123..0000000000 --- a/Sming/Components/Network/Arch/Esp32/Platform/LwipAdapter.h +++ /dev/null @@ -1,71 +0,0 @@ -/** - * LWIP adapter compatibility - */ -#pragma once - -/** - A big thank you to Hristo Gochkov and his Asynchronous TCP library - Big chunks of the code are inspired from this project. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include - -#if 0 - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#include "espinc/lwip_includes.h" - -#ifndef DEBUG_TCP_EXTENDED -#define DEBUG_TCP_EXTENDED 1 -#endif - -// Settings -tcp_pcb* async_tcp_new(); -void async_tcp_arg(struct tcp_pcb* pcb, void* arg); - -// Actions -err_t async_tcp_connect(struct tcp_pcb* pcb, const ip_addr_t* ipaddr, u16_t port, tcp_connected_fn callback); -tcp_pcb* async_tcp_listen_with_backlog(struct tcp_pcb* pcb, u8_t backlog); -void async_tcp_accept(struct tcp_pcb* pcb, tcp_accept_fn callback); -err_t async_tcp_bind(struct tcp_pcb* pcb, const ip_addr_t* ipaddr, u16_t port); -err_t async_tcp_write(struct tcp_pcb* pcb, const void* dataptr, u16_t len, u8_t apiflags); -void async_tcp_recved(struct tcp_pcb* pcb, u16_t len); -err_t async_tcp_output(struct tcp_pcb* pcb); -void async_tcp_abort(struct tcp_pcb* pcb); -err_t async_tcp_close(struct tcp_pcb* pcb); - -// Event callbacks -void async_tcp_recv(struct tcp_pcb* pcb, tcp_recv_fn callback); -void async_tcp_sent(struct tcp_pcb* pcb, tcp_sent_fn callback); -void async_tcp_poll(struct tcp_pcb* pcb, tcp_poll_fn callback, u8_t interval); -void async_tcp_err(struct tcp_pcb* pcb, tcp_err_fn callback); - -// DNS callback -err_t async_dns_gethostbyname(const char* hostname, ip_addr_t* addr, dns_found_callback found, void* callback_arg); - -#ifdef __cplusplus -} -#endif - -#endif // 0 diff --git a/Sming/Components/arch_driver/src/SerialBuffer.cpp b/Sming/Components/arch_driver/src/SerialBuffer.cpp index b567fd4fc4..078b2cc896 100644 --- a/Sming/Components/arch_driver/src/SerialBuffer.cpp +++ b/Sming/Components/arch_driver/src/SerialBuffer.cpp @@ -12,6 +12,10 @@ #include "include/driver/SerialBuffer.h" +#ifdef ARCH_ESP32 +#include +#endif + /** @brief find a character in the buffer * @param c * @retval int position relative to current read pointer, -1 if character not found @@ -46,7 +50,12 @@ size_t SerialBuffer::resize(size_t newSize) return size; } +#ifdef ARCH_ESP32 + // Avoid allocating in SPIRAM + auto new_buf = static_cast(heap_caps_malloc(newSize, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL)); +#else auto new_buf = new char[newSize]; +#endif if(new_buf == nullptr) { return size; } diff --git a/Sming/Components/esptool/component.mk b/Sming/Components/esptool/component.mk index 2a4cf0bbc0..3c936f186f 100644 --- a/Sming/Components/esptool/component.mk +++ b/Sming/Components/esptool/component.mk @@ -22,7 +22,7 @@ $(ESPTOOL): $(ESPTOOL_SUBMODULE)/.submodule ifeq ($(SMING_ARCH),Esp8266) ESP_CHIP := esp8266 else ifeq ($(SMING_ARCH),Esp32) -ESP_CHIP := esp32 +ESP_CHIP := $(ESP_VARIANT) else ifeq ($(MAKE_DOCS),) $(error esptool unsupported arch: $(SMING_ARCH)) endif diff --git a/Sming/Components/terminal/component.mk b/Sming/Components/terminal/component.mk index 5529f916ee..959cc6f2c3 100644 --- a/Sming/Components/terminal/component.mk +++ b/Sming/Components/terminal/component.mk @@ -15,7 +15,7 @@ endif # Universal python terminal application CACHE_VARS += COM_OPTS KILL_TERM TERMINAL -COM_OPTS ?= --raw --encoding ascii +COM_OPTS ?= --raw --encoding ascii --rts 0 --dtr 0 KILL_TERM ?= pkill -9 -f "$(COM_PORT) $(COM_SPEED_SERIAL)" || exit 0 ifdef WSL_ROOT TERMINAL ?= powershell.exe -Command "python -m serial.tools.miniterm $(COM_OPTS) $(COM_PORT) $(COM_SPEED_SERIAL)" diff --git a/Sming/Components/Network/src/Data/Stream/XorOutputStream.h b/Sming/Core/Data/Stream/XorOutputStream.h similarity index 100% rename from Sming/Components/Network/src/Data/Stream/XorOutputStream.h rename to Sming/Core/Data/Stream/XorOutputStream.h diff --git a/Sming/Core/HardwareSerial.h b/Sming/Core/HardwareSerial.h index b689452648..c2fe0cc17c 100644 --- a/Sming/Core/HardwareSerial.h +++ b/Sming/Core/HardwareSerial.h @@ -26,6 +26,8 @@ #define NUMBER_UARTS UART_COUNT ///< Quantity of UARTs available +#define SERIAL_PIN_DEFAULT UART_PIN_DEFAULT + class HardwareSerial; /** @brief Delegate callback type for serial data reception @@ -132,7 +134,7 @@ class HardwareSerial : public ReadWriteStream */ void begin(uint32_t baud = 9600) { - begin(baud, SERIAL_8N1, SERIAL_FULL, 1); + begin(baud, SERIAL_8N1, SERIAL_FULL, SERIAL_PIN_DEFAULT); } /** @@ -145,7 +147,7 @@ class HardwareSerial : public ReadWriteStream */ void begin(uint32_t baud, SerialConfig config) { - begin(baud, config, SERIAL_FULL, 1); + begin(baud, config, SERIAL_FULL, SERIAL_PIN_DEFAULT); } /** @@ -170,7 +172,7 @@ class HardwareSerial : public ReadWriteStream * @param txPin Can specify alternate pin for TX * @param rxPin */ - void begin(uint32_t baud, SerialConfig config, SerialMode mode, uint8_t txPin, uint8_t rxPin = UART_PIN_DEFAULT); + void begin(uint32_t baud, SerialConfig config, SerialMode mode, uint8_t txPin, uint8_t rxPin = SERIAL_PIN_DEFAULT); /** * @brief De-inits the current UART if it is already used diff --git a/Sming/Libraries/LittleFS b/Sming/Libraries/LittleFS index 21f3969a64..e02efce58e 160000 --- a/Sming/Libraries/LittleFS +++ b/Sming/Libraries/LittleFS @@ -1 +1 @@ -Subproject commit 21f3969a6407771d8823e4eac3a3b266d1772ba6 +Subproject commit e02efce58e6996601255e59c3c688d583f1b843d diff --git a/Sming/Libraries/SmingTest b/Sming/Libraries/SmingTest index 36913db2ce..29ca79605d 160000 --- a/Sming/Libraries/SmingTest +++ b/Sming/Libraries/SmingTest @@ -1 +1 @@ -Subproject commit 36913db2ce3a5be82abb90d2140988307adfc38d +Subproject commit 29ca79605d2ec29c06c71ce23583ee74fc16e879 diff --git a/Sming/Platform/Clocks.h b/Sming/Platform/Clocks.h index 6d9b71c40d..3e7ad28f8b 100644 --- a/Sming/Platform/Clocks.h +++ b/Sming/Platform/Clocks.h @@ -95,6 +95,11 @@ struct CpuCycleClock { return cpuFreq == eCF_160MHz; } + + static constexpr CpuFrequency cpuFrequency() + { + return cpuFreq; + } }; #include_next diff --git a/Sming/System/include/gdb/gdb_hooks.h b/Sming/System/include/gdb/gdb_hooks.h index 5a0c28adf4..98bc1fc21e 100644 --- a/Sming/System/include/gdb/gdb_hooks.h +++ b/Sming/System/include/gdb/gdb_hooks.h @@ -55,8 +55,10 @@ void gdb_enable(bool state); #ifdef ENABLE_GDB #ifdef ARCH_HOST #define gdb_do_break() __asm__("int $0x03") -#else +#elif defined(ARCH_ESP8266) #define gdb_do_break() __asm__("break 0,0") +#else +#define gdb_do_break() cpu_hal_break() #endif #else #define gdb_do_break() \ diff --git a/Sming/build.mk b/Sming/build.mk index 151f1411b2..0d3a480527 100644 --- a/Sming/build.mk +++ b/Sming/build.mk @@ -87,7 +87,7 @@ endif export SMING_HOME export COMPILE := gcc -DEBUG_VARS += ARCH_BASE USER_LIBDIR OUT_BASE BUILD_BASE FW_BASE TOOLS_BASE +DEBUG_VARS += ARCH_BASE ARCH_BASE := $(SMING_HOME)/Arch/$(SMING_ARCH) ARCH_SYS = $(ARCH_BASE)/System @@ -95,11 +95,6 @@ ARCH_CORE = $(ARCH_BASE)/Core ARCH_TOOLS = $(ARCH_BASE)/Tools ARCH_COMPONENTS = $(ARCH_BASE)/Components -OUT_BASE := out/$(SMING_ARCH)/$(BUILD_TYPE) -BUILD_BASE = $(OUT_BASE)/build -FW_BASE = $(OUT_BASE)/firmware -TOOLS_BASE = $(SMING_HOME)/$(OUT_BASE)/tools -USER_LIBDIR = $(SMING_HOME)/$(OUT_BASE)/lib # Git command DEBUG_VARS += GIT @@ -194,8 +189,6 @@ endif include $(ARCH_BASE)/build.mk -DEBUG_VARS += ESP_VARIANT - # Detect compiler version DEBUG_VARS += GCC_VERSION GCC_VERSION := $(shell $(CC) -dumpversion) @@ -223,6 +216,20 @@ $(info Instructions for upgrading your compiler can be found here: $(GCC_UPGRADE endif endif +DEBUG_VARS += USER_LIBDIR OUT_BASE BUILD_BASE FW_BASE TOOLS_BASE SMING_ARCH_FULL + +ifdef ESP_VARIANT +SMING_ARCH_FULL := $(SMING_ARCH)/$(ESP_VARIANT) +else +SMING_ARCH_FULL := $(SMING_ARCH) +endif + +OUT_BASE := out/$(SMING_ARCH_FULL)/$(BUILD_TYPE) +BUILD_BASE = $(OUT_BASE)/build +FW_BASE = $(OUT_BASE)/firmware +TOOLS_BASE = $(SMING_HOME)/$(OUT_BASE)/tools +USER_LIBDIR = $(SMING_HOME)/$(OUT_BASE)/lib + # Component (user) libraries have a special prefix so linker script can identify them CLIB_PREFIX := clib- diff --git a/Sming/project.mk b/Sming/project.mk index 2da18baf55..828ef31c58 100644 --- a/Sming/project.mk +++ b/Sming/project.mk @@ -25,6 +25,9 @@ all: checkdirs submodules ##(default) Build all Component libraries BUILD_TYPE_FILE := out/build-type.mk -include $(BUILD_TYPE_FILE) +BUILD_SUBTYPE_FILE = out/$(SMING_ARCH)/build-subtype.mk +-include $(BUILD_SUBTYPE_FILE) + # include $(SMING_HOME)/build.mk @@ -59,7 +62,7 @@ export PROJECT_DIR ifeq ($(MAKELEVEL),0) $(info ) -$(info $(notdir $(PROJECT_DIR)): Invoking '$(MAKECMDGOALS)' for $(SMING_ARCH).$(ESP_VARIANT) ($(BUILD_TYPE)) architecture) +$(info $(notdir $(PROJECT_DIR)): Invoking '$(MAKECMDGOALS)' for $(SMING_ARCH_FULL) ($(BUILD_TYPE)) architecture) endif # CFLAGS used for application and any custom targets @@ -546,14 +549,16 @@ otaserver: all ##Launch a simple python HTTP server for testing OTA updates $(Q) cd $(FW_BASE) && $(PYTHON) -m http.server $(SERVER_OTA_PORT) -# +# Serial redirector to support GDB +TCP_SERIAL_REDIRECT = $(SMING_HOME)/../Tools/tcp_serial_redirect.py $(COM_PORT) $(COM_SPEED_SERIAL) --rts 0 --dtr 0 + .PHONY: tcp-serial-redirect tcp-serial-redirect: ##Redirect COM port to TCP port $(info Starting serial redirector) ifdef WSL_ROOT - $(Q) cmd.exe /c start /MIN python3 $(WSL_ROOT)/$(SMING_HOME)/../Tools/tcp_serial_redirect.py $(COM_PORT) $(COM_SPEED_SERIAL) + $(Q) cmd.exe /c start /MIN python3 $(WSL_ROOT)/$(TCP_SERIAL_REDIRECT) else - $(Q) gnome-terminal -- bash -c "$(PYTHON) $(SMING_HOME)/../Tools/tcp_serial_redirect.py $(COM_PORT) $(COM_SPEED_SERIAL)" + $(Q) gnome-terminal -- bash -c "$(PYTHON) $(TCP_SERIAL_REDIRECT)" endif @@ -647,7 +652,8 @@ $(shell mkdir -p $(dir $1); endef # Update build type cache -$(eval $(call WriteCacheValues,$(BUILD_TYPE_FILE),SMING_ARCH ESP_VARIANT SMING_RELEASE STRICT)) +$(eval $(call WriteCacheValues,$(BUILD_TYPE_FILE),SMING_ARCH SMING_RELEASE STRICT)) +$(eval $(call WriteCacheValues,$(BUILD_SUBTYPE_FILE),ESP_VARIANT)) # Update config cache file # We store the list of variable names to ensure that any not actively in use don't get lost diff --git a/docs/source/arch/esp32/debugging/index.rst b/docs/source/arch/esp32/debugging/index.rst index 94f909b367..b682dd714e 100644 --- a/docs/source/arch/esp32/debugging/index.rst +++ b/docs/source/arch/esp32/debugging/index.rst @@ -1,9 +1,22 @@ Debugging on ESP32 ================== +Serial debugging +---------------- + +If an exception occurs in debug builds then a prompt will be printed to the serial terminal +such as ``Entering gdb stub``. + +As with the ESP8266, if such an exception occurs you can stop the serial debug terminal and type ``make gdb``. + +More advanced debugging is available via JTAG if you have the appropriate tools. + +See https://docs.espressif.com/projects/esp-idf/en/release-v4.3/esp32/api-guides/fatal-errors.html for further details. + Required tools and hardware --------------------------- + A debugger and a JTAG hardware are required. The debugger is part of the provided toolchain. Make sure that you have the following executable in your PATH:: @@ -82,11 +95,11 @@ If you want to debug your application and the Sming Framework code make sure to (re)compile it with :envvar:`ENABLE_GDB` =1 directive:: cd $SMING_HOME/../samples/Basic_Blink - make dist-clean + make clean components-clean make ENABLE_GDB=1 The commands above will re-compile Sming with debug symbols and -optimizations for debugging. These commands need to be executed once. +optimizations for debugging. Application ~~~~~~~~~~~ diff --git a/docs/source/information/multitasking.rst b/docs/source/information/multitasking.rst index b7c5bcc68d..4220613862 100644 --- a/docs/source/information/multitasking.rst +++ b/docs/source/information/multitasking.rst @@ -54,6 +54,9 @@ connections and poor responsiveness. In extreme cases, the system will reset as via *Watchdog Timer*; If it didn't do this, the device would remain unresponsive until physically reset, which is generally a bad thing for an embedded device! +Note that whilst the ESP32 implementation uses the ESP IDF framework based on FreeRTOS, which is a pre-emptive OS, +the programming model for Sming is the same. + .. attention:: Although there are functions available to manually reset watchdog timers, you should endeavour to avoid diff --git a/samples/Basic_Blink/README.rst b/samples/Basic_Blink/README.rst index 81c1fa1a8a..62967a3a06 100644 --- a/samples/Basic_Blink/README.rst +++ b/samples/Basic_Blink/README.rst @@ -1,9 +1,18 @@ Basic Blink =========== -Simple blink example. We use Timer instead of a loop because we want to allow WiFi communications to work in the background. +Simple blink example to confirm that the basic build system is working with your system. + +We use Timer instead of a loop because we want to allow WiFi communications to work in the background. +See :doc:`/information/multitasking`. + +The LED on many development boards is connected to GPIO2, so this is the default. + +If you get no response then check the documentation or schematic as your system +may differ and change the LED_PIN definition accordingly. + +For example, the NodeMCU ESP-C3 kits have an RGB LED connected to GPIO 3, 4 & 5. + .. image:: blink.jpg :height: 192px - - \ No newline at end of file diff --git a/samples/Basic_Serial/app/application.cpp b/samples/Basic_Serial/app/application.cpp index 02548412d1..f580e081da 100644 --- a/samples/Basic_Serial/app/application.cpp +++ b/samples/Basic_Serial/app/application.cpp @@ -12,18 +12,12 @@ struct SerialPins { SerialPins serialPins[2]{ { - UART_PIN_DEFAULT, - UART_PIN_DEFAULT, + SERIAL_PIN_DEFAULT, + SERIAL_PIN_DEFAULT, }, { -#ifdef ESP32 - // Default pins are occupied by flash lines - 17, - 16, -#else - UART_PIN_DEFAULT, - UART_PIN_DEFAULT, -#endif + SERIAL_PIN_DEFAULT, + SERIAL_PIN_DEFAULT, }, }; diff --git a/tests/HostTests/modules/HttpRequest.cpp b/tests/HostTests/Arch/Host/HttpRequest.cpp similarity index 97% rename from tests/HostTests/modules/HttpRequest.cpp rename to tests/HostTests/Arch/Host/HttpRequest.cpp index bf061a3b36..04123022d3 100644 --- a/tests/HostTests/modules/HttpRequest.cpp +++ b/tests/HostTests/Arch/Host/HttpRequest.cpp @@ -109,8 +109,5 @@ class HttpRequestTest : public TestGroup void REGISTER_TEST(HttpRequest) { - // Currently only supported for Host CI -#if defined(ARCH_HOST) registerGroup(); -#endif } diff --git a/tests/HostTests/modules/TcpClient.cpp b/tests/HostTests/Arch/Host/TcpClient.cpp similarity index 98% rename from tests/HostTests/modules/TcpClient.cpp rename to tests/HostTests/Arch/Host/TcpClient.cpp index e22d02391e..0a9a9383ef 100644 --- a/tests/HostTests/modules/TcpClient.cpp +++ b/tests/HostTests/Arch/Host/TcpClient.cpp @@ -98,7 +98,5 @@ class TcpClientTest : public TestGroup void REGISTER_TEST(TcpClient) { -#ifdef ARCH_HOST registerGroup(); -#endif } diff --git a/tests/HostTests/include/modules.h b/tests/HostTests/include/modules.h index c1d8ec57d8..676fea8fc8 100644 --- a/tests/HostTests/include/modules.h +++ b/tests/HostTests/include/modules.h @@ -2,7 +2,10 @@ // Architecture-specific test modules #ifdef ARCH_HOST -#define ARCH_TEST_MAP(XX) XX(Hosted) +#define ARCH_TEST_MAP(XX) \ + XX(Hosted) \ + XX(HttpRequest) \ + XX(TcpClient) #else #define ARCH_TEST_MAP(XX) #endif @@ -33,6 +36,4 @@ XX(Rational) \ XX(Clocks) \ XX(Timers) \ - XX(HttpRequest) \ - XX(TcpClient) \ ARCH_TEST_MAP(XX) diff --git a/tests/HostTests/modules/Clocks.cpp b/tests/HostTests/modules/Clocks.cpp index 8987fbec0e..a1d251483a 100644 --- a/tests/HostTests/modules/Clocks.cpp +++ b/tests/HostTests/modules/Clocks.cpp @@ -23,12 +23,6 @@ template class ClockTestTemplate : public TestG void execute() override { - if(Clock::frequency() == 160000000) { - System.setCpuFrequency(eCF_160MHz); - } else { - System.setCpuFrequency(eCF_80MHz); - } - printLimits(); for(unsigned i = 0; i < 2000; ++i) { @@ -67,10 +61,11 @@ template class ClockTestTemplate : public TestG this->timeunit = unit; - noInterrupts(); - + // valueIsTime = true; - this->value = value % (TimeSource::maxCalcTime() + 1); + this->value = value % TimeSource::maxCalcTime(); + + noInterrupts(); refCycles.start(); ref = timeToTicksRef(); refCycles.update(); @@ -78,6 +73,7 @@ template class ClockTestTemplate : public TestG calcCycles.start(); calc = TimeSource::timeToTicks(this->value); calcCycles.update(); + interrupts(); if(calc != ref) { calc = TimeSource::timeToTicks(this->value); @@ -85,8 +81,11 @@ template class ClockTestTemplate : public TestG compare(); + // valueIsTime = false; - this->value = value % (TimeSource::maxCalcTicks() + 1); + this->value = value % TimeSource::maxCalcTicks(); + + noInterrupts(); refCycles.start(); ref = ticksToTimeRef(); refCycles.update(); @@ -94,9 +93,8 @@ template class ClockTestTemplate : public TestG calcCycles.start(); calc = TimeSource::ticksToTime(this->value); calcCycles.update(); - compare(); - interrupts(); + compare(); } void printStats() @@ -240,6 +238,23 @@ template class ClockTestTemplate : public TestG CpuCycleTimes calcCycles; }; +template class CpuClockTestTemplate : public ClockTestTemplate +{ +public: + using ClockTestTemplate::ClockTestTemplate; + + void execute() override + { + uint32_t curFreq = system_get_cpu_freq(); + System.setCpuFrequency(Clock::cpuFrequency()); + + // delay(100); + debug_i("CPU freq: %u -> %u MHz", curFreq, system_get_cpu_freq()); + ClockTestTemplate::execute(); + System.setCpuFrequency(CpuCycleClockNormal::cpuFrequency()); + } +}; + /* * Why use a Polled timer? Comparison versus hand-coded loops. */ @@ -463,6 +478,9 @@ void REGISTER_TEST(Clocks) registerGroup>(); - registerGroup>(); - registerGroup>(); + if(CpuCycleClockSlow::cpuFrequency() != CpuCycleClockNormal::cpuFrequency()) { + registerGroup>(); + } + registerGroup>(); + registerGroup>(); } diff --git a/tests/HostTests/modules/Libc.cpp b/tests/HostTests/modules/Libc.cpp index dacdcc3459..2ae0596fa1 100644 --- a/tests/HostTests/modules/Libc.cpp +++ b/tests/HostTests/modules/Libc.cpp @@ -39,25 +39,18 @@ class LibcTest : public TestGroup { using namespace libc_initorder; debug_i("order: %d, %d, %d, %d", a1.order, a2.order, a3.order, a4.order); -#ifdef ARCH_ESP32 - /* - * Bit odd this one. There's even a test case in components/cxx/test/test_initialization.cpp - * which is essentially identical to this test. - * - * This order isn't technically wrong since our init_priority attributes are being honoured. - * - * TODO: What going on? - */ - REQUIRE(a1.order == 3); - REQUIRE(a2.order == 4); - REQUIRE(a3.order == 1); - REQUIRE(a4.order == 2); -#else - REQUIRE(a1.order == 1); - REQUIRE(a2.order == 2); - REQUIRE(a3.order == 3); - REQUIRE(a4.order == 4); -#endif + // Compilers may legitimately order these in two different ways + if(a1.order == 3) { + REQUIRE(a1.order == 3); + REQUIRE(a2.order == 4); + REQUIRE(a3.order == 1); + REQUIRE(a4.order == 2); + } else { + REQUIRE(a1.order == 1); + REQUIRE(a2.order == 2); + REQUIRE(a3.order == 3); + REQUIRE(a4.order == 4); + } } #ifdef ARCH_ESP8266 diff --git a/tests/HostTests/modules/Stream.cpp b/tests/HostTests/modules/Stream.cpp index 2a1194c641..d77afc8f8e 100644 --- a/tests/HostTests/modules/Stream.cpp +++ b/tests/HostTests/modules/Stream.cpp @@ -168,7 +168,14 @@ class StreamTest : public TestGroup debug_hex(DBG, "Text", unmaskedString.c_str(), unmaskedString.length()); } + { + // STL may perform one-time memory allocation for mutexes, etc. + std::shared_ptr data(new char[18]); + SharedMemoryStream(data, 18); + } + auto memStart = MallocCount::getCurrent(); + // auto memStart = system_get_free_heap_size(); TEST_CASE("SharedMemoryStream") { @@ -203,8 +210,9 @@ class StreamTest : public TestGroup REQUIRE(data.use_count() == 1); } - debug_i("memStart = %d, now mem = %d", memStart, MallocCount::getCurrent()); - REQUIRE(memStart == MallocCount::getCurrent()); + auto memNow = MallocCount::getCurrent(); + // auto memNow = system_get_free_heap_size(); + REQUIRE_EQ(memStart, memNow); } private: