diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d28d7ac0920..e88a8c61a9e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,10 +20,10 @@ repos: additional_dependencies: - tomli - repo: https://github.com/pre-commit/mirrors-clang-format - rev: 'v15.0.7' + rev: v15.0.7 hooks: - id: clang-format - files: \.((((c|C)(c|pp|xx|\+\+)?$)|((h|H)h?(pp|xx|\+\+)?$))|(ino))$ + types_or: [c, c++] - repo: https://github.com/psf/black-pre-commit-mirror rev: 22.10.0 hooks: @@ -34,7 +34,7 @@ repos: rev: 7.0.0 hooks: - id: flake8 - files: \.(((py)(w|o)?$))$ + types_or: [python] additional_dependencies: - flake8-bugbear - flake8-comprehensions diff --git a/cores/esp32/dummy4.c b/cores/esp32/dummy4.c new file mode 100644 index 00000000000..b22267fbc68 --- /dev/null +++ b/cores/esp32/dummy4.c @@ -0,0 +1,1148 @@ +// Copyright 2015-2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "esp32-hal-uart.h" + +#if SOC_UART_SUPPORTED +#include "esp32-hal.h" +#include "esp32-hal-periman.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" + +#include "driver/uart.h" +#include "hal/uart_ll.h" +#include "soc/soc_caps.h" +#include "soc/uart_struct.h" +#include "soc/uart_periph.h" +#include "rom/ets_sys.h" +#include "rom/gpio.h" + +#include "driver/gpio.h" +#include "hal/gpio_hal.h" +#include "esp_rom_gpio.h" + +static int s_uart_debug_nr = 0; // UART number for debug output + +struct uart_struct_t { + +#if !CONFIG_DISABLE_HAL_LOCKS + SemaphoreHandle_t lock; // UART lock +#endif + + uint8_t num; // UART number for IDF driver API + bool has_peek; // flag to indicate that there is a peek byte pending to be read + uint8_t peek_byte; // peek byte that has been read but not consumed + QueueHandle_t uart_event_queue; // export it by some uartGetEventQueue() function + // configuration data:: Arduino API tipical data + int8_t _rxPin, _txPin, _ctsPin, _rtsPin; // UART GPIOs + uint32_t _baudrate, _config; // UART baudrate and config + // UART ESP32 specific data + uint16_t _rx_buffer_size, _tx_buffer_size; // UART RX and TX buffer sizes + bool _inverted; // UART inverted signal + uint8_t _rxfifo_full_thrhd; // UART RX FIFO full threshold +}; + +#if CONFIG_DISABLE_HAL_LOCKS + +#define UART_MUTEX_LOCK() +#define UART_MUTEX_UNLOCK() + +static uart_t _uart_bus_array[] = { + {0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, +#if SOC_UART_NUM > 1 + {1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, +#endif +#if SOC_UART_NUM > 2 + {2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, +#endif +}; + +#else + +#define UART_MUTEX_LOCK() if(uart->lock != NULL) do {} while (xSemaphoreTake(uart->lock, portMAX_DELAY) != pdPASS) +#define UART_MUTEX_UNLOCK() if(uart->lock != NULL) xSemaphoreGive(uart->lock) + +static uart_t _uart_bus_array[] = { + {NULL, 0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, +#if SOC_UART_NUM > 1 + {NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, +#endif +#if SOC_UART_NUM > 2 + {NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0}, +#endif +}; + +#endif + +// Negative Pin Number will keep it unmodified, thus this function can detach individual pins +// This function will also unset the pins in the Peripheral Manager and set the pin to -1 after detaching +static bool _uartDetachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) +{ + if(uart_num >= SOC_UART_NUM) { + log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); + return false; + } + // get UART information + uart_t* uart = &_uart_bus_array[uart_num]; + bool retCode = true; + //log_v("detaching UART%d pins: prev,pin RX(%d,%d) TX(%d,%d) CTS(%d,%d) RTS(%d,%d)", uart_num, + // uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10); + + // detaches pins and sets Peripheral Manager and UART information + if (rxPin >= 0 && uart->_rxPin == rxPin && perimanGetPinBusType(rxPin) == ESP32_BUS_TYPE_UART_RX) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rxPin], PIN_FUNC_GPIO); + // avoids causing BREAK in the UART line + if (uart->_inverted) { + esp_rom_gpio_connect_in_signal(GPIO_FUNC_IN_LOW, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), false); + } else { + esp_rom_gpio_connect_in_signal(GPIO_FUNC_IN_HIGH, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), false); + } + uart->_rxPin = -1; // -1 means unassigned/detached + if (!perimanClearPinBus(rxPin)) { + retCode = false; + log_e("UART%d failed to detach RX pin %d", uart_num, rxPin); + } + } + if (txPin >= 0 && uart->_txPin == txPin && perimanGetPinBusType(txPin) == ESP32_BUS_TYPE_UART_TX) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[txPin], PIN_FUNC_GPIO); + esp_rom_gpio_connect_out_signal(txPin, SIG_GPIO_OUT_IDX, false, false); + uart->_txPin = -1; // -1 means unassigned/detached + if (!perimanClearPinBus(txPin)) { + retCode = false; + log_e("UART%d failed to detach TX pin %d", uart_num, txPin); + } + } + if (ctsPin >= 0 && uart->_ctsPin == ctsPin && perimanGetPinBusType(ctsPin) == ESP32_BUS_TYPE_UART_CTS) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[ctsPin], PIN_FUNC_GPIO); + esp_rom_gpio_connect_in_signal(GPIO_FUNC_IN_LOW, UART_PERIPH_SIGNAL(uart_num, SOC_UART_CTS_PIN_IDX), false); + uart->_ctsPin = -1; // -1 means unassigned/detached + if (!perimanClearPinBus(ctsPin)) { + retCode = false; + log_e("UART%d failed to detach CTS pin %d", uart_num, ctsPin); + } + } + if (rtsPin >= 0 && uart->_rtsPin == rtsPin && perimanGetPinBusType(rtsPin) == ESP32_BUS_TYPE_UART_RTS) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rtsPin], PIN_FUNC_GPIO); + esp_rom_gpio_connect_out_signal(rtsPin, SIG_GPIO_OUT_IDX, false, false); + uart->_rtsPin = -1; // -1 means unassigned/detached + if (!perimanClearPinBus(rtsPin)) { + retCode = false; + log_e("UART%d failed to detach RTS pin %d", uart_num, rtsPin); + } + } + return retCode; +} + +// Peripheral Manager detach callback for each specific UART PIN +static bool _uartDetachBus_RX(void *busptr) +{ + // sanity check - it should never happen + assert(busptr && "_uartDetachBus_RX bus NULL pointer."); + uart_t* bus = (uart_t*) busptr; + return _uartDetachPins(bus->num, bus->_rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); +} + +static bool _uartDetachBus_TX(void *busptr) +{ + // sanity check - it should never happen + assert(busptr && "_uartDetachBus_TX bus NULL pointer."); + uart_t* bus = (uart_t*) busptr; + return _uartDetachPins(bus->num, UART_PIN_NO_CHANGE, bus->_txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); +} + + +static bool _uartDetachBus_CTS(void *busptr) +{ + // sanity check - it should never happen + assert(busptr && "_uartDetachBus_CTS bus NULL pointer."); + uart_t* bus = (uart_t*) busptr; + return _uartDetachPins(bus->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, bus->_ctsPin, UART_PIN_NO_CHANGE); +} + +static bool _uartDetachBus_RTS(void *busptr) +{ + // sanity check - it should never happen + assert(busptr && "_uartDetachBus_RTS bus NULL pointer."); + uart_t* bus = (uart_t*) busptr; + return _uartDetachPins(bus->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, bus->_rtsPin); +} + +// Attach function for UART +// connects the IO Pad, set Paripheral Manager and internal UART structure data +static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) +{ + if(uart_num >= SOC_UART_NUM) { + log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); + return false; + } + // get UART information + uart_t* uart = &_uart_bus_array[uart_num]; + //log_v("attaching UART%d pins: prev,new RX(%d,%d) TX(%d,%d) CTS(%d,%d) RTS(%d,%d)", uart_num, + // uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10); + + + bool retCode = true; + if (rxPin >= 0) { + // forces a clean detaching from a previous peripheral + if (perimanGetPinBusType(rxPin) != ESP32_BUS_TYPE_INIT) perimanClearPinBus(rxPin); + // connect RX Pad + bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + if (ret) { + ret &= perimanSetPinBus(rxPin, ESP32_BUS_TYPE_UART_RX, (void *)uart, uart_num, -1); + if (ret) uart->_rxPin = rxPin; + } + if (!ret) { + log_e("UART%d failed to attach RX pin %d", uart_num, rxPin); + } + retCode &= ret; + } + if (txPin >= 0) { + // forces a clean detaching from a previous peripheral + if (perimanGetPinBusType(txPin) != ESP32_BUS_TYPE_INIT) perimanClearPinBus(txPin); + // connect TX Pad + bool ret = ESP_OK == uart_set_pin(uart->num, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + if (ret) { + ret &= perimanSetPinBus(txPin, ESP32_BUS_TYPE_UART_TX, (void *)uart, uart_num, -1); + if (ret) uart->_txPin = txPin; + } + if (!ret) { + log_e("UART%d failed to attach TX pin %d", uart_num, txPin); + } + retCode &= ret; + } + if (ctsPin >= 0) { + // forces a clean detaching from a previous peripheral + if (perimanGetPinBusType(ctsPin) != ESP32_BUS_TYPE_INIT) perimanClearPinBus(ctsPin); + // connect CTS Pad + bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, ctsPin); + if (ret) { + ret &= perimanSetPinBus(ctsPin, ESP32_BUS_TYPE_UART_CTS, (void *)uart, uart_num, -1); + if (ret) uart->_ctsPin = ctsPin; + } + if (!ret) { + log_e("UART%d failed to attach CTS pin %d", uart_num, ctsPin); + } + retCode &= ret; + } + if (rtsPin >= 0) { + // forces a clean detaching from a previous peripheral + if (perimanGetPinBusType(rtsPin) != ESP32_BUS_TYPE_INIT) perimanClearPinBus(rtsPin); + // connect RTS Pad + bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, rtsPin, UART_PIN_NO_CHANGE); + if (ret) { + ret &= perimanSetPinBus(rtsPin, ESP32_BUS_TYPE_UART_RTS, (void *)uart, uart_num, -1); + if (ret) uart->_rtsPin = rtsPin; + } + if (!ret) { + log_e("UART%d failed to attach RTS pin %d", uart_num, rtsPin); + } + retCode &= ret; + } + return retCode; +} + +// just helper functions +int8_t uart_get_RxPin(uint8_t uart_num) +{ + return _uart_bus_array[uart_num]._rxPin; +} + +int8_t uart_get_TxPin(uint8_t uart_num) +{ + return _uart_bus_array[uart_num]._txPin; +} + +void uart_init_PeriMan(void) +{ + // set Peripheral Manager deInit Callback for each UART pin + perimanSetBusDeinit(ESP32_BUS_TYPE_UART_RX, _uartDetachBus_RX); + perimanSetBusDeinit(ESP32_BUS_TYPE_UART_TX, _uartDetachBus_TX); + perimanSetBusDeinit(ESP32_BUS_TYPE_UART_CTS, _uartDetachBus_CTS); + perimanSetBusDeinit(ESP32_BUS_TYPE_UART_RTS, _uartDetachBus_RTS); +} + +// Routines that take care of UART events will be in the HardwareSerial Class code +void uartGetEventQueue(uart_t* uart, QueueHandle_t *q) +{ + // passing back NULL for the Queue pointer when UART is not initialized yet + *q = NULL; + if(uart == NULL) { + return; + } + *q = uart->uart_event_queue; + return; +} + +bool uartIsDriverInstalled(uart_t* uart) +{ + if(uart == NULL) { + return false; + } + + if (uart_is_driver_installed(uart->num)) { + return true; + } + return false; +} + +// Negative Pin Number will keep it unmodified, thus this function can set individual pins +// When pins are changed, it will detach the previous one +bool uartSetPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) +{ + if(uart_num >= SOC_UART_NUM) { + log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); + return false; + } + // get UART information + uart_t* uart = &_uart_bus_array[uart_num]; + + bool retCode = true; + UART_MUTEX_LOCK(); + + //log_v("setting UART%d pins: prev->new RX(%d->%d) TX(%d->%d) CTS(%d->%d) RTS(%d->%d)", uart_num, + // uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10); + + // First step: detachs all previous UART pins + bool rxPinChanged = rxPin >= 0 && rxPin != uart->_rxPin; + if (rxPinChanged) { + retCode &= _uartDetachPins(uart_num, uart->_rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + } + bool txPinChanged = txPin >= 0 && txPin != uart->_txPin; + if (txPinChanged) { + retCode &= _uartDetachPins(uart_num, UART_PIN_NO_CHANGE, uart->_txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + } + bool ctsPinChanged = ctsPin >= 0 && ctsPin != uart->_ctsPin; + if (ctsPinChanged) { + retCode &= _uartDetachPins(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, uart->_ctsPin, UART_PIN_NO_CHANGE); + } + bool rtsPinChanged = rtsPin >= 0 && rtsPin != uart->_rtsPin; + if (rtsPinChanged) { + retCode &= _uartDetachPins(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, uart->_rtsPin); + } + + // Second step: attach all UART new pins + if (rxPinChanged) { + retCode &= _uartAttachPins(uart_num, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + } + if (txPinChanged) { + retCode &= _uartAttachPins(uart_num, UART_PIN_NO_CHANGE, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + } + if (ctsPinChanged) { + retCode &= _uartAttachPins(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, ctsPin, UART_PIN_NO_CHANGE); + } + if (rtsPinChanged) { + retCode &= _uartAttachPins(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, rtsPin); + } + UART_MUTEX_UNLOCK(); + + if (!retCode) { + log_e("UART%d set pins failed.", uart_num); + } + return retCode; +} + +// +bool uartSetHwFlowCtrlMode(uart_t *uart, uart_hw_flowcontrol_t mode, uint8_t threshold) { + if(uart == NULL) { + return false; + } + // IDF will issue corresponding error message when mode or threshold are wrong and prevent crashing + // IDF will check (mode > HW_FLOWCTRL_CTS_RTS || threshold >= SOC_UART_FIFO_LEN) + UART_MUTEX_LOCK(); + bool retCode = (ESP_OK == uart_set_hw_flow_ctrl(uart->num, mode, threshold)); + UART_MUTEX_UNLOCK(); + return retCode; +} + +// This helper function will return true if a new IDF UART driver needs to be restarted and false if the current one can continue its execution +bool _testUartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t rx_buffer_size, uint16_t tx_buffer_size, bool inverted, uint8_t rxfifo_full_thrhd) +{ + if(uart_nr >= SOC_UART_NUM) { + return false; // no new driver has to be installed + } + uart_t* uart = &_uart_bus_array[uart_nr]; + // verify if is necessary to restart the UART driver + if (uart_is_driver_installed(uart_nr)) { + // some parameters can't be changed unless we end the UART driver + if ( uart->_rx_buffer_size != rx_buffer_size || uart->_tx_buffer_size != tx_buffer_size || uart->_inverted != inverted || uart->_rxfifo_full_thrhd != rxfifo_full_thrhd) { + return true; // the current IDF UART driver must be terminated and a new driver shall be installed + } else { + return false; // The current IDF UART driver can continue its execution + } + } else { + return true; // no IDF UART driver is running and a new driver shall be installed + } +} + +uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t rx_buffer_size, uint16_t tx_buffer_size, bool inverted, uint8_t rxfifo_full_thrhd) +{ + if(uart_nr >= SOC_UART_NUM) { + log_e("UART number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); + return NULL; // no new driver was installed + } + uart_t* uart = &_uart_bus_array[uart_nr]; + log_v("UART%d baud(%ld) Mode(%x) rxPin(%d) txPin(%d)", uart_nr, baudrate, config, rxPin, txPin); + +#if !CONFIG_DISABLE_HAL_LOCKS + if(uart->lock == NULL) { + uart->lock = xSemaphoreCreateMutex(); + if(uart->lock == NULL) { + log_e("HAL LOCK error."); + return NULL; // no new driver was installed + } + } +#endif + + if (uart_is_driver_installed(uart_nr)) { + log_v("UART%d Driver already installed.", uart_nr); + // some parameters can't be changed unless we end the UART driver + if ( uart->_rx_buffer_size != rx_buffer_size || uart->_tx_buffer_size != tx_buffer_size || uart->_inverted != inverted || uart->_rxfifo_full_thrhd != rxfifo_full_thrhd) { + log_v("UART%d changing buffer sizes or inverted signal or rxfifo_full_thrhd. IDF driver will be restarted", uart_nr); + uartEnd(uart_nr); + } else { + bool retCode = true; + UART_MUTEX_LOCK(); + //User may just want to change some parameters, such as baudrate, data length, parity, stop bits or pins + if (uart->_baudrate != baudrate) { + if (ESP_OK != uart_set_baudrate(uart_nr, baudrate)) { + log_e("UART%d changing baudrate failed.", uart_nr); + retCode = false; + } else { + log_v("UART%d changed baudrate to %d", uart_nr, baudrate); + uart->_baudrate = baudrate; + } + } + uart_word_length_t data_bits = (config & 0xc) >> 2; + uart_parity_t parity = config & 0x3; + uart_stop_bits_t stop_bits = (config & 0x30) >> 4; + if (retCode && (uart->_config & 0xc) >> 2 != data_bits) { + if (ESP_OK != uart_set_word_length(uart_nr, data_bits)) { + log_e("UART%d changing data length failed.", uart_nr); + retCode = false; + } else { + log_v("UART%d changed data length to %d", uart_nr, data_bits + 5); + } + } + if (retCode && (uart->_config & 0x3) != parity) { + if (ESP_OK != uart_set_parity(uart_nr, parity)) { + log_e("UART%d changing parity failed.", uart_nr); + retCode = false; + } else { + log_v("UART%d changed parity to %s", uart_nr, parity == 0 ? "NONE" : parity == 2 ? "EVEN" : "ODD"); + } + } + if (retCode && (uart->_config & 0xc30) >> 4 != stop_bits) { + if (ESP_OK != uart_set_stop_bits(uart_nr, stop_bits)) { + log_e("UART%d changing stop bits failed.", uart_nr); + retCode = false; + } else { + log_v("UART%d changed stop bits to %d", uart_nr, stop_bits == 3 ? 2 : 1); + } + } + if (retCode) uart->_config = config; + if (retCode && rxPin > 0 && uart->_rxPin != rxPin) { + retCode &= _uartDetachPins(uart_nr, uart->_rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + retCode &= _uartAttachPins(uart_nr, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + if (!retCode) { + log_e("UART%d changing RX pin failed.", uart_nr); + } else { + log_v("UART%d changed RX pin to %d", uart_nr, rxPin); + } + } + if (retCode && txPin > 0 && uart->_txPin != txPin) { + retCode &= _uartDetachPins(uart_nr, UART_PIN_NO_CHANGE, uart->_txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + retCode &= _uartAttachPins(uart_nr, UART_PIN_NO_CHANGE, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + if (!retCode) { + log_e("UART%d changing TX pin failed.", uart_nr); + } else { + log_v("UART%d changed TX pin to %d", uart_nr, txPin); + } + } + UART_MUTEX_UNLOCK(); + if (retCode) { + // UART driver was already working, just return the uart_t structure, syaing that no new driver was installed + return uart; + } + // if we reach this point, it means that we need to restart the UART driver + uartEnd(uart_nr); + } + } else { + log_v("UART%d not installed. Starting installation", uart_nr); + } + uart_config_t uart_config; + uart_config.data_bits = (config & 0xc) >> 2; + uart_config.parity = (config & 0x3); + uart_config.stop_bits = (config & 0x30) >> 4; + uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; + uart_config.rx_flow_ctrl_thresh = rxfifo_full_thrhd; + uart_config.baud_rate = baudrate; + // CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F40M for C2 -- CLK_PLL_F48M for H2 -- CLK_PLL_F80M for C6 + uart_config.source_clk = UART_SCLK_DEFAULT; + + UART_MUTEX_LOCK(); + bool retCode = ESP_OK == uart_driver_install(uart_nr, rx_buffer_size, tx_buffer_size, 20, &(uart->uart_event_queue), 0); + + if (retCode) retCode &= ESP_OK == uart_param_config(uart_nr, &uart_config); + + // Is it right or the idea is to swap rx and tx pins? + if (retCode && inverted) { + // invert signal for both Rx and Tx + retCode &= ESP_OK == uart_set_line_inverse(uart_nr, UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV); + } + + if (retCode) { + uart->_baudrate = baudrate; + uart->_config = config; + uart->_inverted = inverted; + uart->_rxfifo_full_thrhd = rxfifo_full_thrhd; + uart->_rx_buffer_size = rx_buffer_size; + uart->_tx_buffer_size = tx_buffer_size; + uart->_ctsPin = -1; + uart->_rtsPin = -1; + uart->has_peek = false; + uart->peek_byte = 0; + } + UART_MUTEX_UNLOCK(); + + // uartSetPins detaches previous pins if new ones are used over a previous begin() + if (retCode) retCode &= uartSetPins(uart_nr, rxPin, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + if (!retCode) { + uartEnd(uart_nr); + uart = NULL; + log_e("UART%d initialization error.", uart->num); + } else { + uartFlush(uart); + log_v("UART%d initialization done.", uart->num); + } + return uart; // a new driver was installed +} + +// This function code is under testing - for now just keep it here +void uartSetFastReading(uart_t* uart) +{ + if(uart == NULL) { + return; + } + + UART_MUTEX_LOCK(); + // override default RX IDF Driver Interrupt - no BREAK, PARITY or OVERFLOW + uart_intr_config_t uart_intr = { + .intr_enable_mask = UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT, // only these IRQs - no BREAK, PARITY or OVERFLOW + .rx_timeout_thresh = 1, + .txfifo_empty_intr_thresh = 10, + .rxfifo_full_thresh = 2, + }; + + ESP_ERROR_CHECK(uart_intr_config(uart->num, &uart_intr)); + UART_MUTEX_UNLOCK(); +} + + +bool uartSetRxTimeout(uart_t* uart, uint8_t numSymbTimeout) +{ + if(uart == NULL) { + return false; + } + + UART_MUTEX_LOCK(); + bool retCode = (ESP_OK == uart_set_rx_timeout(uart->num, numSymbTimeout)); + UART_MUTEX_UNLOCK(); + return retCode; +} + +bool uartSetRxFIFOFull(uart_t* uart, uint8_t numBytesFIFOFull) +{ + if(uart == NULL) { + return false; + } + + UART_MUTEX_LOCK(); + bool retCode = (ESP_OK == uart_set_rx_full_threshold(uart->num, numBytesFIFOFull)); + UART_MUTEX_UNLOCK(); + return retCode; +} + + +void uartEnd(uint8_t uart_num) +{ + if(uart_num >= SOC_UART_NUM) { + log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); + return; + } + // get UART information + uart_t* uart = &_uart_bus_array[uart_num]; + + UART_MUTEX_LOCK(); + _uartDetachPins(uart_num, uart->_rxPin, uart->_txPin, uart->_ctsPin, uart->_rtsPin); + if(uart_is_driver_installed(uart_num)) { + uart_driver_delete(uart_num); + } + UART_MUTEX_UNLOCK(); +} + + +void uartSetRxInvert(uart_t* uart, bool invert) +{ + if (uart == NULL) + return; +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + // POTENTIAL ISSUE :: original code only set/reset rxd_inv bit + // IDF or LL set/reset the whole inv_mask! + // if (invert) + // ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_RXD_INV)); + // else + // ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_INV_DISABLE)); + +#else + // this implementation is better over IDF API because it only affects RXD + // this is supported in ESP32, ESP32-S2 and ESP32-C3 + uart_dev_t *hw = UART_LL_GET_HW(uart->num); + if (invert) + hw->conf0.rxd_inv = 1; + else + hw->conf0.rxd_inv = 0; +#endif +} + + +uint32_t uartAvailable(uart_t* uart) +{ + + if(uart == NULL) { + return 0; + } + + UART_MUTEX_LOCK(); + size_t available; + uart_get_buffered_data_len(uart->num, &available); + if (uart->has_peek) available++; + UART_MUTEX_UNLOCK(); + return available; +} + + +uint32_t uartAvailableForWrite(uart_t* uart) +{ + if(uart == NULL) { + return 0; + } + UART_MUTEX_LOCK(); + uint32_t available = uart_ll_get_txfifo_len(UART_LL_GET_HW(uart->num)); + size_t txRingBufferAvailable = 0; + if (ESP_OK == uart_get_tx_buffer_free_size(uart->num, &txRingBufferAvailable)) { + available += txRingBufferAvailable; + } + UART_MUTEX_UNLOCK(); + return available; +} + +size_t uartReadBytes(uart_t* uart, uint8_t *buffer, size_t size, uint32_t timeout_ms) +{ + if(uart == NULL || size == 0 || buffer == NULL) { + return 0; + } + + size_t bytes_read = 0; + + UART_MUTEX_LOCK(); + + if (uart->has_peek) { + uart->has_peek = false; + *buffer++ = uart->peek_byte; + size--; + bytes_read = 1; + } + + if (size > 0) { + int len = uart_read_bytes(uart->num, buffer, size, pdMS_TO_TICKS(timeout_ms)); + if (len < 0) len = 0; // error reading UART + bytes_read += len; + } + + + UART_MUTEX_UNLOCK(); + return bytes_read; +} + +// DEPRICATED but the original code will be kepts here as future reference when a final solution +// to the UART driver is defined in the use case of reading byte by byte from UART. +uint8_t uartRead(uart_t* uart) +{ + if(uart == NULL) { + return 0; + } + uint8_t c = 0; + + UART_MUTEX_LOCK(); + + if (uart->has_peek) { + uart->has_peek = false; + c = uart->peek_byte; + } else { + + int len = uart_read_bytes(uart->num, &c, 1, 20 / portTICK_PERIOD_MS); + if (len <= 0) { // includes negative return from IDF in case of error + c = 0; + } + } + UART_MUTEX_UNLOCK(); + return c; +} + + +uint8_t uartPeek(uart_t* uart) +{ + if(uart == NULL) { + return 0; + } + uint8_t c = 0; + + UART_MUTEX_LOCK(); + + if (uart->has_peek) { + c = uart->peek_byte; + } else { + int len = uart_read_bytes(uart->num, &c, 1, 20 / portTICK_PERIOD_MS); + if (len <= 0) { // includes negative return from IDF in case of error + c = 0; + } else { + uart->has_peek = true; + uart->peek_byte = c; + } + } + UART_MUTEX_UNLOCK(); + return c; +} + +void uartWrite(uart_t* uart, uint8_t c) +{ + if(uart == NULL) { + return; + } + UART_MUTEX_LOCK(); + uart_write_bytes(uart->num, &c, 1); + UART_MUTEX_UNLOCK(); +} + +void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len) +{ + if(uart == NULL || data == NULL || !len) { + return; + } + + UART_MUTEX_LOCK(); + uart_write_bytes(uart->num, data, len); + UART_MUTEX_UNLOCK(); +} + +void uartFlush(uart_t* uart) +{ + uartFlushTxOnly(uart, true); +} + +void uartFlushTxOnly(uart_t* uart, bool txOnly) +{ + if(uart == NULL) { + return; + } + + UART_MUTEX_LOCK(); + while(!uart_ll_is_tx_idle(UART_LL_GET_HW(uart->num))); + + if ( !txOnly ) { + ESP_ERROR_CHECK(uart_flush_input(uart->num)); + } + UART_MUTEX_UNLOCK(); +} + +void uartSetBaudRate(uart_t* uart, uint32_t baud_rate) +{ + if(uart == NULL) { + return; + } + UART_MUTEX_LOCK(); + uint32_t sclk_freq; + if(uart_get_sclk_freq(UART_SCLK_DEFAULT, &sclk_freq) == ESP_OK){ + uart_ll_set_baudrate(UART_LL_GET_HW(uart->num), baud_rate, sclk_freq); + } + uart->_baudrate = baud_rate; + UART_MUTEX_UNLOCK(); +} + +uint32_t uartGetBaudRate(uart_t* uart) +{ + uint32_t baud_rate = 0; + uint32_t sclk_freq; + + if(uart == NULL) { + return 0; + } + + UART_MUTEX_LOCK(); + if(uart_get_sclk_freq(UART_SCLK_DEFAULT, &sclk_freq) == ESP_OK){ + baud_rate = uart_ll_get_baudrate(UART_LL_GET_HW(uart->num), sclk_freq); + } + UART_MUTEX_UNLOCK(); + return baud_rate; +} + +static void ARDUINO_ISR_ATTR uart0_write_char(char c) +{ + while (uart_ll_get_txfifo_len(&UART0) == 0); + uart_ll_write_txfifo(&UART0, (const uint8_t *) &c, 1); +} + +#if SOC_UART_NUM > 1 +static void ARDUINO_ISR_ATTR uart1_write_char(char c) +{ + while (uart_ll_get_txfifo_len(&UART1) == 0); + uart_ll_write_txfifo(&UART1, (const uint8_t *) &c, 1); +} +#endif + +#if SOC_UART_NUM > 2 +static void ARDUINO_ISR_ATTR uart2_write_char(char c) +{ + while (uart_ll_get_txfifo_len(&UART2) == 0); + uart_ll_write_txfifo(&UART2, (const uint8_t *) &c, 1); +} +#endif + +void uart_install_putc() +{ + switch(s_uart_debug_nr) { + case 0: + ets_install_putc1((void (*)(char)) &uart0_write_char); + break; +#if SOC_UART_NUM > 1 + case 1: + ets_install_putc1((void (*)(char)) &uart1_write_char); + break; +#endif +#if SOC_UART_NUM > 2 + case 2: + ets_install_putc1((void (*)(char)) &uart2_write_char); + break; +#endif + default: + ets_install_putc1(NULL); + break; + } +} + +// Routines that take care of UART mode in the HardwareSerial Class code +// used to set UART_MODE_RS485_HALF_DUPLEX auto RTS for TXD for ESP32 chips +bool uartSetMode(uart_t *uart, uart_mode_t mode) +{ + if (uart == NULL || uart->num >= SOC_UART_NUM) + { + return false; + } + + UART_MUTEX_LOCK(); + bool retCode = (ESP_OK == uart_set_mode(uart->num, mode)); + UART_MUTEX_UNLOCK(); + return retCode; +} + +void uartSetDebug(uart_t* uart) +{ + if(uart == NULL || uart->num >= SOC_UART_NUM) { + s_uart_debug_nr = -1; + } else { + s_uart_debug_nr = uart->num; + } + uart_install_putc(); +} + +int uartGetDebug() +{ + return s_uart_debug_nr; +} + +int log_printfv(const char *format, va_list arg) +{ + static char loc_buf[64]; + char * temp = loc_buf; + uint32_t len; + va_list copy; + va_copy(copy, arg); + len = vsnprintf(NULL, 0, format, copy); + va_end(copy); + if(len >= sizeof(loc_buf)){ + temp = (char*)malloc(len+1); + if(temp == NULL) { + return 0; + } + } +/* +// This causes dead locks with logging in specific cases and also with C++ constructors that may send logs +#if !CONFIG_DISABLE_HAL_LOCKS + if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){ + xSemaphoreTake(_uart_bus_array[s_uart_debug_nr].lock, portMAX_DELAY); + } +#endif +*/ +#if CONFIG_IDF_TARGET_ESP32C3 + vsnprintf(temp, len+1, format, arg); + ets_printf("%s", temp); +#else + int wlen = vsnprintf(temp, len+1, format, arg); + for (int i = 0; i < wlen; i++) { + ets_write_char_uart(temp[i]); + } +#endif +/* +// This causes dead locks with logging and also with constructors that may send logs +#if !CONFIG_DISABLE_HAL_LOCKS + if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){ + xSemaphoreGive(_uart_bus_array[s_uart_debug_nr].lock); + } +#endif +*/ + if(len >= sizeof(loc_buf)){ + free(temp); + } + // flushes TX - make sure that the log message is completely sent. + if(s_uart_debug_nr != -1) while(!uart_ll_is_tx_idle(UART_LL_GET_HW(s_uart_debug_nr))); + return len; +} + +int log_printf(const char *format, ...) +{ + int len; + va_list arg; + va_start(arg, format); + len = log_printfv(format, arg); + va_end(arg); + return len; +} + + +static void log_print_buf_line(const uint8_t *b, size_t len, size_t total_len){ + for(size_t i = 0; i 16){ + for(size_t i = len; i<16; i++){ + log_printf(" "); + } + log_printf(" // "); + } else { + log_printf(" // "); + } + for(size_t i = 0; i= 0x20) && (b[i] < 0x80))?b[i]:'.'); + } + log_printf("\n"); +} + +void log_print_buf(const uint8_t *b, size_t len){ + if(!len || !b){ + return; + } + for(size_t i = 0; i 16){ + log_printf("/* 0x%04X */ ", i); + } + log_print_buf_line(b+i, ((len-i)<16)?(len - i):16, len); + } +} + +/* + * if enough pulses are detected return the minimum high pulse duration + minimum low pulse duration divided by two. + * This equals one bit period. If flag is true the function return inmediately, otherwise it waits for enough pulses. + */ +unsigned long uartBaudrateDetect(uart_t *uart, bool flg) +{ +// Baud rate detection only works for ESP32 and ESP32S2 +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 + if(uart == NULL) { + return 0; + } + + uart_dev_t *hw = UART_LL_GET_HW(uart->num); + + while(hw->rxd_cnt.edge_cnt < 30) { // UART_PULSE_NUM(uart_num) + if(flg) return 0; + ets_delay_us(1000); + } + + UART_MUTEX_LOCK(); + //log_i("lowpulse_min_cnt = %d hightpulse_min_cnt = %d", hw->lowpulse.min_cnt, hw->highpulse.min_cnt); + unsigned long ret = ((hw->lowpulse.min_cnt + hw->highpulse.min_cnt) >> 1); + UART_MUTEX_UNLOCK(); + + return ret; +#else + return 0; +#endif +} + + +/* + * To start detection of baud rate with the uart the auto_baud.en bit needs to be cleared and set. The bit period is + * detected calling uartBadrateDetect(). The raw baudrate is computed using the UART_CLK_FREQ. The raw baudrate is + * rounded to the closed real baudrate. + * + * ESP32-C3 reports wrong baud rate detection as shown below: + * + * This will help in a future recall for the C3. + * Baud Sent: Baud Read: + * 300 --> 19536 + * 2400 --> 19536 + * 4800 --> 19536 + * 9600 --> 28818 + * 19200 --> 57678 + * 38400 --> 115440 + * 57600 --> 173535 + * 115200 --> 347826 + * 230400 --> 701754 + * + * +*/ +void uartStartDetectBaudrate(uart_t *uart) { + if(uart == NULL) { + return; + } + +// Baud rate detection only works for ESP32 and ESP32S2 +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 + uart_dev_t *hw = UART_LL_GET_HW(uart->num); + hw->auto_baud.glitch_filt = 0x08; + hw->auto_baud.en = 0; + hw->auto_baud.en = 1; +#else + + // ESP32-C3 requires further testing + // Baud rate detection returns wrong values + + log_e("baud rate detection for this SoC is not supported."); + return; + + // Code bellow for C3 kept for future recall + //hw->rx_filt.glitch_filt = 0x08; + //hw->rx_filt.glitch_filt_en = 1; + //hw->conf0.autobaud_en = 0; + //hw->conf0.autobaud_en = 1; +#endif +} + +unsigned long uartDetectBaudrate(uart_t *uart) +{ + if(uart == NULL) { + return 0; + } + +// Baud rate detection only works for ESP32 and ESP32S2 +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 + + static bool uartStateDetectingBaudrate = false; + + if(!uartStateDetectingBaudrate) { + uartStartDetectBaudrate(uart); + uartStateDetectingBaudrate = true; + } + + unsigned long divisor = uartBaudrateDetect(uart, true); + if (!divisor) { + return 0; + } + + uart_dev_t *hw = UART_LL_GET_HW(uart->num); + hw->auto_baud.en = 0; + + uartStateDetectingBaudrate = false; // Initialize for the next round + + unsigned long baudrate = getApbFrequency() / divisor; + + //log_i("APB_FREQ = %d\nraw baudrate detected = %d", getApbFrequency(), baudrate); + + static const unsigned long default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400}; + + size_t i; + for (i = 1; i < sizeof(default_rates) / sizeof(default_rates[0]) - 1; i++) // find the nearest real baudrate + { + if (baudrate <= default_rates[i]) + { + if (baudrate - default_rates[i - 1] < default_rates[i] - baudrate) { + i--; + } + break; + } + } + + return default_rates[i]; +#else + log_e("baud rate detection this SoC is not supported."); + return 0; +#endif +} + +/* + These functions are for testing purpose only and can be used in Arduino Sketches + Those are used in the UART examples +*/ + +/* + This is intended to make an internal loopback connection using IOMUX + The function uart_internal_loopback() shall be used right after Arduino Serial.begin(...) + This code "replaces" the physical wiring for connecting TX <--> RX in a loopback +*/ + +// gets the right TX or RX SIGNAL, based on the UART number from gpio_sig_map.h +#if SOC_UART_NUM > 2 + #define UART_TX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0TXD_OUT_IDX : (uartNumber == UART_NUM_1 ? U1TXD_OUT_IDX : U2TXD_OUT_IDX)) + #define UART_RX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0RXD_IN_IDX : (uartNumber == UART_NUM_1 ? U1RXD_IN_IDX : U2RXD_IN_IDX)) +#else + #define UART_TX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0TXD_OUT_IDX : U1TXD_OUT_IDX) + #define UART_RX_SIGNAL(uartNumber) (uartNumber == UART_NUM_0 ? U0RXD_IN_IDX : U1RXD_IN_IDX) +#endif +/* + This function internally binds defined UARTs TX signal with defined RX pin of any UART (same or different). + This creates a loop that lets us receive anything we send on the UART without external wires. +*/ +void uart_internal_loopback(uint8_t uartNum, int8_t rxPin) +{ + if (uartNum > SOC_UART_NUM - 1 || !GPIO_IS_VALID_GPIO(rxPin)) return; + esp_rom_gpio_connect_out_signal(rxPin, UART_TX_SIGNAL(uartNum), false, false); +} + +/* + This is intended to generate BREAK in an UART line +*/ + +// Forces a BREAK in the line based on SERIAL_8N1 configuration at any baud rate +void uart_send_break(uint8_t uartNum) +{ + uint32_t currentBaudrate = 0; + uart_get_baudrate(uartNum, ¤tBaudrate); + // calculates 10 bits of breaks in microseconds for baudrates up to 500mbps + // This is very sensetive timing... it works fine for SERIAL_8N1 + uint32_t breakTime = (uint32_t) (10.0 * (1000000.0 / currentBaudrate)); + uart_set_line_inverse(uartNum, UART_SIGNAL_TXD_INV); + esp_rom_delay_us(breakTime); + uart_set_line_inverse(uartNum, UART_SIGNAL_INV_DISABLE); +} + +// Sends a buffer and at the end of the stream, it generates BREAK in the line +int uart_send_msg_with_break(uint8_t uartNum, uint8_t *msg, size_t msgSize) +{ + // 12 bits long BREAK for 8N1 + return uart_write_bytes_with_break(uartNum, (const void *)msg, msgSize, 12); +} + +#endif /* SOC_UART_SUPPORTED */ + diff --git a/tools/dummy2.py b/tools/dummy2.py new file mode 100755 index 00000000000..10af3d14a9d --- /dev/null +++ b/tools/dummy2.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python + +"""Script to download and extract tools + +This script will download and extract required tools into the current directory. +Tools list is obtained from package/package_esp8266com_index.template.json file. +""" + +from __future__ import print_function + +__author__ = "Ivan Grokhotkov" +__version__ = "2015" + +import os +import shutil +import errno +import os.path +import hashlib +import json +import platform +import sys +import tarfile +import zipfile +import re + +if sys.version_info[0] == 3: + from urllib.request import urlretrieve + from urllib.request import urlopen + unicode = lambda s: str(s) +else: + # Not Python 3 - today, it is most likely to be Python 2 + from urllib import urlretrieve + from urllib import urlopen + +if 'Windows' in platform.system(): + import requests + +# determine if application is a script file or frozen exe +if getattr(sys, 'frozen', False): + current_dir = os.path.dirname(os.path.realpath(unicode(sys.executable))) +elif __file__: + current_dir = os.path.dirname(os.path.realpath(unicode(__file__))) + +#current_dir = os.path.dirname(os.path.realpath(unicode(__file__))) +dist_dir = current_dir + '/dist/' + +def sha256sum(filename, blocksize=65536): + hash = hashlib.sha256() + with open(filename, "rb") as f: + for block in iter(lambda: f.read(blocksize), b""): + hash.update(block) + return hash.hexdigest() + +def mkdir_p(path): + try: + os.makedirs(path) + except OSError as exc: + if exc.errno != errno.EEXIST or not os.path.isdir(path): + raise + +def report_progress(count, blockSize, totalSize): + if sys.stdout.isatty(): + if totalSize > 0: + percent = int(count*blockSize*100/totalSize) + percent = min(100, percent) + sys.stdout.write("\r%d%%" % percent) + else: + sofar = (count*blockSize) / 1024 + if sofar >= 1000: + sofar /= 1024 + sys.stdout.write("\r%dMB " % (sofar)) + else: + sys.stdout.write("\r%dKB" % (sofar)) + sys.stdout.flush() + +def unpack(filename, destination): + dirname = '' + print('Extracting {0} ...'.format(os.path.basename(filename))) + sys.stdout.flush() + if filename.endswith('tar.gz'): + tfile = tarfile.open(filename, 'r:gz') + tfile.extractall(destination) + dirname = tfile.getnames()[0] + elif filename.endswith('tar.xz'): + tfile = tarfile.open(filename, 'r:xz') + tfile.extractall(destination) + dirname = tfile.getnames()[0] + elif filename.endswith('zip'): + zfile = zipfile.ZipFile(filename) + zfile.extractall(destination) + dirname = zfile.namelist()[0] + else: + raise NotImplementedError('Unsupported archive type') + + # a little trick to rename tool directories so they don't contain version number + rename_to = re.match(r'^([a-z][^\-]*\-*)+', dirname).group(0).strip('-') + if rename_to == dirname and dirname.startswith('esp32-arduino-libs-'): + rename_to = 'esp32-arduino-libs' + if rename_to != dirname: + print('Renaming {0} to {1} ...'.format(dirname, rename_to)) + if os.path.isdir(rename_to): + shutil.rmtree(rename_to) + shutil.move(dirname, rename_to) + +def download_file_with_progress(url,filename): + import ssl + import contextlib + ctx = ssl.create_default_context() + ctx.check_hostname = False + ctx.verify_mode = ssl.CERT_NONE + with contextlib.closing(urlopen(url,context=ctx)) as fp: + total_size = int(fp.getheader("Content-Length",fp.getheader("Content-length","0"))) + block_count = 0 + block_size = 1024 * 8 + block = fp.read(block_size) + if block: + with open(filename,'wb') as out_file: + out_file.write(block) + block_count += 1 + report_progress(block_count, block_size, total_size) + while True: + block = fp.read(block_size) + if not block: + break + out_file.write(block) + block_count += 1 + report_progress(block_count, block_size, total_size) + else: + raise Exception ('nonexisting file or connection error') + +def download_file(url,filename): + import ssl + import contextlib + ctx = ssl.create_default_context() + ctx.check_hostname = False + ctx.verify_mode = ssl.CERT_NONE + with contextlib.closing(urlopen(url,context=ctx)) as fp: + block_size = 1024 * 8 + block = fp.read(block_size) + if block: + with open(filename,'wb') as out_file: + out_file.write(block) + while True: + block = fp.read(block_size) + if not block: + break + out_file.write(block) + else: + raise Exception ('nonexisting file or connection error') + +def get_tool(tool): + sys_name = platform.system() + archive_name = tool['archiveFileName'] + local_path = dist_dir + archive_name + url = tool['url'] + if not os.path.isfile(local_path): + print('Downloading ' + archive_name + ' ...') + sys.stdout.flush() + if 'CYGWIN_NT' in sys_name: + import ssl + ctx = ssl.create_default_context() + ctx.check_hostname = False + ctx.verify_mode = ssl.CERT_NONE + urlretrieve(url, local_path, report_progress, context=ctx) + elif 'Windows' in sys_name: + r = requests.get(url) + f = open(local_path, 'wb') + f.write(r.content) + f.close() + else: + is_ci = os.environ.get('GITHUB_WORKSPACE'); + if is_ci: + download_file(url, local_path) + else: + try: + urlretrieve(url, local_path, report_progress) + except: + download_file_with_progress(url, local_path) + sys.stdout.write("\rDone \n") + sys.stdout.flush() + else: + print('Tool {0} already downloaded'.format(archive_name)) + sys.stdout.flush() + unpack(local_path, '.') + +def load_tools_list(filename, platform): + tools_info = json.load(open(filename))['packages'][0]['tools'] + tools_to_download = [] + for t in tools_info: + tool_platform = [p for p in t['systems'] if p['host'] == platform] + if len(tool_platform) == 0: + # Fallback to x86 on Apple ARM + if platform == 'arm64-apple-darwin': + tool_platform = [p for p in t['systems'] if p['host'] == 'x86_64-apple-darwin'] + if len(tool_platform) == 0: + continue + # Fallback to 32bit on 64bit x86 Windows + elif platform == 'x86_64-mingw32': + tool_platform = [p for p in t['systems'] if p['host'] == 'i686-mingw32'] + if len(tool_platform) == 0: + continue + else: + continue + tools_to_download.append(tool_platform[0]) + return tools_to_download + +def identify_platform(): + arduino_platform_names = {'Darwin' : {32 : 'i386-apple-darwin', 64 : 'x86_64-apple-darwin'}, + 'DarwinARM': {32 : 'arm64-apple-darwin', 64 : 'arm64-apple-darwin'}, + 'Linux' : {32 : 'i686-pc-linux-gnu', 64 : 'x86_64-pc-linux-gnu'}, + 'LinuxARM' : {32 : 'arm-linux-gnueabihf', 64 : 'aarch64-linux-gnu'}, + 'Windows' : {32 : 'i686-mingw32', 64 : 'x86_64-mingw32'}} + bits = 32 + if sys.maxsize > 2**32: + bits = 64 + sys_name = platform.system() + sys_platform = platform.platform() + if 'Darwin' in sys_name and (sys_platform.find('arm') > 0 or sys_platform.find('arm64') > 0): + sys_name = 'DarwinARM' + if 'Linux' in sys_name and (sys_platform.find('arm') > 0 or sys_platform.find('aarch64') > 0): + sys_name = 'LinuxARM' + if 'CYGWIN_NT' in sys_name: + sys_name = 'Windows' + print('System: %s, Bits: %d, Info: %s' % (sys_name, bits, sys_platform)) + return arduino_platform_names[sys_name][bits] + +if __name__ == '__main__': + is_test = (len(sys.argv) > 1 and sys.argv[1] == '-h') + if is_test: + print('Test run!') + identified_platform = identify_platform() + print('Platform: {0}'.format(identified_platform)) + tools_to_download = load_tools_list(current_dir + '/../package/package_esp32_index.template.json', identified_platform) + mkdir_p(dist_dir) + for tool in tools_to_download: + if is_test: + print('Would install: {0}'.format(tool['archiveFileName'])) + else: + get_tool(tool) + print('Platform Tools Installed')