diff options
| author | sakumisu <[email protected]> | 2025-04-29 18:28:30 +0800 |
|---|---|---|
| committer | sakumisu <[email protected]> | 2025-04-30 10:11:04 +0800 |
| commit | c27458d71aaf7f46744e75082251e4a570517b1f (patch) | |
| tree | 438df0e681e2636270b5023d83750988b7ae9e16 /platform | |
| parent | 644ac2b37f13218042e6c4040de3537d3db2e05c (diff) | |
update(platform): update platform code
Signed-off-by: sakumisu <[email protected]>
Diffstat (limited to 'platform')
| -rw-r--r-- | platform/README.md | 58 | ||||
| -rw-r--r-- | platform/blackmagic/bmp_port_cdc_acm.c | 294 | ||||
| -rw-r--r-- | platform/daplink/dap_main.c | 553 | ||||
| -rw-r--r-- | platform/daplink/dap_main.h | 151 | ||||
| -rw-r--r-- | platform/fatfs/usbh_fatfs.c (renamed from platform/none/usbh_fatfs.c) | 0 | ||||
| -rw-r--r-- | platform/lwip/usbh_lwip.c (renamed from platform/none/usbh_lwip.c) | 0 | ||||
| -rw-r--r-- | platform/qmk/.gitkeep | 1 | ||||
| -rw-r--r-- | platform/uf2/bootuf2.c | 463 | ||||
| -rw-r--r-- | platform/uf2/bootuf2.h | 218 |
9 files changed, 1728 insertions, 10 deletions
diff --git a/platform/README.md b/platform/README.md index a6afc93e..74b3f0f8 100644 --- a/platform/README.md +++ b/platform/README.md @@ -1,14 +1,52 @@ # Platform Support -This is a platform support for other os with their own components. +This is a platform support for other opensource projects. -| Platform | fs | net | serial | -|:---------:|:------------:|:------------:|:------------:| -|none | fatfs | lwip | none | -|rtthread | dfs | lwip | rt_device | -|nuttx | nuttx block driver | nuttx net | nuttx char driver| -|threadx | filex | netx | none | -- **fs** is for usbd_msc and usbh_msc -- **net** is for cdc_ecm, cdc_rndis, cdc_ncm, asix, rtl8152 and so on. -- **serial** is for cdc_acm, ch340, ftdi, cp210x, pl2303 and so on.
\ No newline at end of file +## Fatfs + +Fatfs support with usb host msc. + +## lwip + +lwip support with usb host net class(cdc_ecm/cdc_ncm/cdc_rndis/asix/rtl8152/bl616_wifi). + +## RT-Thread + +- rt_device support with usb device msc. +- DFS support with usb host msc. +- lwip support with usb host net class(cdc_ecm/cdc_ncm/cdc_rndis/asix/rtl8152/bl616_wifi). +- msh support with lsusb + + +## Nuttx + +- char device support fowithr usb device cdc acm. +- char device support with usb host cdc acm. +- fs support with usb device msc. +- fs support with usb host msc. +- net support with usb host net class(cdc_rndis). + +## Threadx + +- filx support with usb host msc. + +## LVGL + +- lvgl index support with usb host mouse and keyboard. + +## Blackmagic + +Blackmagic support with usb device cdc acm. + +## DAPLINK + +DAPLINK v2.1 support with usb device cdc acm + winusb(hid and msc optional). + +## UF2 + +UF2 support with usb device msc. + +## QMK + +QMK support with usb device hid.
\ No newline at end of file diff --git a/platform/blackmagic/bmp_port_cdc_acm.c b/platform/blackmagic/bmp_port_cdc_acm.c new file mode 100644 index 00000000..ae4e5457 --- /dev/null +++ b/platform/blackmagic/bmp_port_cdc_acm.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2025, A_Stupid_Liberal + * Copyright (c) 2025, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "usbd_core.h" +#include "usbd_cdc_acm.h" +#include "general.h" +#include "gdb_if.h" +#include "hpm_l1c_drv.h" + +#define CDC_IN_EP 0x81 +#define CDC_OUT_EP 0x01 +#define CDC_INT_EP 0x83 + +#define CDC_MAX_PACKET_SIZE 512 + +#ifdef CONFIG_USB_HS +#if CDC_MAX_PACKET_SIZE != 512 +#error "CDC_MAX_PACKET_SIZE must be 512 in hs" +#endif +#else +#if CDC_MAX_PACKET_SIZE != 64 +#error "CDC_MAX_PACKET_SIZE must be 64 in fs" +#endif +#endif + +/*!< config descriptor size */ +#define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN) + +static const uint8_t device_descriptor[] = { + USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01) +}; + +static const uint8_t config_descriptor_hs[] = { + USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), + CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02), +}; + +static const uint8_t config_descriptor_fs[] = { + USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), + CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02), +}; + +static const uint8_t device_quality_descriptor[] = { + USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, 0x01), +}; + +static const uint8_t other_speed_config_descriptor_hs[] = { + USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), + CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_FS, 0x02), +}; + +static const uint8_t other_speed_config_descriptor_fs[] = { + USB_OTHER_SPEED_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), + CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, USB_BULK_EP_MPS_HS, 0x02), +}; + +static const char *string_descriptors[] = { + (const char[]){ 0x09, 0x04 }, /* Langid */ + "CherryUSB", /* Manufacturer */ + "CherryUSB BMP DEMO", /* Product */ + "20250501", /* Serial Number */ +}; + +static const uint8_t *device_descriptor_callback(uint8_t speed) +{ + (void)speed; + + return device_descriptor; +} + +static const uint8_t *config_descriptor_callback(uint8_t speed) +{ + if (speed == USB_SPEED_HIGH) { + return config_descriptor_hs; + } else if (speed == USB_SPEED_FULL) { + return config_descriptor_fs; + } else { + return NULL; + } +} + +static const uint8_t *device_quality_descriptor_callback(uint8_t speed) +{ + (void)speed; + + return device_quality_descriptor; +} + +static const uint8_t *other_speed_config_descriptor_callback(uint8_t speed) +{ + if (speed == USB_SPEED_HIGH) { + return other_speed_config_descriptor_hs; + } else if (speed == USB_SPEED_FULL) { + return other_speed_config_descriptor_fs; + } else { + return NULL; + } +} + +static const char *string_descriptor_callback(uint8_t speed, uint8_t index) +{ + (void)speed; + + if (index >= (sizeof(string_descriptors) / sizeof(char *))) { + return NULL; + } + return string_descriptors[index]; +} + +const struct usb_descriptor cdc_descriptor = { + .device_descriptor_callback = device_descriptor_callback, + .config_descriptor_callback = config_descriptor_callback, + .device_quality_descriptor_callback = device_quality_descriptor_callback, + .other_speed_descriptor_callback = other_speed_config_descriptor_callback, + .string_descriptor_callback = string_descriptor_callback, +}; + +#define USB_RX_BUFFER_SIZE 16384 +__attribute__((aligned(64))) uint8_t g_usb_write_buffer[USB_RX_BUFFER_SIZE]; +__attribute__((aligned(64))) uint8_t g_usb_read_buffer[USB_RX_BUFFER_SIZE]; + +volatile bool g_usb_tx_busy_flag = false; +volatile uint32_t g_usb_tx_count = 0; +volatile uint32_t g_usb_rx_count = 0; +volatile uint32_t g_usb_rx_offset = 0; + +static void usbd_event_handler(uint8_t busid, uint8_t event) +{ + switch (event) { + case USBD_EVENT_RESET: + g_usb_tx_busy_flag = false; + g_usb_rx_offset = 0; + g_usb_rx_count = 0; + g_usb_tx_count = 0; + break; + case USBD_EVENT_CONNECTED: + break; + case USBD_EVENT_DISCONNECTED: + g_usb_tx_busy_flag = false; + g_usb_rx_offset = 0; + g_usb_rx_count = 0; + g_usb_tx_count = 0; + break; + case USBD_EVENT_RESUME: + break; + case USBD_EVENT_SUSPEND: + break; + case USBD_EVENT_CONFIGURED: + /* setup first out ep read transfer */ + usbd_ep_start_read(busid, CDC_OUT_EP, g_usb_read_buffer, USB_RX_BUFFER_SIZE); + break; + case USBD_EVENT_SET_REMOTE_WAKEUP: + break; + case USBD_EVENT_CLR_REMOTE_WAKEUP: + break; + + default: + break; + } +} + +void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + (void)busid; + + usb_dcache_invalidate((uint32_t)g_usb_read_buffer, USB_ALIGN_UP(nbytes, 64)); + g_usb_rx_count = nbytes; + g_usb_rx_offset = 0; +} + +void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + (void)busid; + + if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) { + /* send zlp */ + usbd_ep_start_write(busid, CDC_IN_EP, NULL, 0); + } else { + g_usb_tx_busy_flag = false; + } +} + +/*!< endpoint call back */ +struct usbd_endpoint cdc_out_ep = { + .ep_addr = CDC_OUT_EP, + .ep_cb = usbd_cdc_acm_bulk_out +}; + +struct usbd_endpoint cdc_in_ep = { + .ep_addr = CDC_IN_EP, + .ep_cb = usbd_cdc_acm_bulk_in +}; + +static struct usbd_interface intf0; +static struct usbd_interface intf1; + +/* function ------------------------------------------------------------------*/ + +void cdc_acm_init(uint8_t busid, uint32_t reg_base) +{ + usbd_desc_register(busid, &cdc_descriptor); + usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf0)); + usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf1)); + usbd_add_endpoint(busid, &cdc_out_ep); + usbd_add_endpoint(busid, &cdc_in_ep); + usbd_initialize(busid, reg_base, usbd_event_handler); +} + +volatile bool dtr_enable = false; + +void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr) +{ + if (dtr) { + //printf("remote attach \r\n"); + } else { + //printf("remote detach \r\n"); + } + + dtr_enable = dtr; +} + +void gdb_if_putchar(const char c, const bool flush) +{ + g_usb_write_buffer[g_usb_tx_count++] = c; + + if (flush) { + g_usb_tx_busy_flag = true; + usb_dcache_clean((uint32_t)g_usb_write_buffer, USB_ALIGN_UP(g_usb_tx_count, 64)); + usbd_ep_start_write(0, CDC_IN_EP, (uint8_t *)core_local_mem_to_sys_address(0, (uint32_t)g_usb_write_buffer), g_usb_tx_count); + while (g_usb_tx_busy_flag) { + } + g_usb_tx_count = 0; + } +} + +void gdb_if_flush(const bool force) +{ + g_usb_tx_busy_flag = true; + usb_dcache_clean((uint32_t)g_usb_write_buffer, USB_ALIGN_UP(g_usb_tx_count, 64)); + usbd_ep_start_write(0, CDC_IN_EP, (uint8_t *)core_local_mem_to_sys_address(0, (uint32_t)g_usb_write_buffer), g_usb_tx_count); + while (g_usb_tx_busy_flag) { + } + g_usb_tx_count = 0; +} + +static int __gdb_if_getchar(void) +{ + if (dtr_enable == false) { + return '\04'; + } + + if (g_usb_rx_count > 0) { + if (g_usb_rx_offset < g_usb_rx_count) { + return g_usb_read_buffer[g_usb_rx_offset++]; + } else { + g_usb_rx_count = 0; + /* setup first out ep read transfer */ + usbd_ep_start_read(0, CDC_OUT_EP, g_usb_read_buffer, USB_RX_BUFFER_SIZE); + return -1; + } + } else { + return -1; + } +} + +char gdb_if_getchar(void) +{ + int c; + + while ((c = __gdb_if_getchar()) == -1) { + } + + return (char)c; +} + +char gdb_if_getchar_to(const uint32_t timeout) +{ + int c = 0; + platform_timeout_s receive_timeout; + platform_timeout_set(&receive_timeout, timeout); + + /* Wait while we need more data or until the timeout expires */ + while (!platform_timeout_is_expired(&receive_timeout)) { + c = __gdb_if_getchar(); + if (c != -1) { + return (char)c; + } + } + return -1; +}
\ No newline at end of file diff --git a/platform/daplink/dap_main.c b/platform/daplink/dap_main.c new file mode 100644 index 00000000..f977cffd --- /dev/null +++ b/platform/daplink/dap_main.c @@ -0,0 +1,553 @@ +/* + * Copyright (c) 2023 ~ 2025, sakumisu + * Copyright (c) 2023 ~ 2025, HalfSweet + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "dap_main.h" +#include "DAP_config.h" +#include "DAP.h" + +#define USB_CONFIG_SIZE (9 + CMSIS_DAP_INTERFACE_SIZE + CDC_ACM_DESCRIPTOR_LEN + CONFIG_MSC_DESCRIPTOR_LEN) +#define INTF_NUM (2 + 1 + CONFIG_MSC_INTF_NUM) + +__ALIGN_BEGIN const uint8_t USBD_WinUSBDescriptorSetDescriptor[] = { + WBVAL(WINUSB_DESCRIPTOR_SET_HEADER_SIZE), /* wLength */ + WBVAL(WINUSB_SET_HEADER_DESCRIPTOR_TYPE), /* wDescriptorType */ + 0x00, 0x00, 0x03, 0x06, /* >= Win 8.1 */ /* dwWindowsVersion*/ + WBVAL(USBD_WINUSB_DESC_SET_LEN), /* wDescriptorSetTotalLength */ +#if (USBD_WEBUSB_ENABLE) + WBVAL(WINUSB_FUNCTION_SUBSET_HEADER_SIZE), // wLength + WBVAL(WINUSB_SUBSET_HEADER_FUNCTION_TYPE), // wDescriptorType + 0, // bFirstInterface USBD_WINUSB_IF_NUM + 0, // bReserved + WBVAL(FUNCTION_SUBSET_LEN), // wSubsetLength + WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_SIZE), // wLength + WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_TYPE), // wDescriptorType + 'W', 'I', 'N', 'U', 'S', 'B', 0, 0, // CompatibleId + 0, 0, 0, 0, 0, 0, 0, 0, // SubCompatibleId + WBVAL(DEVICE_INTERFACE_GUIDS_FEATURE_LEN), // wLength + WBVAL(WINUSB_FEATURE_REG_PROPERTY_TYPE), // wDescriptorType + WBVAL(WINUSB_PROP_DATA_TYPE_REG_MULTI_SZ), // wPropertyDataType + WBVAL(42), // wPropertyNameLength + 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, + 'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0, + 'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0, + WBVAL(80), // wPropertyDataLength + '{', 0, + '9', 0, '2', 0, 'C', 0, 'E', 0, '6', 0, '4', 0, '6', 0, '2', 0, '-', 0, + '9', 0, 'C', 0, '7', 0, '7', 0, '-', 0, + '4', 0, '6', 0, 'F', 0, 'E', 0, '-', 0, + '9', 0, '3', 0, '3', 0, 'B', 0, '-', + 0, '3', 0, '1', 0, 'C', 0, 'B', 0, '9', 0, 'C', 0, '5', 0, 'A', 0, 'A', 0, '3', 0, 'B', 0, '9', 0, + '}', 0, 0, 0, 0, 0 +#endif +#if USBD_BULK_ENABLE + WBVAL(WINUSB_FUNCTION_SUBSET_HEADER_SIZE), /* wLength */ + WBVAL(WINUSB_SUBSET_HEADER_FUNCTION_TYPE), /* wDescriptorType */ + 0, /* bFirstInterface USBD_BULK_IF_NUM*/ + 0, /* bReserved */ + WBVAL(FUNCTION_SUBSET_LEN), /* wSubsetLength */ + WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_SIZE), /* wLength */ + WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_TYPE), /* wDescriptorType */ + 'W', 'I', 'N', 'U', 'S', 'B', 0, 0, /* CompatibleId*/ + 0, 0, 0, 0, 0, 0, 0, 0, /* SubCompatibleId*/ + WBVAL(DEVICE_INTERFACE_GUIDS_FEATURE_LEN), /* wLength */ + WBVAL(WINUSB_FEATURE_REG_PROPERTY_TYPE), /* wDescriptorType */ + WBVAL(WINUSB_PROP_DATA_TYPE_REG_MULTI_SZ), /* wPropertyDataType */ + WBVAL(42), /* wPropertyNameLength */ + 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, + 'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0, + 'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0, + WBVAL(80), /* wPropertyDataLength */ + '{', 0, + 'C', 0, 'D', 0, 'B', 0, '3', 0, 'B', 0, '5', 0, 'A', 0, 'D', 0, '-', 0, + '2', 0, '9', 0, '3', 0, 'B', 0, '-', 0, + '4', 0, '6', 0, '6', 0, '3', 0, '-', 0, + 'A', 0, 'A', 0, '3', 0, '6', 0, '-', + 0, '1', 0, 'A', 0, 'A', 0, 'E', 0, '4', 0, '6', 0, '4', 0, '6', 0, '3', 0, '7', 0, '7', 0, '6', 0, + '}', 0, 0, 0, 0, 0 +#endif +}; + +__ALIGN_BEGIN const uint8_t USBD_BinaryObjectStoreDescriptor[] = { + 0x05, /* bLength */ + 0x0f, /* bDescriptorType */ + WBVAL(USBD_BOS_WTOTALLENGTH), /* wTotalLength */ + USBD_NUM_DEV_CAPABILITIES, /* bNumDeviceCaps */ +#if (USBD_WEBUSB_ENABLE) + USBD_WEBUSB_DESC_LEN, /* bLength */ + 0x10, /* bDescriptorType */ + USB_DEVICE_CAPABILITY_PLATFORM, /* bDevCapabilityType */ + 0x00, /* bReserved */ + 0x38, 0xB6, 0x08, 0x34, /* PlatformCapabilityUUID */ + 0xA9, 0x09, 0xA0, 0x47, + 0x8B, 0xFD, 0xA0, 0x76, + 0x88, 0x15, 0xB6, 0x65, + WBVAL(0x0100), /* 1.00 */ /* bcdVersion */ + USBD_WINUSB_VENDOR_CODE, /* bVendorCode */ + 0, /* iLandingPage */ +#endif +#if (USBD_WINUSB_ENABLE) + USBD_WINUSB_DESC_LEN, /* bLength */ + 0x10, /* bDescriptorType */ + USB_DEVICE_CAPABILITY_PLATFORM, /* bDevCapabilityType */ + 0x00, /* bReserved */ + 0xDF, 0x60, 0xDD, 0xD8, /* PlatformCapabilityUUID */ + 0x89, 0x45, 0xC7, 0x4C, + 0x9C, 0xD2, 0x65, 0x9D, + 0x9E, 0x64, 0x8A, 0x9F, + 0x00, 0x00, 0x03, 0x06, /* >= Win 8.1 */ /* dwWindowsVersion*/ + WBVAL(USBD_WINUSB_DESC_SET_LEN), /* wDescriptorSetTotalLength */ + USBD_WINUSB_VENDOR_CODE, /* bVendorCode */ + 0, /* bAltEnumCode */ +#endif +}; + +static const uint8_t device_descriptor[] = { + USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01), +}; + +static const uint8_t config_descriptor[] = { + USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), + /* Interface 0 */ + USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02), + /* Endpoint OUT 2 */ + USB_ENDPOINT_DESCRIPTOR_INIT(DAP_OUT_EP, USB_ENDPOINT_TYPE_BULK, DAP_PACKET_SIZE, 0x00), + /* Endpoint IN 1 */ + USB_ENDPOINT_DESCRIPTOR_INIT(DAP_IN_EP, USB_ENDPOINT_TYPE_BULK, DAP_PACKET_SIZE, 0x00), + CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, DAP_PACKET_SIZE, 0x00), +#ifdef CONFIG_CHERRYDAP_USE_MSC + MSC_DESCRIPTOR_INIT(MSC_INTF_NUM, MSC_OUT_EP, MSC_IN_EP, DAP_PACKET_SIZE, 0x00), +#endif +}; + +static const uint8_t other_speed_config_descriptor[] = { + USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTF_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), + /* Interface 0 */ + USB_INTERFACE_DESCRIPTOR_INIT(0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x02), + /* Endpoint OUT 2 */ + USB_ENDPOINT_DESCRIPTOR_INIT(DAP_OUT_EP, USB_ENDPOINT_TYPE_BULK, DAP_PACKET_SIZE, 0x00), + /* Endpoint IN 1 */ + USB_ENDPOINT_DESCRIPTOR_INIT(DAP_IN_EP, USB_ENDPOINT_TYPE_BULK, DAP_PACKET_SIZE, 0x00), + CDC_ACM_DESCRIPTOR_INIT(0x01, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, DAP_PACKET_SIZE, 0x00), +#ifdef CONFIG_CHERRYDAP_USE_MSC + MSC_DESCRIPTOR_INIT(MSC_INTF_NUM, MSC_OUT_EP, MSC_IN_EP, DAP_PACKET_SIZE, 0x00), +#endif +}; + +char *string_descriptors[] = { + (char[]) {0x09, 0x04}, /* Langid */ + "CherryUSB", /* Manufacturer */ + "CherryUSB CMSIS-DAP", /* Product */ + "00000000000000000123456789ABCDEF", /* Serial Number */ +}; + +static const uint8_t device_quality_descriptor[] = { + USB_DEVICE_QUALIFIER_DESCRIPTOR_INIT(USB_2_1, 0x00, 0x00, 0x00, 0x01), +}; + +__WEAK const uint8_t *device_descriptor_callback(uint8_t speed) +{ + (void) speed; + return device_descriptor; +} + +__WEAK const uint8_t *config_descriptor_callback(uint8_t speed) +{ + (void) speed; + return config_descriptor; +} + +__WEAK const uint8_t *device_quality_descriptor_callback(uint8_t speed) +{ + (void) speed; + return device_quality_descriptor; +} + +__WEAK const uint8_t *other_speed_config_descriptor_callback(uint8_t speed) +{ + (void) speed; + return other_speed_config_descriptor; +} + +__WEAK const char *string_descriptor_callback(uint8_t speed, uint8_t index) +{ + (void) speed; + + if (index >= (sizeof(string_descriptors) / sizeof(char *))) { + return NULL; + } + return string_descriptors[index]; +} + +static volatile uint16_t USB_RequestIndexI = 0; // Request Index In +static volatile uint16_t USB_RequestIndexO = 0; // Request Index Out +static volatile uint16_t USB_RequestCountI = 0; // Request Count In +static volatile uint16_t USB_RequestCountO = 0; // Request Count Out +static volatile uint8_t USB_RequestIdle = 1; // Request Idle Flag + +static volatile uint16_t USB_ResponseIndexI = 0; // Response Index In +static volatile uint16_t USB_ResponseIndexO = 0; // Response Index Out +static volatile uint16_t USB_ResponseCountI = 0; // Response Count In +static volatile uint16_t USB_ResponseCountO = 0; // Response Count Out +static volatile uint8_t USB_ResponseIdle = 1; // Response Idle Flag + +static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t USB_Request[DAP_PACKET_COUNT][DAP_PACKET_SIZE]; // Request Buffer +static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t USB_Response[DAP_PACKET_COUNT][DAP_PACKET_SIZE]; // Response Buffer +static uint16_t USB_RespSize[DAP_PACKET_COUNT]; // Response Size + +volatile struct cdc_line_coding g_cdc_lincoding; +volatile uint8_t config_uart = 0; +volatile uint8_t config_uart_transfer = 0; + +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t uartrx_ringbuffer[CONFIG_UARTRX_RINGBUF_SIZE]; +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t usbrx_ringbuffer[CONFIG_USBRX_RINGBUF_SIZE]; +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t usb_tmpbuffer[DAP_PACKET_SIZE]; + +static volatile uint8_t usbrx_idle_flag = 0; +static volatile uint8_t usbtx_idle_flag = 0; +static volatile uint8_t uarttx_idle_flag = 0; + +USB_NOCACHE_RAM_SECTION chry_ringbuffer_t g_uartrx; +USB_NOCACHE_RAM_SECTION chry_ringbuffer_t g_usbrx; + +void usbd_event_handler(uint8_t busid, uint8_t event) +{ + (void) busid; + switch (event) { + case USBD_EVENT_RESET: + usbrx_idle_flag = 0; + usbtx_idle_flag = 0; + uarttx_idle_flag = 0; + config_uart_transfer = 0; + break; + case USBD_EVENT_CONNECTED: + break; + case USBD_EVENT_DISCONNECTED: + break; + case USBD_EVENT_RESUME: + break; + case USBD_EVENT_SUSPEND: + break; + case USBD_EVENT_CONFIGURED: + /* setup first out ep read transfer */ + USB_RequestIdle = 0U; + + usbd_ep_start_read(0, DAP_OUT_EP, USB_Request[0], DAP_PACKET_SIZE); + usbd_ep_start_read(0, CDC_OUT_EP, usb_tmpbuffer, DAP_PACKET_SIZE); + + break; + case USBD_EVENT_SET_REMOTE_WAKEUP: + break; + case USBD_EVENT_CLR_REMOTE_WAKEUP: + break; + + default: + break; + } +} + +void dap_out_callback(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + (void) busid; + if (USB_Request[USB_RequestIndexI][0] == ID_DAP_TransferAbort) { + DAP_TransferAbort = 1U; + } else { + USB_RequestIndexI++; + if (USB_RequestIndexI == DAP_PACKET_COUNT) { + USB_RequestIndexI = 0U; + } + USB_RequestCountI++; + } + + // Start reception of next request packet + if ((uint16_t) (USB_RequestCountI - USB_RequestCountO) != DAP_PACKET_COUNT) { + usbd_ep_start_read(0, DAP_OUT_EP, USB_Request[USB_RequestIndexI], DAP_PACKET_SIZE); + } else { + USB_RequestIdle = 1U; + } +} + +void dap_in_callback(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + (void) busid; + if (USB_ResponseCountI != USB_ResponseCountO) { + // Load data from response buffer to be sent back + usbd_ep_start_write(0, DAP_IN_EP, USB_Response[USB_ResponseIndexO], USB_RespSize[USB_ResponseIndexO]); + USB_ResponseIndexO++; + if (USB_ResponseIndexO == DAP_PACKET_COUNT) { + USB_ResponseIndexO = 0U; + } + USB_ResponseCountO++; + } else { + USB_ResponseIdle = 1U; + } +} + +void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + (void) busid; + chry_ringbuffer_write(&g_usbrx, usb_tmpbuffer, nbytes); + if (chry_ringbuffer_get_free(&g_usbrx) >= DAP_PACKET_SIZE) { + usbd_ep_start_read(0, CDC_OUT_EP, usb_tmpbuffer, DAP_PACKET_SIZE); + } else { + usbrx_idle_flag = 1; + } +} + +void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + (void) busid; + uint32_t size; + uint8_t *buffer; + + chry_ringbuffer_linear_read_done(&g_uartrx, nbytes); + if ((nbytes % DAP_PACKET_SIZE) == 0 && nbytes) { + /* send zlp */ + usbd_ep_start_write(0, CDC_IN_EP, NULL, 0); + } else { + if (chry_ringbuffer_get_used(&g_uartrx)) { + buffer = chry_ringbuffer_linear_read_setup(&g_uartrx, &size); + usbd_ep_start_write(0, CDC_IN_EP, buffer, size); + } else { + usbtx_idle_flag = 1; + } + } +} + +struct usbd_endpoint dap_out_ep = { + .ep_addr = DAP_OUT_EP, + .ep_cb = dap_out_callback +}; + +struct usbd_endpoint dap_in_ep = { + .ep_addr = DAP_IN_EP, + .ep_cb = dap_in_callback +}; + +struct usbd_endpoint cdc_out_ep = { + .ep_addr = CDC_OUT_EP, + .ep_cb = usbd_cdc_acm_bulk_out +}; + +struct usbd_endpoint cdc_in_ep = { + .ep_addr = CDC_IN_EP, + .ep_cb = usbd_cdc_acm_bulk_in +}; + +struct usbd_interface dap_intf; +struct usbd_interface intf1; +struct usbd_interface intf2; +struct usbd_interface intf3; +struct usbd_interface hid_intf; + +struct usb_msosv2_descriptor msosv2_desc = { + .vendor_code = USBD_WINUSB_VENDOR_CODE, + .compat_id = USBD_WinUSBDescriptorSetDescriptor, + .compat_id_len = USBD_WINUSB_DESC_SET_LEN, +}; + +struct usb_bos_descriptor bos_desc = { + .string = USBD_BinaryObjectStoreDescriptor, + .string_len = USBD_BOS_WTOTALLENGTH +}; + +const struct usb_descriptor cmsisdap_descriptor = { + .device_descriptor_callback = device_descriptor_callback, + .config_descriptor_callback = config_descriptor_callback, + .device_quality_descriptor_callback = device_quality_descriptor_callback, + .other_speed_descriptor_callback = other_speed_config_descriptor_callback, + .string_descriptor_callback = string_descriptor_callback, + .bos_descriptor = &bos_desc, + .msosv2_descriptor = &msosv2_desc, +}; + +void chry_dap_handle(void) +{ + uint32_t n; + + // Process pending requests + while (USB_RequestCountI != USB_RequestCountO) { + // Handle Queue Commands + n = USB_RequestIndexO; + while (USB_Request[n][0] == ID_DAP_QueueCommands) { + USB_Request[n][0] = ID_DAP_ExecuteCommands; + n++; + if (n == DAP_PACKET_COUNT) { + n = 0U; + } + if (n == USB_RequestIndexI) { + // flags = osThreadFlagsWait(0x81U, osFlagsWaitAny, osWaitForever); + // if (flags & 0x80U) { + // break; + // } + } + } + + // Execute DAP Command (process request and prepare response) + USB_RespSize[USB_ResponseIndexI] = + (uint16_t) DAP_ExecuteCommand(USB_Request[USB_RequestIndexO], USB_Response[USB_ResponseIndexI]); + + // Update Request Index and Count + USB_RequestIndexO++; + if (USB_RequestIndexO == DAP_PACKET_COUNT) { + USB_RequestIndexO = 0U; + } + USB_RequestCountO++; + + if (USB_RequestIdle) { + if ((uint16_t) (USB_RequestCountI - USB_RequestCountO) != DAP_PACKET_COUNT) { + USB_RequestIdle = 0U; + usbd_ep_start_read(0, DAP_OUT_EP, USB_Request[USB_RequestIndexI], DAP_PACKET_SIZE); + } + } + + // Update Response Index and Count + USB_ResponseIndexI++; + if (USB_ResponseIndexI == DAP_PACKET_COUNT) { + USB_ResponseIndexI = 0U; + } + USB_ResponseCountI++; + + if (USB_ResponseIdle) { + if (USB_ResponseCountI != USB_ResponseCountO) { + // Load data from response buffer to be sent back + n = USB_ResponseIndexO++; + if (USB_ResponseIndexO == DAP_PACKET_COUNT) { + USB_ResponseIndexO = 0U; + } + USB_ResponseCountO++; + USB_ResponseIdle = 0U; + usbd_ep_start_write(0, DAP_IN_EP, USB_Response[n], USB_RespSize[n]); + } + } + } +} + +void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding) +{ + (void) busid; + if (memcmp(line_coding, (uint8_t *) &g_cdc_lincoding, sizeof(struct cdc_line_coding)) != 0) { + memcpy((uint8_t *) &g_cdc_lincoding, line_coding, sizeof(struct cdc_line_coding)); + config_uart = 1; + config_uart_transfer = 0; + } +} + +void usbd_cdc_acm_get_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding) +{ + (void) busid; + memcpy(line_coding, (uint8_t *) &g_cdc_lincoding, sizeof(struct cdc_line_coding)); +} + +void chry_dap_usb2uart_handle(void) +{ + uint32_t size; + uint8_t *buffer; + + if (config_uart) { + /* disable irq here */ + config_uart = 0; + /* config uart here */ + chry_dap_usb2uart_uart_config_callback((struct cdc_line_coding *) &g_cdc_lincoding); + usbtx_idle_flag = 1; + uarttx_idle_flag = 1; + config_uart_transfer = 1; + //chry_ringbuffer_reset_read(&g_uartrx); + /* enable irq here */ + } + + if (config_uart_transfer == 0) { + return; + } + + /* why we use chry_ringbuffer_linear_read_setup? + * becase we use dma and we do not want to use temp buffer to memcpy from ringbuffer + * + */ + + /* uartrx to usb tx */ + if (usbtx_idle_flag) { + if (chry_ringbuffer_get_used(&g_uartrx)) { + usbtx_idle_flag = 0; + /* start first transfer */ + buffer = chry_ringbuffer_linear_read_setup(&g_uartrx, &size); + usbd_ep_start_write(0, CDC_IN_EP, buffer, size); + } + } + + /* usbrx to uart tx */ + if (uarttx_idle_flag) { + if (chry_ringbuffer_get_used(&g_usbrx)) { + uarttx_idle_flag = 0; + /* start first transfer */ + buffer = chry_ringbuffer_linear_read_setup(&g_usbrx, &size); + chry_dap_usb2uart_uart_send_bydma(buffer, size); + } + } + + /* check whether usb rx ringbuffer have space to store */ + if (usbrx_idle_flag) { + if (chry_ringbuffer_get_free(&g_usbrx) >= DAP_PACKET_SIZE) { + usbrx_idle_flag = 0; + usbd_ep_start_read(0, CDC_OUT_EP, usb_tmpbuffer, DAP_PACKET_SIZE); + } + } +} + +/* implment by user */ +__WEAK void chry_dap_usb2uart_uart_config_callback(struct cdc_line_coding *line_coding) +{ +} + +/* called by user */ +void chry_dap_usb2uart_uart_send_complete(uint32_t size) +{ + uint8_t *buffer; + + chry_ringbuffer_linear_read_done(&g_usbrx, size); + + if (chry_ringbuffer_get_used(&g_usbrx)) { + buffer = chry_ringbuffer_linear_read_setup(&g_usbrx, &size); + chry_dap_usb2uart_uart_send_bydma(buffer, size); + } else { + uarttx_idle_flag = 1; + } +} + +/* implment by user */ +__WEAK void chry_dap_usb2uart_uart_send_bydma(uint8_t *data, uint16_t len) +{ +} + +#ifdef CONFIG_CHERRYDAP_USE_MSC +#define BLOCK_SIZE 512 +#define BLOCK_COUNT 10 + +typedef struct +{ + uint8_t BlockSpace[BLOCK_SIZE]; +} BLOCK_TYPE; + +BLOCK_TYPE mass_block[BLOCK_COUNT]; + +void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint16_t *block_size) +{ + *block_num = 1000; //Pretend having so many buffer,not has actually. + *block_size = BLOCK_SIZE; +} +int usbd_msc_sector_read(uint32_t sector, uint8_t *buffer, uint32_t length) +{ + if (sector < 10) + memcpy(buffer, mass_block[sector].BlockSpace, length); + return 0; +} + +int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length) +{ + if (sector < 10) + memcpy(mass_block[sector].BlockSpace, buffer, length); + return 0; +} +#endif diff --git a/platform/daplink/dap_main.h b/platform/daplink/dap_main.h new file mode 100644 index 00000000..082cb996 --- /dev/null +++ b/platform/daplink/dap_main.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2023 ~ 2025, sakumisu + * Copyright (c) 2023 ~ 2025, HalfSweet + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef DAP_MAIN_H +#define DAP_MAIN_H + +#include "usbd_core.h" +#include "usbd_cdc.h" +#include "usbd_msc.h" +#include "chry_ringbuffer.h" +#include "DAP_config.h" +#include "DAP.h" + +#define DAP_IN_EP 0x81 +#define DAP_OUT_EP 0x02 + +#define CDC_IN_EP 0x83 +#define CDC_OUT_EP 0x04 +#define CDC_INT_EP 0x85 + +#define MSC_IN_EP 0x86 +#define MSC_OUT_EP 0x07 + +#define USBD_VID 0x0D28 +#define USBD_PID 0x0204 +#define USBD_MAX_POWER 500 +#define USBD_LANGID_STRING 1033 + +#define CMSIS_DAP_INTERFACE_SIZE (9 + 7 + 7) + +#ifdef CONFIG_CHERRYDAP_USE_MSC +#define CONFIG_MSC_DESCRIPTOR_LEN CDC_ACM_DESCRIPTOR_LEN +#define CONFIG_MSC_INTF_NUM 1 +#define MSC_INTF_NUM (0x02 + 1) +#else +#define CONFIG_MSC_DESCRIPTOR_LEN 0 +#define CONFIG_MSC_INTF_NUM 0 +#define MSC_INTF_NUM (0x02) +#endif + +#ifdef CONFIG_USB_HS +#if DAP_PACKET_SIZE != 512 +#error "DAP_PACKET_SIZE must be 512 in hs" +#endif +#else +#if DAP_PACKET_SIZE != 64 +#error "DAP_PACKET_SIZE must be 64 in fs" +#endif +#endif + +#define USBD_WINUSB_VENDOR_CODE 0x20 + +#define USBD_WEBUSB_ENABLE 0 +#define USBD_BULK_ENABLE 1 +#define USBD_WINUSB_ENABLE 1 + +/* WinUSB Microsoft OS 2.0 descriptor sizes */ +#define WINUSB_DESCRIPTOR_SET_HEADER_SIZE 10 +#define WINUSB_FUNCTION_SUBSET_HEADER_SIZE 8 +#define WINUSB_FEATURE_COMPATIBLE_ID_SIZE 20 + +#define FUNCTION_SUBSET_LEN 160 +#define DEVICE_INTERFACE_GUIDS_FEATURE_LEN 132 + +#define USBD_WINUSB_DESC_SET_LEN (WINUSB_DESCRIPTOR_SET_HEADER_SIZE + USBD_WEBUSB_ENABLE * FUNCTION_SUBSET_LEN + USBD_BULK_ENABLE * FUNCTION_SUBSET_LEN) + +#define USBD_NUM_DEV_CAPABILITIES (USBD_WEBUSB_ENABLE + USBD_WINUSB_ENABLE) + +#define USBD_WEBUSB_DESC_LEN 24 +#define USBD_WINUSB_DESC_LEN 28 + +#define USBD_BOS_WTOTALLENGTH (0x05 + \ + USBD_WEBUSB_DESC_LEN * USBD_WEBUSB_ENABLE + \ + USBD_WINUSB_DESC_LEN * USBD_WINUSB_ENABLE) + +#define CONFIG_UARTRX_RINGBUF_SIZE (8 * 1024) +#define CONFIG_USBRX_RINGBUF_SIZE (8 * 1024) + +#ifdef __cplusplus +extern "C" +{ +#endif + +extern USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t uartrx_ringbuffer[CONFIG_UARTRX_RINGBUF_SIZE]; +extern USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t usbrx_ringbuffer[CONFIG_USBRX_RINGBUF_SIZE]; +extern USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t usb_tmpbuffer[DAP_PACKET_SIZE]; + +extern const struct usb_descriptor cmsisdap_descriptor; +extern __ALIGN_BEGIN const uint8_t USBD_WinUSBDescriptorSetDescriptor[]; +extern __ALIGN_BEGIN const uint8_t USBD_BinaryObjectStoreDescriptor[]; +extern char *string_descriptors[]; + +extern struct usbd_interface dap_intf; +extern struct usbd_interface intf1; +extern struct usbd_interface intf2; +extern struct usbd_interface intf3; +extern struct usbd_interface hid_intf; + +extern struct usbd_endpoint dap_out_ep; +extern struct usbd_endpoint dap_in_ep; +extern struct usbd_endpoint cdc_out_ep; +extern struct usbd_endpoint cdc_in_ep; + +extern chry_ringbuffer_t g_uartrx; +extern chry_ringbuffer_t g_usbrx; + +__STATIC_INLINE void chry_dap_init(uint8_t busid, uint32_t reg_base) +{ + chry_ringbuffer_init(&g_uartrx, uartrx_ringbuffer, CONFIG_UARTRX_RINGBUF_SIZE); + chry_ringbuffer_init(&g_usbrx, usbrx_ringbuffer, CONFIG_USBRX_RINGBUF_SIZE); + + DAP_Setup(); + + usbd_desc_register(0, &cmsisdap_descriptor); + + /*!< winusb */ + usbd_add_interface(0, &dap_intf); + usbd_add_endpoint(0, &dap_out_ep); + usbd_add_endpoint(0, &dap_in_ep); + + /*!< cdc acm */ + usbd_add_interface(0, usbd_cdc_acm_init_intf(0, &intf1)); + usbd_add_interface(0, usbd_cdc_acm_init_intf(0, &intf2)); + usbd_add_endpoint(0, &cdc_out_ep); + usbd_add_endpoint(0, &cdc_in_ep); + +#ifdef CONFIG_CHERRYDAP_USE_MSC + usbd_add_interface(0, usbd_msc_init_intf(0, &intf3, MSC_OUT_EP, MSC_IN_EP)); +#endif + extern void usbd_event_handler(uint8_t busid, uint8_t event); + usbd_initialize(busid, reg_base, usbd_event_handler); +} + +void chry_dap_handle(void); + +void chry_dap_usb2uart_handle(void); + +void chry_dap_usb2uart_uart_config_callback(struct cdc_line_coding *line_coding); + +void chry_dap_usb2uart_uart_send_bydma(uint8_t *data, uint16_t len); + +void chry_dap_usb2uart_uart_send_complete(uint32_t size); + +#ifdef __cplusplus +} +#endif + +#endif
\ No newline at end of file diff --git a/platform/none/usbh_fatfs.c b/platform/fatfs/usbh_fatfs.c index 5e164a7b..5e164a7b 100644 --- a/platform/none/usbh_fatfs.c +++ b/platform/fatfs/usbh_fatfs.c diff --git a/platform/none/usbh_lwip.c b/platform/lwip/usbh_lwip.c index 7b3f7c62..7b3f7c62 100644 --- a/platform/none/usbh_lwip.c +++ b/platform/lwip/usbh_lwip.c diff --git a/platform/qmk/.gitkeep b/platform/qmk/.gitkeep new file mode 100644 index 00000000..91fe8b9b --- /dev/null +++ b/platform/qmk/.gitkeep @@ -0,0 +1 @@ +TODO Release
\ No newline at end of file diff --git a/platform/uf2/bootuf2.c b/platform/uf2/bootuf2.c new file mode 100644 index 00000000..80de5592 --- /dev/null +++ b/platform/uf2/bootuf2.c @@ -0,0 +1,463 @@ +/* + * Copyright (c) 2024, sakumisu + * Copyright (c) 2024, Egahp + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "bootuf2.h" +#include "usbd_core.h" + +char file_INFO[] = { + "CherryUSB UF2 BOOT\r\n" + "Model: " CONFIG_PRODUCT "\r\n" + "Board-ID: " CONFIG_BOARD "\r\n" +}; + +const char file_IDEX[] = { + "<!doctype html>\n" + "<html>" + "<body>" + "<script>\n" + "location.replace(\"" CONFIG_BOOTUF2_INDEX_URL "\");\n" + "</script>" + "</body>" + "</html>\n" +}; + +const char file_JOIN[] = { + "<!doctype html>\n" + "<html>" + "<body>" + "<script>\n" + "location.replace(\"" CONFIG_BOOTUF2_JOIN_URL "\");\n" + "</script>" + "</body>" + "</html>\n" +}; + +const char file_ID__[12] = BOOTUF2_FAMILYID_ARRAY; + +static struct bootuf2_FILE files[] = { + [0] = { .Name = file_ID__, .Content = NULL, .FileSize = 0 }, + [1] = { .Name = "INFO_UF2TXT", .Content = file_INFO, .FileSize = sizeof(file_INFO) - 1 }, + [2] = { .Name = "INDEX HTM", .Content = file_IDEX, .FileSize = sizeof(file_IDEX) - 1 }, + [3] = { .Name = "JOIN HTM", .Content = file_JOIN, .FileSize = sizeof(file_JOIN) - 1 }, +}; + +struct bootuf2_data { + const struct bootuf2_DBR *const DBR; + struct bootuf2_STATE *const STATE; + uint8_t *const fbuff; + uint8_t *const erase; + size_t page_count; + uint8_t *const cache; + const size_t cache_size; + uint32_t cached_address; + size_t cached_bytes; +}; + +/*!< define DBRs */ +static const struct bootuf2_DBR bootuf2_DBR = { + .JMPInstruction = { 0xEB, 0x3C, 0x90 }, + .OEM = "UF2 UF2 ", + .BPB = { + .BytesPerSector = CONFIG_BOOTUF2_SECTOR_SIZE, + .SectorsPerCluster = CONFIG_BOOTUF2_SECTOR_PER_CLUSTER, + .ReservedSectors = CONFIG_BOOTUF2_SECTOR_RESERVED, + .NumberOfFAT = CONFIG_BOOTUF2_NUM_OF_FAT, + .RootEntries = CONFIG_BOOTUF2_ROOT_ENTRIES, + .Sectors = (BOOTUF2_SECTORS(0) > 0xFFFF) ? 0 : BOOTUF2_SECTORS(0), + .MediaDescriptor = 0xF8, + .SectorsPerFAT = BOOTUF2_SECTORS_PER_FAT(0), + .SectorsPerTrack = 1, + .Heads = 1, + .HiddenSectors = 0, + .SectorsOver32MB = (BOOTUF2_SECTORS(0) > 0xFFFF) ? BOOTUF2_SECTORS(0) : 0, + .BIOSDrive = 0x80, + .Reserved = 0, + .ExtendBootSignature = 0x29, + .VolumeSerialNumber = 0x00420042, + .VolumeLabel = "CHERRYUF2", + .FileSystem = "FAT16 ", + }, +}; + +/*!< define mask */ +static uint8_t __attribute__((aligned(4))) bootuf2_mask[BOOTUF2_BLOCKSMAX / 8 + 1] = { 0 }; + +/*!< define state */ +static struct bootuf2_STATE bootuf2_STATE = { + .NumberOfBlock = 0, + .NumberOfWritten = 0, + .Mask = bootuf2_mask, + .Enable = 1, +}; + +/*!< define flash cache */ +static uint8_t __attribute__((aligned(4))) bootuf2_disk_cache[CONFIG_BOOTUF2_CACHE_SIZE]; + +/*!< define flash buff */ +static uint8_t __attribute__((aligned(4))) bootuf2_disk_fbuff[256]; + +/*!< define erase flag buff */ +static uint8_t __attribute__((aligned(4))) bootuf2_disk_erase[BOOTUF2_DIVCEIL(CONFIG_BOOTUF2_PAGE_COUNTMAX, 8)]; + +/*!< define disk */ +static struct bootuf2_data bootuf2_disk = { + .DBR = &bootuf2_DBR, + .STATE = &bootuf2_STATE, + .fbuff = bootuf2_disk_fbuff, + .erase = bootuf2_disk_erase, + .cache = bootuf2_disk_cache, + .cache_size = sizeof(bootuf2_disk_cache), +}; + +static void fname_copy(char *dst, char const *src, uint16_t len) +{ + for (size_t i = 0; i < len; ++i) { + if (*src) + *dst++ = *src++; + else + *dst++ = ' '; + } +} + +static void fcalculate_cluster(struct bootuf2_data *ctx) +{ + /*!< init files cluster */ + uint16_t cluster_beg = 2; + for (int i = 0; i < ARRAY_SIZE(files); i++) { + files[i].ClusterBeg = cluster_beg; + files[i].ClusterEnd = -1 + cluster_beg + + BOOTUF2_DIVCEIL(files[i].FileSize, + ctx->DBR->BPB.BytesPerSector * + ctx->DBR->BPB.SectorsPerCluster); + cluster_beg = files[i].ClusterEnd + 1; + } +} + +static int ffind_by_cluster(uint32_t cluster) +{ + if (cluster >= 0xFFF0) { + return -1; + } + + for (uint32_t i = 0; i < ARRAY_SIZE(files); i++) { + if ((files[i].ClusterBeg <= cluster) && + (cluster <= files[i].ClusterEnd)) { + return i; + } + } + + return -1; +} + +static bool bootuf2block_check_writable(struct bootuf2_STATE *STATE, + struct bootuf2_BLOCK *uf2, uint32_t block_max) +{ + if (uf2->NumberOfBlock) { + if (uf2->BlockIndex < block_max) { + uint8_t mask = 1 << (uf2->BlockIndex % 8); + uint32_t pos = uf2->BlockIndex / 8; + + if ((STATE->Mask[pos] & mask) == 0) { + return true; + } + } + } + + return false; +} + +static void bootuf2block_state_update(struct bootuf2_STATE *STATE, + struct bootuf2_BLOCK *uf2, uint32_t block_max) +{ + if (uf2->NumberOfBlock) { + if (STATE->NumberOfBlock != uf2->NumberOfBlock) { + if ((uf2->NumberOfBlock >= BOOTUF2_BLOCKSMAX) || + STATE->NumberOfBlock) { + /*!< uf2 block only can be update once */ + /*!< this will cause never auto reboot */ + STATE->NumberOfBlock = 0xffffffff; + } else { + STATE->NumberOfBlock = uf2->NumberOfBlock; + } + } + + if (uf2->BlockIndex < block_max) { + uint8_t mask = 1 << (uf2->BlockIndex % 8); + uint32_t pos = uf2->BlockIndex / 8; + + if ((STATE->Mask[pos] & mask) == 0) { + STATE->Mask[pos] |= mask; + STATE->NumberOfWritten++; + } + } + } + + USB_LOG_DBG("UF2 block total %d written %d index %d\r\n", + uf2->NumberOfBllock, STATE->NumberOfWritten, uf2->BlockIndex); +} + +static bool bootuf2block_state_check(struct bootuf2_STATE *STATE) +{ + return (STATE->NumberOfWritten >= STATE->NumberOfBlock) && + STATE->NumberOfBlock; +} + +static int bootuf2_flash_flush(struct bootuf2_data *ctx) +{ + int err; + + if (ctx->cached_bytes == 0) { + return 0; + } + + err = bootuf2_flash_write(ctx->cached_address, ctx->cache, ctx->cached_bytes); + + if (err) { + USB_LOG_ERR("UF2 slot flash write error %d at offset %08lx len %d\r\n", + err, ctx->cached_address, ctx->cached_bytes); + return -1; + } + + ctx->cached_bytes = 0; + + return 0; +} + +int bootuf2_flash_write_internal(struct bootuf2_data *ctx, struct bootuf2_BLOCK *uf2) +{ + /*!< 1.cache not empty and address not continue */ + /*!< 2.cache full */ + if ((ctx->cached_bytes && ((ctx->cached_address + ctx->cached_bytes) != uf2->TargetAddress)) || + (ctx->cached_bytes == ctx->cache_size)) { + int err = bootuf2_flash_flush(ctx); + if (err) + return err; + } + + /*!< write len always is 256, cache_size always is a multiple of 256 */ + memcpy(ctx->cache + ctx->cached_bytes, uf2->Data, uf2->PayloadSize); + + ctx->cached_address = uf2->TargetAddress - ctx->cached_bytes; + ctx->cached_bytes += uf2->PayloadSize; + + return 0; +} + +void bootuf2_init(void) +{ + struct bootuf2_data *ctx; + + ctx = &bootuf2_disk; + + fcalculate_cluster(ctx); + + ctx->cached_bytes = 0; + ctx->cached_address = 0; +} + +int boot2uf2_read_sector(uint32_t start_sector, uint8_t *buff, uint32_t sector_count) +{ + struct bootuf2_data *ctx; + + ctx = &bootuf2_disk; + + while (sector_count) { + memset(buff, 0, ctx->DBR->BPB.BytesPerSector); + + uint32_t sector_relative = start_sector; + + /*!< DBR sector */ + if (start_sector == BOOTUF2_SECTOR_DBR_END) { + memcpy(buff, ctx->DBR, sizeof(struct bootuf2_DBR)); + buff[510] = 0x55; + buff[511] = 0xaa; + } + /*!< FAT sector */ + else if (start_sector < BOOTUF2_SECTOR_FAT_END(ctx->DBR)) { + uint16_t *buff16 = (uint16_t *)buff; + + sector_relative -= BOOTUF2_SECTOR_RSVD_END(ctx->DBR); + + /*!< Perform the same operation on all FAT tables */ + while (sector_relative >= ctx->DBR->BPB.SectorsPerFAT) { + sector_relative -= ctx->DBR->BPB.SectorsPerFAT; + } + + uint16_t cluster_unused = files[ARRAY_SIZE(files) - 1].ClusterEnd + 1; + uint16_t cluster_absolute_first = sector_relative * + BOOTUF2_FAT16_PER_SECTOR(ctx->DBR); + + /*!< cluster used link to chain, or unsed */ + for (uint16_t i = 0, cluster_absolute = cluster_absolute_first; + i < BOOTUF2_FAT16_PER_SECTOR(ctx->DBR); + i++, cluster_absolute++) { + if (cluster_absolute >= cluster_unused) + buff16[i] = 0; + else + buff16[i] = cluster_absolute + 1; + } + + /*!< cluster 0 and 1 */ + if (sector_relative == 0) { + buff[0] = ctx->DBR->BPB.MediaDescriptor; + buff[1] = 0xff; + buff16[1] = 0xffff; + } + + /*!< cluster end of file */ + for (uint32_t i = 0; i < ARRAY_SIZE(files); i++) { + uint16_t cluster_file_last = files[i].ClusterEnd; + + if (cluster_file_last >= cluster_absolute_first) { + uint16_t idx = cluster_file_last - cluster_absolute_first; + if (idx < BOOTUF2_FAT16_PER_SECTOR(ctx->DBR)) { + buff16[idx] = 0xffff; + } + } + } + } + /*!< root entries */ + else if (start_sector < BOOTUF2_SECTOR_ROOT_END(ctx->DBR)) { + sector_relative -= BOOTUF2_SECTOR_FAT_END(ctx->DBR); + + struct bootuf2_ENTRY *ent = (void *)buff; + int remain_entries = BOOTUF2_ENTRY_PER_SECTOR(ctx->DBR); + + uint32_t file_index_first; + + /*!< volume label entry */ + if (sector_relative == 0) { + fname_copy(ent->Name, (char const *)ctx->DBR->BPB.VolumeLabel, 11); + ent->Attribute = 0x28; + ent++; + remain_entries--; + file_index_first = 0; + } else { + /*!< -1 to account for volume label in first sector */ + file_index_first = sector_relative * BOOTUF2_ENTRY_PER_SECTOR(ctx->DBR) - 1; + } + + for (uint32_t idx = file_index_first; + (remain_entries > 0) && (idx < ARRAY_SIZE(files)); + idx++, ent++) { + const uint32_t cluster_beg = files[idx].ClusterBeg; + + const struct bootuf2_FILE *f = &files[idx]; + + if ((0 == f->FileSize) && + (0 != idx)) { + continue; + } + + fname_copy(ent->Name, f->Name, 11); + ent->Attribute = 0x05; + ent->CreateTimeTeenth = BOOTUF2_SECONDS_INT % 2 * 100; + ent->CreateTime = BOOTUF2_DOS_TIME; + ent->CreateDate = BOOTUF2_DOS_DATE; + ent->LastAccessDate = BOOTUF2_DOS_DATE; + ent->FirstClustH16 = cluster_beg >> 16; + ent->UpdateTime = BOOTUF2_DOS_TIME; + ent->UpdateDate = BOOTUF2_DOS_DATE; + ent->FirstClustL16 = cluster_beg & 0xffff; + ent->FileSize = f->FileSize; + } + } + /*!< data */ + else if (start_sector < BOOTUF2_SECTOR_DATA_END(ctx->DBR)) { + sector_relative -= BOOTUF2_SECTOR_ROOT_END(ctx->DBR); + + int fid = ffind_by_cluster(2 + sector_relative / ctx->DBR->BPB.SectorsPerCluster); + + if (fid >= 0) { + const struct bootuf2_FILE *f = &files[fid]; + + uint32_t sector_relative_file = + sector_relative - + (files[fid].ClusterBeg - 2) * ctx->DBR->BPB.SectorsPerCluster; + + size_t fcontent_offset = sector_relative_file * ctx->DBR->BPB.BytesPerSector; + size_t fcontent_length = f->FileSize; + + if (fcontent_length > fcontent_offset) { + const void *src = (void *)((uint8_t *)(f->Content) + fcontent_offset); + size_t copy_size = fcontent_length - fcontent_offset; + + if (copy_size > ctx->DBR->BPB.BytesPerSector) { + copy_size = ctx->DBR->BPB.BytesPerSector; + } + + memcpy(buff, src, copy_size); + } + } + } + /*!< unknown sector, ignore */ + + start_sector++; + sector_count--; + buff += ctx->DBR->BPB.BytesPerSector; + } + + return 0; +} + +int bootuf2_write_sector(uint32_t start_sector, const uint8_t *buff, uint32_t sector_count) +{ + struct bootuf2_data *ctx; + + ctx = &bootuf2_disk; + + while (sector_count) { + struct bootuf2_BLOCK *uf2 = (void *)buff; + + if (!((uf2->MagicStart0 == BOOTUF2_MAGIC_START0) && + (uf2->MagicStart1 == BOOTUF2_MAGIC_START1) && + (uf2->MagicEnd == BOOTUF2_MAGIC_END) && + (uf2->Flags & BOOTUF2_FLAG_FAMILID_PRESENT) && + !(uf2->Flags & BOOTUF2_FLAG_NOT_MAIN_FLASH))) { + goto next; + } + + if (uf2->FamilyID == CONFIG_BOOTUF2_FAMILYID) { + if (bootuf2block_check_writable(ctx->STATE, uf2, CONFIG_BOOTUF2_FLASHMAX)) { + bootuf2_flash_write_internal(ctx, uf2); + bootuf2block_state_update(ctx->STATE, uf2, CONFIG_BOOTUF2_FLASHMAX); + } else { + USB_LOG_DBG("UF2 block %d already written\r\n", + uf2->BlockIndex); + } + } else { + USB_LOG_DBG("UF2 block illegal id %08x\r\n", uf2->FamilyID); + } + + next: + start_sector++; + sector_count--; + buff += ctx->DBR->BPB.BytesPerSector; + } + + return 0; +} + +uint16_t bootuf2_get_sector_size(void) +{ + return bootuf2_disk.DBR->BPB.BytesPerSector; +} + +uint32_t bootuf2_get_sector_count(void) +{ + return bootuf2_disk.DBR->BPB.SectorsOver32MB + bootuf2_disk.DBR->BPB.Sectors; +} + +bool bootuf2_is_write_done(void) +{ + if (bootuf2block_state_check(bootuf2_disk.STATE)) { + bootuf2_flash_flush(&bootuf2_disk); + USB_LOG_DBG("UF2 update ok\r\n"); + return true; + } else { + return false; + } +}
\ No newline at end of file diff --git a/platform/uf2/bootuf2.h b/platform/uf2/bootuf2.h new file mode 100644 index 00000000..ec31d3ea --- /dev/null +++ b/platform/uf2/bootuf2.h @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2024, sakumisu + * Copyright (c) 2024, Egahp + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef BOOTUF2_H +#define BOOTUF2_H + +#include <stdint.h> +#include <stddef.h> +#include <string.h> +#include <stdbool.h> +#include <stdio.h> +#include <bootuf2_config.h> + +#ifndef __PACKED +#define __PACKED __attribute__((packed)) +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(array) \ + ((int)((sizeof(array) / sizeof((array)[0])))) +#endif + +struct bootuf2_BLOCK +{ + // 32 byte header + uint32_t MagicStart0; + uint32_t MagicStart1; + uint32_t Flags; + uint32_t TargetAddress; + uint32_t PayloadSize; + uint32_t BlockIndex; + uint32_t NumberOfBlock; + uint32_t FamilyID; // or file_size + uint8_t Data[476]; + uint32_t MagicEnd; +} __PACKED; +//BUILD_ASSERT(sizeof(struct bootuf2_BLOCK) == 512, "bootuf2_BLOCK not sector sized"); + +struct bootuf2_STATE +{ + uint32_t NumberOfBlock; + uint32_t NumberOfWritten; + uint8_t *const Mask; + uint8_t Enable; +}; + +struct bootuf2_DBR +{ + /*!< offset 0 */ + uint8_t JMPInstruction[3]; + /*!< offset 3 */ + uint8_t OEM[8]; + /*!< offset 11 */ + struct + { + uint16_t BytesPerSector; + uint8_t SectorsPerCluster; + uint16_t ReservedSectors; + uint8_t NumberOfFAT; + uint16_t RootEntries; + uint16_t Sectors; + uint8_t MediaDescriptor; + uint16_t SectorsPerFAT; + uint16_t SectorsPerTrack; + uint16_t Heads; + uint32_t HiddenSectors; + uint32_t SectorsOver32MB; + uint8_t BIOSDrive; + uint8_t Reserved; + uint8_t ExtendBootSignature; + uint32_t VolumeSerialNumber; + uint8_t VolumeLabel[11]; + uint8_t FileSystem[8]; + } __PACKED BPB; + /*!< offset 62 */ + /*!< BootLoader */ + /*!< offset 511 */ + /*!< 0x55 0xAA */ +} __PACKED; +//BUILD_ASSERT(sizeof(struct bootuf2_DBR) == 62, "bootuf2_DBR size must be 62 byte"); + +struct bootuf2_ENTRY +{ + char Name[11]; + uint8_t Attribute; + uint8_t NTReserved; + uint8_t CreateTimeTeenth; + uint16_t CreateTime; + uint16_t CreateDate; + uint16_t LastAccessDate; + uint16_t FirstClustH16; + uint16_t UpdateTime; + uint16_t UpdateDate; + uint16_t FirstClustL16; + uint32_t FileSize; +} __PACKED; +//BUILD_ASSERT(sizeof(struct bootuf2_ENTRY) == 32, "bootuf2_ENTRY size must be 32 byte"); + +struct bootuf2_FILE +{ + const char *const Name; + const void *const Content; + uint32_t FileSize; + uint16_t ClusterBeg; + uint16_t ClusterEnd; +}; + +#define BOOTUF2_DIVCEIL(_v, _d) (((_v) / (_d)) + ((_v) % (_d) ? 1 : 0)) + +#define BOOTUF2_MAGIC_START0 0x0A324655u +#define BOOTUF2_MAGIC_START1 0x9E5D5157u +#define BOOTUF2_MAGIC_SERIAL 0x251B18BDu +#define BOOTUF2_MAGIC_END 0x0AB16F30u + +#define BOOTUF2_FLAG_NOT_MAIN_FLASH 0x00000001u +#define BOOTUF2_FLAG_FILE_CONTAINER 0x00001000u +#define BOOTUF2_FLAG_FAMILID_PRESENT 0x00002000u +#define BOOTUF2_FLAG_MD5_PRESENT 0x00004000u + +#define BOOTUF2_CMD_READ 0 +#define BOOTUF2_CMD_SYNC 1 + +#define BOOTUF2_BLOCKSMAX (((CONFIG_BOOTUF2_FLASHMAX) / 256) + (((CONFIG_BOOTUF2_FLASHMAX) % 256) ? 1 : 0)) + +#define BOOTUF2_FAMILYID_POSNUM(n) (((CONFIG_BOOTUF2_FAMILYID) / (0x10000000 >> ((n) * 4))) % 0x10) +#define BOOTUF2_FAMILYID_ARRAY \ + { \ + ((BOOTUF2_FAMILYID_POSNUM(0) >= 10) ? BOOTUF2_FAMILYID_POSNUM(0) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(0) + '0'), \ + ((BOOTUF2_FAMILYID_POSNUM(1) >= 10) ? BOOTUF2_FAMILYID_POSNUM(1) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(1) + '0'), \ + ((BOOTUF2_FAMILYID_POSNUM(2) >= 10) ? BOOTUF2_FAMILYID_POSNUM(2) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(2) + '0'), \ + ((BOOTUF2_FAMILYID_POSNUM(3) >= 10) ? BOOTUF2_FAMILYID_POSNUM(3) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(3) + '0'), \ + ((BOOTUF2_FAMILYID_POSNUM(4) >= 10) ? BOOTUF2_FAMILYID_POSNUM(4) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(4) + '0'), \ + ((BOOTUF2_FAMILYID_POSNUM(5) >= 10) ? BOOTUF2_FAMILYID_POSNUM(5) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(5) + '0'), \ + ((BOOTUF2_FAMILYID_POSNUM(6) >= 10) ? BOOTUF2_FAMILYID_POSNUM(6) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(6) + '0'), \ + ((BOOTUF2_FAMILYID_POSNUM(7) >= 10) ? BOOTUF2_FAMILYID_POSNUM(7) - 10 + 'A' : BOOTUF2_FAMILYID_POSNUM(7) + '0'), \ + ('I'), \ + ('D'), \ + (' '), \ + ('\0'), \ + }; + +#define BOOTUF2_FAT16_PER_SECTOR(pDBR) (pDBR->BPB.BytesPerSector / 2) +#define BOOTUF2_ENTRY_PER_SECTOR(pDBR) (pDBR->BPB.BytesPerSector / sizeof(struct bootuf2_ENTRY)) +#define BOOTUF2_CLUSTERSMAX (0xFFF0 - 2) +#define BOOTUF2_SECTOR_DBR_END (0) +#define BOOTUF2_SECTOR_RSVD_END(pDBR) BOOTUF2_SECTOR_DBR_END + (pDBR->BPB.ReservedSectors) +#define BOOTUF2_SECTOR_FAT_END(pDBR) BOOTUF2_SECTOR_RSVD_END(pDBR) + (pDBR->BPB.SectorsPerFAT * pDBR->BPB.NumberOfFAT) +#define BOOTUF2_SECTOR_ROOT_END(pDBR) BOOTUF2_SECTOR_FAT_END(pDBR) + (pDBR->BPB.RootEntries / (pDBR->BPB.BytesPerSector / sizeof(struct bootuf2_ENTRY))) +#define BOOTUF2_SECTOR_DATA_END(pDBR) (pDBR->BPB.Sectors + pDBR->BPB.SectorsOver32MB) + +#define BOOTUF2_SECTORS_PER_FAT(n) \ + BOOTUF2_DIVCEIL(BOOTUF2_CLUSTERSMAX, (CONFIG_BOOTUF2_SECTOR_SIZE / 2)) +#define BOOTUF2_SECTORS_FOR_ENTRIES(n) \ + (CONFIG_BOOTUF2_ROOT_ENTRIES / (CONFIG_BOOTUF2_SECTOR_SIZE / sizeof(struct bootuf2_ENTRY))) +#define BOOTUF2_SECTORS(n) \ + (CONFIG_BOOTUF2_SECTOR_RESERVED + \ + CONFIG_BOOTUF2_NUM_OF_FAT * BOOTUF2_SECTORS_PER_FAT(n) + \ + BOOTUF2_SECTORS_FOR_ENTRIES(n) + \ + BOOTUF2_CLUSTERSMAX * CONFIG_BOOTUF2_SECTOR_PER_CLUSTER) + +#define BOOTUF2_YEAR_INT ( \ + (__DATE__[7u] - '0') * 1000u + \ + (__DATE__[8u] - '0') * 100u + \ + (__DATE__[9u] - '0') * 10u + \ + (__DATE__[10u] - '0') * 1u) + +#define BOOTUF2_MONTH_INT ( \ + (__DATE__[2u] == 'n' && __DATE__[1u] == 'a') ? 1u /*Jan*/ \ + : (__DATE__[2u] == 'b') ? 2u /*Feb*/ \ + : (__DATE__[2u] == 'r' && __DATE__[1u] == 'a') ? 3u /*Mar*/ \ + : (__DATE__[2u] == 'r') ? 4u /*Apr*/ \ + : (__DATE__[2u] == 'y') ? 5u /*May*/ \ + : (__DATE__[2u] == 'n') ? 6u /*Jun*/ \ + : (__DATE__[2u] == 'l') ? 7u /*Jul*/ \ + : (__DATE__[2u] == 'g') ? 8u /*Aug*/ \ + : (__DATE__[2u] == 'p') ? 9u /*Sep*/ \ + : (__DATE__[2u] == 't') ? 10u /*Oct*/ \ + : (__DATE__[2u] == 'v') ? 11u /*Nov*/ \ + : 12u /*Dec*/) + +#define BOOTUF2_DAY_INT ( \ + (__DATE__[4u] == ' ' ? 0 : __DATE__[4u] - '0') * 10u + \ + (__DATE__[5u] - '0')) + +#define BOOTUF2_HOUR_INT ( \ + (__TIME__[0u] == '?' ? 0 : __TIME__[0u] - '0') * 10u + (__TIME__[1u] == '?' ? 0 : __TIME__[1u] - '0')) + +#define BOOTUF2_MINUTE_INT ( \ + (__TIME__[3u] == '?' ? 0 : __TIME__[3u] - '0') * 10u + (__TIME__[4u] == '?' ? 0 : __TIME__[4u] - '0')) + +#define BOOTUF2_SECONDS_INT ( \ + (__TIME__[6u] == '?' ? 0 : __TIME__[6u] - '0') * 10u + (__TIME__[7u] == '?' ? 0 : __TIME__[7u] - '0')) + +#define BOOTUF2_DOS_DATE ( \ + ((BOOTUF2_YEAR_INT - 1980u) << 9u) | \ + (BOOTUF2_MONTH_INT << 5u) | \ + (BOOTUF2_DAY_INT << 0u)) + +#define BOOTUF2_DOS_TIME ( \ + (BOOTUF2_HOUR_INT << 11u) | \ + (BOOTUF2_MINUTE_INT << 5u) | \ + (BOOTUF2_SECONDS_INT << 0u)) + +void bootuf2_init(void); +int boot2uf2_read_sector(uint32_t start_sector, uint8_t *buff, uint32_t sector_count); +int bootuf2_write_sector(uint32_t start_sector, const uint8_t *buff, uint32_t sector_count); +uint16_t bootuf2_get_sector_size(void); +uint32_t bootuf2_get_sector_count(void); + +bool bootuf2_is_write_done(void); + +void boot2uf2_flash_init(void); +int bootuf2_flash_write(uint32_t address, const uint8_t *data, size_t size); + +#endif /* BOOTUF2_H */ |
