39#ifndef _FREERTOS_DRIVERS_ESP32_ESP32BOOTLOADERHAL_HXX_
40#define _FREERTOS_DRIVERS_ESP32_ESP32BOOTLOADERHAL_HXX_
44#ifndef BOOTLOADER_LOG_LEVEL
45#define BOOTLOADER_LOG_LEVEL VERBOSE
48#ifndef BOOTLOADER_TWAI_LOG_LEVEL
49#define BOOTLOADER_TWAI_LOG_LEVEL VERBOSE
53#define BOOTLOADER_STREAM
54#ifndef WRITE_BUFFER_SIZE
56#define WRITE_BUFFER_SIZE (CONFIG_WL_SECTOR_SIZE / 2)
59#include <driver/twai.h>
61#include <esp_app_format.h>
62#include <esp_chip_info.h>
63#include <esp_ota_ops.h>
64#if defined(CONFIG_IDF_TARGET_ESP32)
65#include <esp32/rom/rtc.h>
66#elif defined(CONFIG_IDF_TARGET_ESP32S2)
67#include <esp32s2/rom/rtc.h>
68#elif defined(CONFIG_IDF_TARGET_ESP32S3)
69#include <esp32s3/rom/rtc.h>
70#elif defined(CONFIG_IDF_TARGET_ESP32C3)
71#include <esp32c3/rom/rtc.h>
73#error Unknown/Unsupported ESP32 variant.
147 twai_timing_config_t t_config = TWAI_TIMING_CONFIG_125KBITS();
150 twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
153 twai_general_config_t g_config =
156 g_config.tx_queue_len = config_can_tx_buffer_size();
157 g_config.rx_queue_len = config_can_rx_buffer_size();
159 LOG(BOOTLOADER_LOG_LEVEL,
"[Bootloader] Configuring TWAI driver");
160 ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config));
161 LOG(BOOTLOADER_LOG_LEVEL,
"[Bootloader] Starting TWAI driver");
162 ESP_ERROR_CHECK(twai_start());
171 LOG(BOOTLOADER_LOG_LEVEL,
"[Bootloader] application_entry");
186 LOG(BOOTLOADER_LOG_LEVEL,
"[Bootloader] Reboot requested");
195 twai_message_t rx_msg;
196 memset(&rx_msg, 0,
sizeof(twai_message_t));
197 if (twai_receive(&rx_msg, MAX_TWAI_WAIT) == ESP_OK)
199 LOG(BOOTLOADER_TWAI_LOG_LEVEL,
"[Bootloader] CAN_RX");
200 frame->can_id = rx_msg.identifier;
201 frame->can_dlc = rx_msg.data_length_code;
203 frame->can_eff = rx_msg.extd;
204 frame->can_rtr = rx_msg.rtr;
205 memcpy(frame->data, rx_msg.data, frame->can_dlc);
217 twai_message_t tx_msg;
218 memset(&tx_msg, 0,
sizeof(twai_message_t));
219 tx_msg.identifier = frame.can_id;
220 tx_msg.data_length_code = frame.can_dlc;
221 tx_msg.extd = frame.can_eff;
222 tx_msg.rtr = frame.can_rtr;
223 memcpy(tx_msg.data, frame.data, frame.can_dlc);
226 LOG(BOOTLOADER_TWAI_LOG_LEVEL,
"[Bootloader] CAN_TX");
245 LOG(BOOTLOADER_LOG_LEVEL,
246 "[Bootloader] get_flash_boundaries(%d, %" PRIu32
")",
248 *((uint32_t *)flash_min) = 0;
259 const void *address,
const void **page_start, uint32_t *page_length_bytes)
261 uint32_t value = (uint32_t)address;
262 value &= ~(CONFIG_WL_SECTOR_SIZE - 1);
263 *page_start = (
const void *)value;
264 *page_length_bytes = CONFIG_WL_SECTOR_SIZE;
265 LOG(BOOTLOADER_LOG_LEVEL,
266 "[Bootloader] get_flash_page_info(%" PRIu32
", %" PRIu32
")",
267 value, *page_length_bytes);
279 LOG(BOOTLOADER_LOG_LEVEL,
"[Bootloader] Erase: %" PRIu32,
295void write_flash(
const void *address,
const void *data, uint32_t size_bytes)
297 uint32_t addr = (uint32_t)address;
298 LOG(
VERBOSE,
"[Bootloader] Write: %" PRIu32
", %" PRIu32, addr,
307 const char *
const CHIP_ID_NAMES[] =
325 bool should_abort =
false;
326 esp_image_header_t *image_header = (esp_image_header_t *)data;
329 if (image_header->magic == ESP_IMAGE_HEADER_MAGIC)
331 LOG(BOOTLOADER_LOG_LEVEL,
"[Bootloader] Chip ID: %s / %x (%x)",
332 CHIP_ID_NAMES[image_header->chip_id],
336 if (image_header->chip_id != ESP_CHIP_ID_INVALID &&
342 esp_err_t err = ESP_ERROR_CHECK_WITHOUT_ABORT(
345 should_abort = (err != ESP_OK);
349 LOG_ERROR(
"[Bootloader] Firmware does not appear to be valid "
350 "or is for a different chip (%s - %x vs %s - %x).",
351 CHIP_ID_NAMES[image_header->chip_id],
352 image_header->chip_id,
360 LOG_ERROR(
"[Bootloader] Image magic is incorrect: %d vs %d!",
361 image_header->magic, ESP_IMAGE_HEADER_MAGIC);
381 ESP_ERROR_CHECK_WITHOUT_ABORT(
408 LOG(
INFO,
"[Bootloader] Finalizing firmware update");
412 LOG_ERROR(
"[Bootloader] Firmware update failed: %s (%04x), aborting!",
413 esp_err_to_name(res), res);
417 "[Bootloader] Firmware appears valid, updating the next boot "
422 LOG_ERROR(
"[Bootloader] Failed to update the boot partition %s (%04x)!",
423 esp_err_to_name(res), res);
426 return openlcb::Defs::ERROR_CODE_OK;
439 LOG(BOOTLOADER_LOG_LEVEL,
"[Bootloader] checksum_data(%" PRIu32
")", size);
451 LOG(BOOTLOADER_LOG_LEVEL,
"[Bootloader] nmranet_alias");
461 LOG(BOOTLOADER_LOG_LEVEL,
"[Bootloader] nmranet_nodeid");
489 if (reset_reason == POWERON_RESET)
502 bool reboot_on_exit =
true)
513 esp_chip_info_t chip_info;
514 esp_chip_info(&chip_info);
515 switch (chip_info.model)
530 LOG(
FATAL,
"[Bootloader] Unknown/Unsupported Chip ID: %x",
542 (esp_partition_t *)esp_ota_get_next_update_partition(NULL);
546 LOG(
INFO,
"[Bootloader] Preparing to receive firmware");
547 LOG(
INFO,
"[Bootloader] Current partition: %s",
549 LOG(
INFO,
"[Bootloader] Target partition: %s",
553 LOG(BOOTLOADER_LOG_LEVEL,
"[Bootloader] calling bootloader_entry");
558 LOG_ERROR(
"[Bootloader] Unable to locate next OTA partition!");
563 LOG(BOOTLOADER_LOG_LEVEL,
"[Bootloader] Stopping TWAI driver");
564 ESP_ERROR_CHECK(twai_stop());
565 LOG(BOOTLOADER_LOG_LEVEL,
"[Bootloader] Disabling TWAI driver");
566 ESP_ERROR_CHECK(twai_driver_uninstall());
576 LOG(
INFO,
"[Bootloader] Restarting!");
void bootloader_entry()
Main entry point for MCU-based bootloaders. Never returns.
bool try_send_can_frame(const struct can_frame &frame)
Callback from the bootloader to transmit a single CAN frame.
static constexpr BaseType_t MAX_TWAI_WAIT_RX
Maximum time to wait for a TWAI frame to be received before giving up.
void get_flash_boundaries(const void **flash_min, const void **flash_max, const struct app_header **app_header)
Callback from the bootloader to retrieve flash boundaries.
void esp32_bootloader_init(uint8_t reset_reason)
Initializes the ESP32 Bootloader.
void bootloader_reboot(void)
Callback from the bootloader when a reboot should be triggered.
static constexpr uint32_t RTC_BOOL_TRUE
Value to be assigned to bootloader_request when the bootloader should run instead of normal node oper...
void application_entry(void)
Callback from the bootloader for entering the application.
static constexpr uint32_t RTC_BOOL_FALSE
Default value to assign to bootloader_request when the ESP32-C3 starts the first time or when the boo...
void erase_flash_page(const void *address)
Callback from the bootloader to erase a flash page.
void get_flash_page_info(const void *address, const void **page_start, uint32_t *page_length_bytes)
Callback from the bootloader to retrieve flash page information.
static constexpr BaseType_t MAX_TWAI_WAIT_TX
Maximum time to wait for a TWAI frame to be transmitted before giving up.
void esp32_bootloader_run(uint64_t id, gpio_num_t rx, gpio_num_t tx, bool reboot_on_exit=true)
Runs the ESP32 Bootloader.
uint16_t flash_complete(void)
Callback from the bootloader to indicate that the full firmware file has been received.
void checksum_data(const void *data, uint32_t size, uint32_t *checksum)
Callback from the bootloader to calculate the checksum of a data block.
static uint32_t RTC_NOINIT_ATTR bootloader_request
Flag used to indicate that we have been requested to enter the bootloader instead of normal node oper...
void bootloader_hw_init(void)
Callback from the bootloader to configure and start the TWAI hardware.
bool read_can_frame(struct can_frame *frame)
Callback from the bootloader to read a single CAN frame.
uint16_t nmranet_alias(void)
Callback from the bootloader to obtain the pre-defined alias to use.
uint64_t nmranet_nodeid(void)
Callback from the bootloader to obtain the node-id to use.
static Esp32BootloaderState esp_bl_state
Bootloader configuration data.
void write_flash(const void *address, const void *data, uint32_t size_bytes)
Callback from the bootloader to write to flash.
void bootloader_led(enum BootloaderLed led, bool value)
Sets status LEDs.
#define CHECKSUM_COUNT
Number of 32-bit words in one checksum data.
#define LOG(level, message...)
Conditionally write a message to the logging output.
static const int VERBOSE
Loglevel that is usually not printed, reporting debugging information.
static const int INFO
Loglevel that is printed by default, reporting some status information.
static const int FATAL
Loglevel that kills the current process.
#define LOG_ERROR(message...)
Shorthand for LOG(LEVEL_ERROR, message...). See LOG.
ESP32 Bootloader internal data.
esp_partition_t * current
Partition where the firmware is currently running from.
gpio_num_t rx_pin
GPIO pin connected to the CAN transceiver RX pin.
uint64_t node_id
Node ID to use for the bootloader.
esp_ota_handle_t ota_handle
OTA handle used to track the firmware update progress.
gpio_num_t tx_pin
GPIO pin connected to the CAN transceiver TX pin.
esp_partition_t * target
Partition where the new firmware should be written to.
esp_chip_id_t chip_id
Chip identifier for the currently running firmware.
struct app_header app_header
Currently running application header information.
bool twai_initialized
Internal flag to indicate that we have initialized the TWAI peripheral and should deinit it before ex...
@ ERROR_FIRMWARE_CSUM
The firmware written has failed checksum (temporary error).