/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
/*
ArduPilot bootloader. This implements the same protocol originally
developed for PX4, but builds on top of the ChibiOS HAL
It does not use the full AP_HAL API in order to keep the firmware
size below the maximum of 16kByte required for F4 based
boards. Instead it uses the ChibiOS APIs directly
*/
#include
#include "ch.h"
#include "hal.h"
#include "hwdef.h"
#include
#include
#include
#include "support.h"
#include "bl_protocol.h"
#include "flash_from_sd.h"
#include "can.h"
#include
#if EXT_FLASH_SIZE_MB
#include
#endif
#include
#include "network.h"
extern "C" {
int main(void);
}
struct boardinfo board_info = {
.board_type = APJ_BOARD_ID,
.board_rev = 0,
.fw_size = (BOARD_FLASH_SIZE - (FLASH_BOOTLOADER_LOAD_KB + FLASH_RESERVE_END_KB + APP_START_OFFSET_KB))*1024,
.extf_size = (EXT_FLASH_SIZE_MB * 1024 * 1024) - (EXT_FLASH_RESERVE_START_KB + EXT_FLASH_RESERVE_END_KB) * 1024
};
#ifndef HAL_BOOTLOADER_TIMEOUT
#define HAL_BOOTLOADER_TIMEOUT 5000
#endif
#ifndef HAL_STAY_IN_BOOTLOADER_VALUE
#define HAL_STAY_IN_BOOTLOADER_VALUE 0
#endif
#if EXT_FLASH_SIZE_MB
AP_FlashIface_JEDEC ext_flash;
#endif
#if AP_BOOTLOADER_NETWORK_ENABLED
static BL_Network network;
#endif
int main(void)
{
#ifdef AP_BOOTLOADER_CUSTOM_HERE4
custom_startup();
#endif
flash_init();
#if defined(STM32H7) && CH_CFG_USE_HEAP
check_ecc_errors();
#endif
#ifdef STM32F427xx
if (BOARD_FLASH_SIZE > 1024 && check_limit_flash_1M()) {
board_info.fw_size = (1024 - (FLASH_BOOTLOADER_LOAD_KB + APP_START_OFFSET_KB))*1024;
}
#endif
bool try_boot = false;
uint32_t timeout = HAL_BOOTLOADER_TIMEOUT;
#ifdef HAL_BOARD_AP_PERIPH_ZUBAXGNSS
// setup remapping register for ZubaxGNSS
uint32_t mapr = AFIO->MAPR;
mapr &= ~AFIO_MAPR_SWJ_CFG;
mapr |= AFIO_MAPR_SWJ_CFG_JTAGDISABLE;
AFIO->MAPR = mapr | AFIO_MAPR_CAN_REMAP_REMAP2 | AFIO_MAPR_SPI3_REMAP;
#endif
#if HAL_FLASH_PROTECTION
stm32_flash_unprotect_flash();
#endif
#if AP_BOOTLOADER_NETWORK_ENABLED
network.save_comms_ip();
#endif
#if AP_FASTBOOT_ENABLED
enum rtc_boot_magic m = check_fast_reboot();
bool was_watchdog = stm32_was_watchdog_reset();
if (was_watchdog) {
try_boot = true;
timeout = 0;
} else if (m == RTC_BOOT_HOLD) {
timeout = 0;
} else if (m == RTC_BOOT_FAST) {
try_boot = true;
timeout = 0;
}
#if HAL_USE_CAN == TRUE || HAL_NUM_CAN_IFACES
else if ((m & 0xFFFFFF00) == RTC_BOOT_CANBL) {
try_boot = false;
timeout = 10000;
can_set_node_id(m & 0xFF);
}
if (can_check_update()) {
// trying to update firmware, stay in bootloader
try_boot = false;
timeout = 0;
}
#if AP_CHECK_FIRMWARE_ENABLED
const auto ok = check_good_firmware();
if (ok != check_fw_result_t::CHECK_FW_OK) {
// bad firmware CRC, don't try and boot
timeout = 0;
try_boot = false;
led_set(LED_BAD_FW);
}
#if AP_BOOTLOADER_NETWORK_ENABLED
if (ok == check_fw_result_t::CHECK_FW_OK) {
const auto *app_descriptor = get_app_descriptor();
if (app_descriptor != nullptr) {
network.status_printf("Firmware OK: %ld.%ld.%lx\n", app_descriptor->version_major,
app_descriptor->version_minor,
app_descriptor->git_hash);
}
} else {
network.status_printf("Firmware Error: %d\n", (int)ok);
}
#endif
#endif // AP_CHECK_FIRMWARE_ENABLED
#ifndef BOOTLOADER_DEV_LIST
else if (timeout == HAL_BOOTLOADER_TIMEOUT) {
// fast boot for good firmware if we haven't been told to stay
// in bootloader
try_boot = true;
timeout = 1000;
}
#endif
if (was_watchdog && m != RTC_BOOT_FWOK) {
// we've had a watchdog within 30s of booting main CAN
// firmware. We will stay in bootloader to allow the user to
// load a fixed firmware
stm32_watchdog_clear_reason();
try_boot = false;
timeout = 0;
}
#elif AP_CHECK_FIRMWARE_ENABLED
const auto ok = check_good_firmware();
if (ok != check_fw_result_t::CHECK_FW_OK) {
// bad firmware, don't try and boot
timeout = 0;
try_boot = false;
led_set(LED_BAD_FW);
}
#endif
#if defined(HAL_GPIO_PIN_VBUS) && defined(HAL_ENABLE_VBUS_CHECK)
#if HAL_USE_SERIAL_USB == TRUE
else if (palReadLine(HAL_GPIO_PIN_VBUS) == 0) {
try_boot = true;
timeout = 0;
}
#endif
#endif
// if we fail to boot properly we want to pause in bootloader to give
// a chance to load new app code
set_fast_reboot(RTC_BOOT_OFF);
#endif // AP_FASTBOOT_ENABLED
#ifdef HAL_GPIO_PIN_STAY_IN_BOOTLOADER
// optional "stay in bootloader" pin
if (palReadLine(HAL_GPIO_PIN_STAY_IN_BOOTLOADER) == HAL_STAY_IN_BOOTLOADER_VALUE) {
try_boot = false;
timeout = 0;
}
#endif
#if EXT_FLASH_SIZE_MB
while (!ext_flash.init()) {
// keep trying until we get it working
// there's no future without it
chThdSleep(chTimeMS2I(20));
}
#endif
if (try_boot) {
jump_to_app();
}
#if defined(BOOTLOADER_DEV_LIST)
init_uarts();
#endif
#if HAL_USE_CAN == TRUE || HAL_NUM_CAN_IFACES
can_start();
#endif
#if AP_BOOTLOADER_NETWORK_ENABLED
network.init();
#endif
#if AP_BOOTLOADER_FLASH_FROM_SD_ENABLED
if (flash_from_sd()) {
jump_to_app();
}
#endif
#if defined(BOOTLOADER_DEV_LIST)
while (true) {
bootloader(timeout);
jump_to_app();
}
#else
// CAN and network only
while (true) {
uint32_t t0 = AP_HAL::millis();
while (timeout == 0 || AP_HAL::millis() - t0 <= timeout) {
can_update();
chThdSleep(chTimeMS2I(1));
}
jump_to_app();
}
#endif
}