diff --git a/Tools/ardupilotwaf/chibios.py b/Tools/ardupilotwaf/chibios.py index 85b1122bed2e4f..d6ef365caa93fa 100644 --- a/Tools/ardupilotwaf/chibios.py +++ b/Tools/ardupilotwaf/chibios.py @@ -633,6 +633,17 @@ def bldpath(path): env.DEFINES += [ 'CANARD_MULTI_IFACE=1' ] setup_optimization(cfg.env) +def get_build_option_value(env, name): + '''return the value of a build option, or None if it was not specified''' + enable_option = 'enable_' + name + disable_option = 'disable_' + name + if env.OPTIONS.get(enable_option, False) or env.OPTIONS.get(enable_option.lower(), False): + return 1 + if env.OPTIONS.get(disable_option, False) or env.OPTIONS.get(disable_option.lower(), False): + return 0 + return None + + def generate_hwdef_h(env): '''run chibios_hwdef.py''' if env.BOOTLOADER: @@ -660,6 +671,7 @@ def generate_hwdef_h(env): outdir=hwdef_out, bootloader=bootloader_flag, signed_fw=bool(env.AP_SIGNED_FIRMWARE), + mass_storage_option=get_build_option_value(env, 'MASS_STORAGE'), hwdef=hwdef, # stringify like old subprocess based invocation. note that no error is # generated if this path is missing! diff --git a/Tools/scripts/build_options.py b/Tools/scripts/build_options.py index 5523ccbcac684e..d862cf347a041a 100644 --- a/Tools/scripts/build_options.py +++ b/Tools/scripts/build_options.py @@ -420,6 +420,7 @@ def config_option(self): Feature('Other', 'GyroFFT', 'HAL_GYROFFT_ENABLED', 'Enable In-Flight gyro FFT calculations', 0, None), Feature('Other', 'NMEA_OUTPUT', 'HAL_NMEA_OUTPUT_ENABLED', 'Enable NMEA output', 0, None), Feature('Other', 'SDCARD_FORMATTING', 'AP_FILESYSTEM_FORMAT_ENABLED', 'Enable Formatting of microSD cards', 0, None), + Feature('Other', 'MASS_STORAGE', 'AP_REBOOT_MASS_STORAGE_ENABLED', 'Enable reboot to USB mass storage', 0, None), Feature('Other', 'BOOTLOADER_FLASHING', 'AP_BOOTLOADER_FLASHING_ENABLED', 'Enable Bootloader flashing', 0, "FILESYSTEM_ROMFS"), # noqa Feature('Other', 'SERIALDEVICE_REGISTER', 'AP_SERIALMANAGER_REGISTER_ENABLED', 'Enable Serial device registration', 0, None), # noqa diff --git a/Tools/scripts/extract_features.py b/Tools/scripts/extract_features.py index b0d682e9938f8a..7de7e725db3ee4 100755 --- a/Tools/scripts/extract_features.py +++ b/Tools/scripts/extract_features.py @@ -34,6 +34,7 @@ def __init__(self, filename, nm="arm-none-eabi-nm", strings="strings"): self.features = [ ('AP_ADVANCEDFAILSAFE_ENABLED', r'AP_AdvancedFailsafe::heartbeat\b',), ('AP_BOOTLOADER_FLASHING_ENABLED', 'ChibiOS::Util::flash_bootloader',), + ('AP_REBOOT_MASS_STORAGE_ENABLED', r'ChibiOS::usb_msd_run',), ('AP_AIRSPEED_ENABLED', 'AP_Airspeed::AP_Airspeed',), ('AP_AIRSPEED_{type}_ENABLED', r'AP_Airspeed_(?P.*)::init',), diff --git a/libraries/AP_HAL/AP_HAL_Boards.h b/libraries/AP_HAL/AP_HAL_Boards.h index 6bb859cfdb14d1..0270859d7949f6 100644 --- a/libraries/AP_HAL/AP_HAL_Boards.h +++ b/libraries/AP_HAL/AP_HAL_Boards.h @@ -228,6 +228,10 @@ #define HAL_OS_LITTLEFS_IO 0 #endif +#ifndef AP_REBOOT_MASS_STORAGE_ENABLED +#define AP_REBOOT_MASS_STORAGE_ENABLED 0 +#endif + #ifndef HAL_BARO_DEFAULT #define HAL_BARO_DEFAULT HAL_BARO_NONE #endif diff --git a/libraries/AP_HAL/Util.h b/libraries/AP_HAL/Util.h index 9f3de509cac8e0..f73f18546a48e3 100644 --- a/libraries/AP_HAL/Util.h +++ b/libraries/AP_HAL/Util.h @@ -24,6 +24,11 @@ class AP_HAL::Util { // return true if the reason for the reboot was a watchdog reset virtual bool was_watchdog_reset() const { return false; } +#if AP_REBOOT_MASS_STORAGE_ENABLED + // support an early application mode which exports the SD card over USB + virtual bool request_usb_msd() { return false; } +#endif + // return true if safety was off and this was a watchdog reset bool was_watchdog_safety_off() const { return was_watchdog_reset() && persistent_data.safety_state == SAFETY_ARMED; @@ -77,7 +82,8 @@ class AP_HAL::Util { uint8_t fault_thd_prio; char thread_name4[4]; int8_t scheduler_task; - bool armed; // true if vehicle was armed + bool armed : 1; // true if vehicle was armed + bool boot_to_mass_storage : 1; enum safety_state safety_state; bool boot_to_dfu; // true if we should reboot to DFU on boot }; diff --git a/libraries/AP_HAL/board/chibios.h b/libraries/AP_HAL/board/chibios.h index 33ec03a7d5b79b..5448731b3743c3 100644 --- a/libraries/AP_HAL/board/chibios.h +++ b/libraries/AP_HAL/board/chibios.h @@ -30,6 +30,14 @@ #define HAL_PROGRAM_SIZE_LIMIT_KB (BOARD_FLASH_SIZE+EXT_FLASH_SIZE_MB*1024) #endif +#ifndef AP_REBOOT_MASS_STORAGE_ENABLED +#if HAL_PROGRAM_SIZE_LIMIT_KB >= 2048 +#define AP_REBOOT_MASS_STORAGE_ENABLED 1 +#else +#define AP_REBOOT_MASS_STORAGE_ENABLED 0 +#endif +#endif + #ifndef HAL_NUM_CAN_IFACES #define HAL_NUM_CAN_IFACES 0 #endif diff --git a/libraries/AP_HAL_ChibiOS/HAL_ChibiOS_Class.cpp b/libraries/AP_HAL_ChibiOS/HAL_ChibiOS_Class.cpp index 21e88b408eb40f..421321d51e6519 100644 --- a/libraries/AP_HAL_ChibiOS/HAL_ChibiOS_Class.cpp +++ b/libraries/AP_HAL_ChibiOS/HAL_ChibiOS_Class.cpp @@ -25,6 +25,7 @@ #include #include "shared_dma.h" #include "sdcard.h" +#include "USB_MSD.h" #include #include "hwdef/common/usbcfg.h" #include "hwdef/common/stm32_util.h" @@ -367,6 +368,12 @@ void HAL_ChibiOS::run(int argc, char * const argv[], Callbacks* callbacks) const AP::sitl()->init(); #endif // AP_SIM_ENABLED +#if AP_REBOOT_MASS_STORAGE_ENABLED && HAL_USB_MSD_BOOT_ENABLED + if (ChibiOS::usb_msd_boot_requested()) { + ChibiOS::usb_msd_run(); + } +#endif + #if HAL_USE_SERIAL_USB == TRUE usb_initialise(); #endif diff --git a/libraries/AP_HAL_ChibiOS/USB_MSD.cpp b/libraries/AP_HAL_ChibiOS/USB_MSD.cpp new file mode 100644 index 00000000000000..fc1d41cc99d2d5 --- /dev/null +++ b/libraries/AP_HAL_ChibiOS/USB_MSD.cpp @@ -0,0 +1,225 @@ +/* + * This file 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 file 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. + */ + +#include + +#if CONFIG_HAL_BOARD == HAL_BOARD_CHIBIOS + +#include "USB_MSD.h" + +#if AP_REBOOT_MASS_STORAGE_ENABLED && HAL_USB_MSD_BOOT_ENABLED + +#include +#include + +#include "hwdef/common/stm32_util.h" +#include "hwdef/common/watchdog.h" +#include "sdcard.h" +#include "shared_dma.h" + +#if !defined(STM32H7) && !defined(STM32F7) && !defined(STM32F4) +#error HAL_USB_MSD_BOOT_ENABLED is only supported on STM32H7, STM32F7 and STM32F4 +#endif + +#if HAL_USE_USB_MSD != TRUE || (HAL_USE_SDC != TRUE && HAL_USE_MMC_SPI != TRUE) || HAL_USE_SERIAL_USB != TRUE +#error HAL_USB_MSD_BOOT_ENABLED requires USB MSD, a microSD block device and USB support +#endif + +extern const AP_HAL::HAL& hal; + +namespace ChibiOS { + +static constexpr size_t USB_MSD_IO_SIZE = 4096; + +static const uint8_t device_descriptor_data[18] = { + USB_DESC_DEVICE( + 0x0110, + 0x00, + 0x00, + 0x00, + 0x40, + HAL_USB_VENDOR_ID, + HAL_USB_PRODUCT_ID, + 0x0200, + 0, + 1, + 0, + 1) +}; + +static const USBDescriptor device_descriptor = { + sizeof(device_descriptor_data), + device_descriptor_data +}; + +static const uint8_t configuration_descriptor_data[32] = { + USB_DESC_CONFIGURATION(32, 1, 1, 0, 0xC0, 50), + USB_DESC_INTERFACE(0, 0, 2, 0x08, 0x06, 0x50, 0), + USB_DESC_ENDPOINT(0x01, 0x02, 0x0040, 0), + USB_DESC_ENDPOINT(0x81, 0x02, 0x0040, 0) +}; + +static const USBDescriptor configuration_descriptor = { + sizeof(configuration_descriptor_data), + configuration_descriptor_data +}; + +static const uint8_t string0[] = { + USB_DESC_BYTE(4), + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), + USB_DESC_WORD(0x0409) +}; + +static const uint8_t product_string[] = { + USB_DESC_BYTE(36), USB_DESC_BYTE(USB_DESCRIPTOR_STRING), + 'A', 0, 'r', 0, 'd', 0, 'u', 0, 'P', 0, 'i', 0, 'l', 0, 'o', 0, 't', 0, + ' ', 0, 'S', 0, 'D', 0, ' ', 0, 'C', 0, 'a', 0, 'r', 0, 'd', 0 +}; + +static const USBDescriptor string_descriptors[] = { + { sizeof(string0), string0 }, + { sizeof(product_string), product_string } +}; + +static const USBDescriptor *get_descriptor(USBDriver *usbp, uint8_t type, + uint8_t index, uint16_t language) +{ + (void)usbp; + (void)language; + + switch (type) { + case USB_DESCRIPTOR_DEVICE: + return &device_descriptor; + case USB_DESCRIPTOR_CONFIGURATION: + return &configuration_descriptor; + case USB_DESCRIPTOR_STRING: + if (index < ARRAY_SIZE(string_descriptors)) { + return &string_descriptors[index]; + } + break; + } + return nullptr; +} + +static USBInEndpointState ep1_in_state; +static USBOutEndpointState ep1_out_state; + +static const USBEndpointConfig ep1_config = { + USB_EP_MODE_TYPE_BULK, + nullptr, + nullptr, + nullptr, + 0x0040, + 0x0040, + &ep1_in_state, + &ep1_out_state, + 2, + nullptr +}; + +static void usb_event(USBDriver *usbp, usbevent_t event) +{ + if (event != USB_EVENT_CONFIGURED) { + return; + } + + chSysLockFromISR(); + usbInitEndpointI(usbp, 1, &ep1_config); + chSysUnlockFromISR(); +} + +static const USBConfig usb_config = { + usb_event, + get_descriptor, + msd_request_hook, + nullptr +}; + +bool usb_msd_boot_requested() +{ + AP_HAL::Util::PersistentData persistent_data {}; + stm32_watchdog_load(reinterpret_cast(&persistent_data), + (sizeof(persistent_data) + 3) / 4); + if (!persistent_data.boot_to_mass_storage) { + return false; + } + persistent_data.boot_to_mass_storage = false; + stm32_watchdog_save(reinterpret_cast(&persistent_data), + (sizeof(persistent_data) + 3) / 4); + return true; +} + +void usb_msd_set_boot_request() +{ + hal.util->persistent_data.boot_to_mass_storage = true; + stm32_watchdog_save(reinterpret_cast(&hal.util->persistent_data), + (sizeof(hal.util->persistent_data) + 3) / 4); +} + +void usb_msd_run() +{ + peripheral_power_enable(); + +#if AP_HAL_SHARED_DMA_ENABLED + Shared_DMA::init(); +#endif + + // Mass-storage mode is dedicated to bulk transfers, so deliberately use + // no SD slowdown for maximum speed. Normal flight logging honours + // BRD_SD_SLOWDOWN for maximum robustness. + if (!sdcard_init_raw(0, 3)) { + return; + } + + auto *msdp = static_cast(calloc(1, sizeof(USBMassStorageDriver))); + auto *block_buffer = static_cast( + hal.util->malloc_type(USB_MSD_IO_SIZE * 2, AP_HAL::Util::MEM_FILESYSTEM)); + if (msdp == nullptr || block_buffer == nullptr) { + free(msdp); + hal.util->free_type(block_buffer, USB_MSD_IO_SIZE * 2, AP_HAL::Util::MEM_FILESYSTEM); + return; + } + +#if STM32_OTG2_IS_OTG1 + auto *usbp = &USBD2; +#else + auto *usbp = &USBD1; +#endif + + usbDisconnectBus(usbp); + chThdSleep(chTimeUS2I(1500)); + usbStart(usbp, &usb_config); + + msdObjectInit(msdp); + msdStart(msdp, usbp, sdcard_get_block_device(), + block_buffer, block_buffer + USB_MSD_IO_SIZE, USB_MSD_IO_SIZE, + nullptr, nullptr, nullptr, nullptr); + + usbConnectBus(usbp); + +#if !defined(DISABLE_WATCHDOG) + stm32_watchdog_init(); +#endif + // Mass-storage mode deliberately owns the SD card until power is removed; + // never return to the flight firmware while the USB host may retain access. + while (true) { +#if !defined(DISABLE_WATCHDOG) + stm32_watchdog_pat(); +#endif + chThdSleepMilliseconds(50); + } +} + +} + +#endif // AP_REBOOT_MASS_STORAGE_ENABLED && HAL_USB_MSD_BOOT_ENABLED +#endif // HAL_BOARD_CHIBIOS diff --git a/libraries/AP_HAL_ChibiOS/USB_MSD.h b/libraries/AP_HAL_ChibiOS/USB_MSD.h new file mode 100644 index 00000000000000..bb67d124b9da8b --- /dev/null +++ b/libraries/AP_HAL_ChibiOS/USB_MSD.h @@ -0,0 +1,15 @@ +#pragma once + +#ifndef HAL_USB_MSD_BOOT_ENABLED +#define HAL_USB_MSD_BOOT_ENABLED 0 +#endif + +namespace ChibiOS { + +#if AP_REBOOT_MASS_STORAGE_ENABLED && HAL_USB_MSD_BOOT_ENABLED +bool usb_msd_boot_requested(); +void usb_msd_set_boot_request(); +void usb_msd_run(); +#endif + +} diff --git a/libraries/AP_HAL_ChibiOS/Util.cpp b/libraries/AP_HAL_ChibiOS/Util.cpp index 31f57b9f76b673..b0a9382e6d8d55 100644 --- a/libraries/AP_HAL_ChibiOS/Util.cpp +++ b/libraries/AP_HAL_ChibiOS/Util.cpp @@ -60,6 +60,15 @@ extern AP_IOMCU iomcu; extern const AP_HAL::HAL& hal; using namespace ChibiOS; + +#if AP_REBOOT_MASS_STORAGE_ENABLED && HAL_USB_MSD_BOOT_ENABLED +bool Util::request_usb_msd() +{ + usb_msd_set_boot_request(); + return true; +} +#endif + #if CH_CFG_USE_HEAP == TRUE /** diff --git a/libraries/AP_HAL_ChibiOS/Util.h b/libraries/AP_HAL_ChibiOS/Util.h index 5eb2260db4d9d1..49a2567044fe64 100644 --- a/libraries/AP_HAL_ChibiOS/Util.h +++ b/libraries/AP_HAL_ChibiOS/Util.h @@ -19,6 +19,7 @@ #include #include "AP_HAL_ChibiOS_Namespace.h" #include "AP_HAL_ChibiOS.h" +#include "USB_MSD.h" #include #include @@ -67,6 +68,10 @@ class ChibiOS::Util : public AP_HAL::Util { // return true if the reason for the reboot was a watchdog reset bool was_watchdog_reset() const override; +#if AP_REBOOT_MASS_STORAGE_ENABLED && HAL_USB_MSD_BOOT_ENABLED + bool request_usb_msd() override; +#endif + #if CH_DBG_ENABLE_STACK_CHECK == TRUE // request information on running threads void thread_info(ExpandingString &str) override; @@ -135,9 +140,14 @@ class ChibiOS::Util : public AP_HAL::Util { FlashBootloader flash_bootloader() override; #endif - // stm32F4 and F7 have 20 total RTC backup registers. We use the first one for boot type - // flags, so 19 available for persistent data - static_assert(sizeof(persistent_data) <= 19*4, "watchdog persistent data too large"); + // STM32F4 has 20 total RTC backup registers. We use the first one for boot + // flags, leaving 19 registers for the common persistent data ABI. + static_assert(sizeof(persistent_data) == 19*4, + "watchdog persistent data layout changed"); + static_assert(offsetof(AP_HAL::Util::PersistentData, safety_state) == 74, + "watchdog persistent data layout changed"); + static_assert(offsetof(AP_HAL::Util::PersistentData, boot_to_dfu) == 75, + "bootloader persistent data layout changed"); #if HAL_ENABLE_SAVE_PERSISTENT_PARAMS // save/load key persistent parameters in bootloader sector diff --git a/libraries/AP_HAL_ChibiOS/hwdef/common/chibios_board.mk b/libraries/AP_HAL_ChibiOS/hwdef/common/chibios_board.mk index 610ccf11ae7dc1..2f0013736ba77f 100644 --- a/libraries/AP_HAL_ChibiOS/hwdef/common/chibios_board.mk +++ b/libraries/AP_HAL_ChibiOS/hwdef/common/chibios_board.mk @@ -279,3 +279,9 @@ ULIBS = # End of user defines ############################################################################## include $(HWDEF)/common/chibios_common.mk + +# ChibiOS intentionally fills the fixed-width USB MSD serial-number field +# without a trailing NUL. Limit the warning suppression to that source file. +ifeq ($(USE_USB_MSD),yes) +$(OBJDIR)/hal_usb_msd.o: CWARN += -Wno-unterminated-string-initialization +endif diff --git a/libraries/AP_HAL_ChibiOS/hwdef/common/stm32_util.h b/libraries/AP_HAL_ChibiOS/hwdef/common/stm32_util.h index 7d78d41b82b15b..21f137cafac46a 100644 --- a/libraries/AP_HAL_ChibiOS/hwdef/common/stm32_util.h +++ b/libraries/AP_HAL_ChibiOS/hwdef/common/stm32_util.h @@ -196,4 +196,3 @@ void stm32_disable_cm4_core(void); #ifdef __cplusplus } #endif - diff --git a/libraries/AP_HAL_ChibiOS/hwdef/scripts/chibios_hwdef.py b/libraries/AP_HAL_ChibiOS/hwdef/scripts/chibios_hwdef.py index 377ba8193fdb68..658700b37f2a54 100644 --- a/libraries/AP_HAL_ChibiOS/hwdef/scripts/chibios_hwdef.py +++ b/libraries/AP_HAL_ChibiOS/hwdef/scripts/chibios_hwdef.py @@ -56,10 +56,13 @@ class ChibiOSHWDef(hwdef.HWDef): UART_TYPE_RE = re.compile(r'UART(\d+)') UART_LABEL_RE = re.compile(r'UART(\d+)_(RX|TX|CTS|RTS|CTS_GPIO)') - def __init__(self, bootloader=False, signed_fw=False, default_params_filepath=None, **kwargs): + def __init__(self, bootloader=False, signed_fw=False, mass_storage_option=None, + default_params_filepath=None, **kwargs): super(ChibiOSHWDef, self).__init__(**kwargs) self.bootloader = bootloader self.signed_fw = signed_fw + self.mass_storage_option = mass_storage_option + self.usb_mass_storage_enabled = False self.default_params_filepath = default_params_filepath self.processed_defaults_filepath = None self.have_defaults_file = False @@ -1056,6 +1059,17 @@ def write_mcu_config(self, f): if 'OTG2' in self.bytype: f.write('#define STM32_USB_USE_OTG2 TRUE\n') + if self.is_normal_fw(): + f.write('#define AP_REBOOT_MASS_STORAGE_ENABLED %u\n' % self.usb_mass_storage_enabled) + if self.usb_mass_storage_enabled: + f.write(''' +#define HAL_USB_MSD_BOOT_ENABLED 1 +#define HAL_USE_USB_MSD TRUE +#define USB_MSD_THREAD_WA_SIZE 1024 +#define USB_USE_WAIT TRUE +''') + self.build_flags.append('USE_USB_MSD=yes') + if 'ETH1' in self.bytype: self.enable_networking(f) f.write(''' @@ -1116,14 +1130,13 @@ def write_mcu_config(self, f): if d.startswith('define '): if 'HAL_USE_CAN' in d: using_chibios_can = True + if d.split()[1] == 'AP_REBOOT_MASS_STORAGE_ENABLED': + continue f.write('#define %s\n' % d[7:]) if self.intdefines.get('AP_NETWORKING_ENABLED', 0) == 1: self.enable_networking(f) - if self.intdefines.get('HAL_USE_USB_MSD', 0) == 1: - self.build_flags.append('USE_USB_MSD=yes') - if self.have_type_prefix('CAN') and not using_chibios_can: self.enable_can(f) else: @@ -3055,7 +3068,7 @@ def add_firmware_defaults_from_file(self, f, filename, description): ''' % (description, content, description)) def is_io_fw(self): - return int(self.env_vars.get('IOMCU_FW', 0)) != 0 + return self.get_config('IOMCU_FW', default=0, required=False, type=int) != 0 def add_iomcu_firmware_defaults(self, f): '''add default defines IO firmwares''' @@ -3154,6 +3167,35 @@ def get_stale_defines(self): }) return ret + def setup_usb_mass_storage(self): + '''setup USB mass storage support''' + flash_size = self.get_config('FLASH_SIZE_KB', type=int) + ext_flash_size = self.get_config('EXT_FLASH_SIZE_MB', default=0, type=int) + program_size_limit = self.intdefines.get( + 'HAL_PROGRAM_SIZE_LIMIT_KB', flash_size + ext_flash_size * 1024) + mcu_defines = self.get_mcu_config('DEFINES', False) or {} + fastboot_enabled = self.intdefines.get( + 'AP_FASTBOOT_ENABLED', int(mcu_defines.get('AP_FASTBOOT_ENABLED', 1))) == 1 + default_mass_storage = (self.is_normal_fw() and + program_size_limit >= 2048 and fastboot_enabled) + mass_storage_option = self.mass_storage_option + if mass_storage_option is None: + mass_storage_option = self.intdefines.get('AP_REBOOT_MASS_STORAGE_ENABLED') + mass_storage_requested = (default_mass_storage if mass_storage_option is None else + bool(mass_storage_option)) + supported_mcu = self.mcu_series.startswith(('STM32F4', 'STM32F7', 'STM32H7')) + have_sdcard = (not self.dataflash_list and + (self.have_type_prefix('SDIO') or self.have_type_prefix('SDMMC') or + self.has_sdcard_spi())) + have_usb = 'OTG1' in self.bytype + self.usb_mass_storage_enabled = (self.is_normal_fw() and mass_storage_requested and + supported_mcu and fastboot_enabled and have_sdcard and have_usb) + if mass_storage_option is not None and mass_storage_option > 0 and not self.usb_mass_storage_enabled: + self.error('USB mass storage unavailable (requires normal STM32F4/F7/H7 firmware, ' + 'persistent reboot state, USB and microSD)') + if mass_storage_option is None and default_mass_storage and not self.usb_mass_storage_enabled: + self.progress('USB mass storage unavailable (requires STM32F4/F7/H7, USB and microSD)') + def run(self): # process input file self.process_hwdefs() @@ -3166,6 +3208,8 @@ def run(self): self.mcu_type = self.get_config('MCU', 1) self.progress("Setup for MCU %s" % self.mcu_type) + self.setup_usb_mass_storage() + # put USE_BOOTLOADER_FROM_BOARD into the environment so the # build process can use it when generating hex files: use_bootloader_from_board = self.get_config('USE_BOOTLOADER_FROM_BOARD', default=None, required=False) diff --git a/libraries/AP_HAL_ChibiOS/hwdef/scripts/defaults_bootloader.h b/libraries/AP_HAL_ChibiOS/hwdef/scripts/defaults_bootloader.h index 8600cb4b513d5b..809187ed6df93e 100644 --- a/libraries/AP_HAL_ChibiOS/hwdef/scripts/defaults_bootloader.h +++ b/libraries/AP_HAL_ChibiOS/hwdef/scripts/defaults_bootloader.h @@ -4,6 +4,7 @@ #define HAL_DSHOT_ALARM_ENABLED 0 #define HAL_LOGGING_ENABLED 0 #define HAL_SCHEDULER_ENABLED 0 +#define AP_REBOOT_MASS_STORAGE_ENABLED 0 // bootloaders *definitely* don't use the FFT library: #ifndef HAL_GYROFFT_ENABLED diff --git a/libraries/AP_HAL_ChibiOS/hwdef/scripts/defaults_iofirmware.h b/libraries/AP_HAL_ChibiOS/hwdef/scripts/defaults_iofirmware.h index 7e3ed4765b7135..69dc8e91a3b5b9 100644 --- a/libraries/AP_HAL_ChibiOS/hwdef/scripts/defaults_iofirmware.h +++ b/libraries/AP_HAL_ChibiOS/hwdef/scripts/defaults_iofirmware.h @@ -1,6 +1,8 @@ // this file is inserted (by chibios_hwdef.py) into hwdef.h when // configuring for iofirmware builds +#define AP_REBOOT_MASS_STORAGE_ENABLED 0 + #define HAL_DSHOT_ALARM_ENABLED 0 #define HAL_LOGGING_ENABLED 0 diff --git a/libraries/AP_HAL_ChibiOS/hwdef/scripts/defaults_periph.h b/libraries/AP_HAL_ChibiOS/hwdef/scripts/defaults_periph.h index f1cf94be4ae9df..9a4dbf6d35fff8 100644 --- a/libraries/AP_HAL_ChibiOS/hwdef/scripts/defaults_periph.h +++ b/libraries/AP_HAL_ChibiOS/hwdef/scripts/defaults_periph.h @@ -1,6 +1,8 @@ // this file is inserted (by chibios_hwdef.py) into hwdef.h when // configuring for AP_Periph builds +#define AP_REBOOT_MASS_STORAGE_ENABLED 0 + #ifndef AP_SCHEDULER_ENABLED #define AP_SCHEDULER_ENABLED 0 #endif diff --git a/libraries/AP_HAL_ChibiOS/sdcard.cpp b/libraries/AP_HAL_ChibiOS/sdcard.cpp index e57d0461c1521e..e9b8f0c9cdbd6c 100644 --- a/libraries/AP_HAL_ChibiOS/sdcard.cpp +++ b/libraries/AP_HAL_ChibiOS/sdcard.cpp @@ -47,21 +47,10 @@ static SPIConfig lowspeed; static SPIConfig highspeed; #endif -/* - initialise microSD card if avaialble. This is called during - AP_BoardConfig initialisation. The parameter BRD_SD_SLOWDOWN - controls a scaling factor on the microSD clock - */ -bool sdcard_init() +// initialise the microSD block device without mounting its filesystem +bool sdcard_init_raw(uint8_t sd_slowdown, uint8_t tries) { #if HAL_USE_FATFS -#ifndef HAL_BOOTLOADER_BUILD - WITH_SEMAPHORE(sem); - - uint8_t sd_slowdown = AP_BoardConfig::get_sdcard_slowdown(); -#else - uint8_t sd_slowdown = 0; // maybe take from a define? -#endif #if HAL_USE_SDC #if STM32_SDC_USE_SDMMC2 == TRUE @@ -102,7 +91,6 @@ bool sdcard_init() sdcard_stop(); } - const uint8_t tries = 3; for (uint8_t i=0; i(&SDCD2); +#else + return reinterpret_cast(&SDCD1); +#endif +#elif HAL_USE_MMC_SPI + return reinterpret_cast(&MMCD1); +#else + return nullptr; +#endif +} + +bool sdcard_init() +{ +#if HAL_USE_FATFS +#ifndef HAL_BOOTLOADER_BUILD + WITH_SEMAPHORE(sem); + const uint8_t sd_slowdown = AP_BoardConfig::get_sdcard_slowdown(); +#else + const uint8_t sd_slowdown = 0; +#endif + + for (uint8_t i = 0; i < 3; i++) { + if (!sdcard_init_raw(sd_slowdown, 1)) { + continue; + } + if (f_mount(&SDC_FS, "/", 1) == FR_OK) { + printf("Successfully mounted SDCard (slowdown=%u)\n", (unsigned)sd_slowdown); + return true; + } + sdcard_stop(); + } +#endif + return false; +} + /* stop sdcard interface (for reboot) */ diff --git a/libraries/AP_HAL_ChibiOS/sdcard.h b/libraries/AP_HAL_ChibiOS/sdcard.h index 50c3c55e49b921..ddecb95d74843a 100644 --- a/libraries/AP_HAL_ChibiOS/sdcard.h +++ b/libraries/AP_HAL_ChibiOS/sdcard.h @@ -15,13 +15,15 @@ */ #pragma once -#include +#include namespace AP_HAL { class SPIDevice; } bool sdcard_init(); +bool sdcard_init_raw(uint8_t slowdown, uint8_t tries); +BaseBlockDevice *sdcard_get_block_device(); void sdcard_stop(); bool sdcard_retry(); AP_HAL::SPIDevice *sdcard_get_spi_device(); diff --git a/libraries/GCS_MAVLink/GCS_Common.cpp b/libraries/GCS_MAVLink/GCS_Common.cpp index 570fd7a99c6519..a90eeb0186d207 100644 --- a/libraries/GCS_MAVLink/GCS_Common.cpp +++ b/libraries/GCS_MAVLink/GCS_Common.cpp @@ -3653,6 +3653,20 @@ MAV_RESULT GCS_MAVLINK::handle_preflight_reboot(const mavlink_command_int_t &pac #endif } + const bool reboot = is_equal(packet.param1, static_cast(REBOOT_SHUTDOWN_ACTION_REBOOT)); + const bool reboot_to_bootloader = is_equal(packet.param1, + static_cast(REBOOT_SHUTDOWN_ACTION_REBOOT_TO_BOOTLOADER)); + +#if AP_REBOOT_MASS_STORAGE_ENABLED + const bool reboot_to_mass_storage = is_equal(packet.param1, + static_cast(REBOOT_SHUTDOWN_ACTION_REBOOT_TO_MASS_STORAGE)); + + // exporting writable storage must never be entered while armed + if (reboot_to_mass_storage && hal.util->get_soft_armed()) { + return MAV_RESULT_FAILED; + } +#endif + // refuse reboot when armed: if (hal.util->get_soft_armed()) { /// but allow it if forced: @@ -3662,10 +3676,21 @@ MAV_RESULT GCS_MAVLINK::handle_preflight_reboot(const mavlink_command_int_t &pac } } - if (!(is_equal(packet.param1, 1.0f) || is_equal(packet.param1, 3.0f))) { - // param1 must be 1 or 3 - 1 being reboot, 3 being reboot-to-bootloader +#if AP_REBOOT_MASS_STORAGE_ENABLED + const bool supported_reboot_action = reboot || reboot_to_bootloader || reboot_to_mass_storage; +#else + const bool supported_reboot_action = reboot || reboot_to_bootloader; +#endif + if (!supported_reboot_action) { + // param1 must select a supported reboot action + return MAV_RESULT_UNSUPPORTED; + } + +#if AP_REBOOT_MASS_STORAGE_ENABLED + if (reboot_to_mass_storage && !hal.util->request_usb_msd()) { return MAV_RESULT_UNSUPPORTED; } +#endif #if CONFIG_HAL_BOARD == HAL_BOARD_SITL { // autotest relies in receiving the ACK for the reboot. Ensure @@ -3686,13 +3711,10 @@ MAV_RESULT GCS_MAVLINK::handle_preflight_reboot(const mavlink_command_int_t &pac msg.sysid, msg.compid); - // when packet.param1 == 3 we reboot to hold in bootloader - const bool hold_in_bootloader = is_equal(packet.param1, 3.0f); - #if AP_VEHICLE_ENABLED - AP::vehicle()->reboot(hold_in_bootloader); // not expected to return + AP::vehicle()->reboot(reboot_to_bootloader); // not expected to return #else - hal.scheduler->reboot(hold_in_bootloader); + hal.scheduler->reboot(reboot_to_bootloader); #endif return MAV_RESULT_FAILED; diff --git a/modules/ChibiOS b/modules/ChibiOS index b8f4f3c03d70c6..9aebaf4a404422 160000 --- a/modules/ChibiOS +++ b/modules/ChibiOS @@ -1 +1 @@ -Subproject commit b8f4f3c03d70c65a09c77c2199204a02c20af4d4 +Subproject commit 9aebaf4a40442277d01bd9dd38c13713fc45ef41