diff --git a/.gitignore b/.gitignore index 26578c7..f2ff998 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ cmake-build/ build/ ex/ compile_commands.json +_old/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 565a4ac..5c24df3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,22 +56,18 @@ endif() target_sources(${PROJECT} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/libco/libco.S - ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/DAP.c - ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/JTAG_DP.c - ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/DAP_vendor.c - ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/SWO.c - ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/SW_DP.c - ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/cdc_uart.c - ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/i2c_tinyusb.c - ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/spi_serprog.c - ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/tempsensor.c +# ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/DAP.c +# ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/JTAG_DP.c +# ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/DAP_vendor.c +# ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/SWO.c +# ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Source/SW_DP.c ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/unique.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_serprog.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/vnd_i2ctinyusb.c ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/rtconf.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c - ${CMAKE_CURRENT_SOURCE_DIR}/src/tempsensor.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/modeset.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/thread.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/tusb_plt.S + ${CMAKE_CURRENT_SOURCE_DIR}/src/vnd_cfg.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/m_default/0def.c ) if(USE_USBCDC_FOR_STDIO) target_sources(${PROJECT} PUBLIC @@ -81,8 +77,8 @@ endif() target_include_directories(${PROJECT} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/ ${CMAKE_CURRENT_SOURCE_DIR}/libco/ - ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Include/ - ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/Core/Include/ +# ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/DAP/Firmware/Include/ +# ${CMAKE_CURRENT_SOURCE_DIR}/CMSIS_5/CMSIS/Core/Include/ ${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/ ${CMAKE_CURRENT_SOURCE_DIR}/bsp/default/ ) diff --git a/bsp/default/DAP_config.h b/bsp/default/DAP_config.h deleted file mode 100644 index b75191f..0000000 --- a/bsp/default/DAP_config.h +++ /dev/null @@ -1,470 +0,0 @@ -// vim: set et: -/* - * The MIT License (MIT) - * - * Copyright (c) 2021 Peter Lawrence - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* -This DAP_config provides a CMSIS-DAP alternative to picoprobe and raspberrypi-swd.cfg -*/ - -#ifndef __DAP_CONFIG_H__ -#define __DAP_CONFIG_H__ - -//************************************************************************************************** -/** -\defgroup DAP_Config_Debug_gr CMSIS-DAP Debug Unit Information -\ingroup DAP_ConfigIO_gr -@{ -Provides definitions about the hardware and configuration of the Debug Unit. - -This information includes: - - Definition of Cortex-M processor parameters used in CMSIS-DAP Debug Unit. - - Debug Unit Identification strings (Vendor, Product, Serial Number). - - Debug Unit communication packet size. - - Debug Access Port supported modes and settings (JTAG/SWD and SWO). - - Optional information about a connected Target Device (for Evaluation Boards). -*/ - -#include "cmsis_compiler.h" -#include "util.h" - -/// Processor Clock of the Cortex-M MCU used in the Debug Unit. -/// This value is used to calculate the SWD/JTAG clock speed. -#define CPU_CLOCK 48000000U ///< Specifies the CPU Clock in Hz. - -/// Number of processor cycles for I/O Port write operations. -/// This value is used to calculate the SWD/JTAG clock speed that is generated with I/O -/// Port write operations in the Debug Unit by a Cortex-M MCU. Most Cortex-M processors -/// require 2 processor cycles for a I/O Port Write operation. If the Debug Unit uses -/// a Cortex-M0+ processor with high-speed peripheral I/O only 1 processor cycle might be -/// required. -#define IO_PORT_WRITE_CYCLES 2U ///< I/O Cycles: 2=default, 1=Cortex-M0+ fast I/0. - -/// Indicate that Serial Wire Debug (SWD) communication mode is available at the Debug Access Port. -/// This information is returned by the command \ref DAP_Info as part of Capabilities. -#define DAP_SWD 1 ///< SWD Mode: 1 = available, 0 = not available. - -/// Indicate that JTAG communication mode is available at the Debug Port. -/// This information is returned by the command \ref DAP_Info as part of Capabilities. -#define DAP_JTAG 1 ///< JTAG Mode: 1 = available, 0 = not available. - -/// Configure maximum number of JTAG devices on the scan chain connected to the Debug Access Port. -/// This setting impacts the RAM requirements of the Debug Unit. Valid range is 1 .. 255. -#define DAP_JTAG_DEV_CNT 8U ///< Maximum number of JTAG devices on scan chain. - -/// Default communication mode on the Debug Access Port. -/// Used for the command \ref DAP_Connect when Port Default mode is selected. -#define DAP_DEFAULT_PORT 2U ///< Default JTAG/SWJ Port Mode: 1 = SWD, 2 = JTAG. - -/// Default communication speed on the Debug Access Port for SWD and JTAG mode. -/// Used to initialize the default SWD/JTAG clock frequency. -/// The command \ref DAP_SWJ_Clock can be used to overwrite this default setting. -#define DAP_DEFAULT_SWJ_CLOCK 1000000U ///< Default SWD/JTAG clock frequency in Hz. - -/// Maximum Package Size for Command and Response data. -/// This configuration settings is used to optimize the communication performance with the -/// debugger and depends on the USB peripheral. Typical vales are 64 for Full-speed USB HID or -/// WinUSB, 1024 for High-speed USB HID and 512 for High-speed USB WinUSB. -#define DAP_PACKET_SIZE CFG_TUD_HID_EP_BUFSIZE ///< Specifies Packet Size in bytes. - -/// Maximum Package Buffers for Command and Response data. -/// This configuration settings is used to optimize the communication performance with the -/// debugger and depends on the USB peripheral. For devices with limited RAM or USB buffer the -/// setting can be reduced (valid range is 1 .. 255). -#define DAP_PACKET_COUNT 1U ///< Specifies number of packets buffered. - -/// Indicate that UART Serial Wire Output (SWO) trace is available. -/// This information is returned by the command \ref DAP_Info as part of Capabilities. -#define SWO_UART 0 ///< SWO UART: 1 = available, 0 = not available. - -/// Maximum SWO UART Baudrate. -#define SWO_UART_MAX_BAUDRATE 10000000U ///< SWO UART Maximum Baudrate in Hz. - -/// Indicate that Manchester Serial Wire Output (SWO) trace is available. -/// This information is returned by the command \ref DAP_Info as part of Capabilities. -#define SWO_MANCHESTER 0 ///< SWO Manchester: 1 = available, 0 = not available. - -/// SWO Trace Buffer Size. -#define SWO_BUFFER_SIZE 4096U ///< SWO Trace Buffer Size in bytes (must be 2^n). - -/// SWO Streaming Trace. -#define SWO_STREAM 0 ///< SWO Streaming Trace: 1 = available, 0 = not available. - -/// Indicate that UART Communication Port is available. -/// This information is returned by the command \ref DAP_Info as part of Capabilities. -#define DAP_UART 0 ///< DAP UART: 1 = available, 0 = not available. - -/// USART Driver instance number for the UART Communication Port. -#define DAP_UART_DRIVER 1 ///< USART Driver instance number (Driver_USART#). - -/// UART Receive Buffer Size. -#define DAP_UART_RX_BUFFER_SIZE 64U ///< Uart Receive Buffer Size in bytes (must be 2^n). - -/// UART Transmit Buffer Size. -#define DAP_UART_TX_BUFFER_SIZE 64U ///< Uart Transmit Buffer Size in bytes (must be 2^n). - -/// Indicate that UART Communication via USB COM Port is available. -/// This information is returned by the command \ref DAP_Info as part of Capabilities. -#ifdef USE_USBCDC_FOR_STDIO -#define DAP_UART_USB_COM_PORT 1 ///< USB COM Port: 1 = available, 0 = not available. -#else -#define DAP_UART_USB_COM_PORT 0 -#endif - -/// Clock frequency of the Test Domain Timer. Timer value is returned with \ref TIMESTAMP_GET. -#define TIMESTAMP_CLOCK 0U ///< Timestamp clock in Hz (0 = timestamps not supported). - -/// Debug Unit is connected to fixed Target Device. -/// The Debug Unit may be part of an evaluation board and always connected to a fixed -/// known device. In this case a Device Vendor and Device Name string is stored which -/// may be used by the debugger or IDE to configure device parameters. -#define TARGET_DEVICE_FIXED 0 ///< Target Device: 1 = known, 0 = unknown; - -#include "DAP.h" - -/** Get Vendor ID string. -\param str Pointer to buffer to store the string. -\return String length. -*/ -__STATIC_INLINE uint8_t DAP_GetVendorString(char* str) { - static const char vnd[] = INFO_MANUFACTURER; - for (size_t i = 0; i < sizeof(vnd); ++i) str[i] = vnd[i]; - return sizeof(vnd) - 1; -} - -/** Get Product ID string. -\param str Pointer to buffer to store the string. -\return String length. -*/ -__STATIC_INLINE uint8_t DAP_GetProductString(char* str) { - static const char prd[] = INFO_PRODUCT(INFO_BOARDNAME); - for (size_t i = 0; i < sizeof(prd); ++i) str[i] = prd[i]; - return sizeof(prd) - 1; -} - -/** Get Serial Number string. -\param str Pointer to buffer to store the string. -\return String length. -*/ -__STATIC_INLINE uint8_t DAP_GetSerNumString(char* str) { return get_unique_id_u8((uint8_t*)str); } - -/** Get Target Device Vendor string. -\param str Pointer to buffer to store the string (max 60 characters). -\return String length (including terminating NULL character) or 0 (no string). -*/ -__STATIC_INLINE uint8_t DAP_GetTargetDeviceVendorString(char* str) { - (void)str; - return 0; -} - -/** Get Target Device Name string. -\param str Pointer to buffer to store the string (max 60 characters). -\return String length (including terminating NULL character) or 0 (no string). -*/ -__STATIC_INLINE uint8_t DAP_GetTargetDeviceNameString(char* str) { - (void)str; - return 0; -} - -/** Get Target Board Vendor string. -\param str Pointer to buffer to store the string (max 60 characters). -\return String length (including terminating NULL character) or 0 (no string). -*/ -__STATIC_INLINE uint8_t DAP_GetTargetBoardVendorString(char* str) { - (void)str; - return 0; -} - -/** Get Target Board Name string. -\param str Pointer to buffer to store the string (max 60 characters). -\return String length (including terminating NULL character) or 0 (no string). -*/ -__STATIC_INLINE uint8_t DAP_GetTargetBoardNameString(char* str) { - (void)str; - return 0; -} - -/* TODO! */ -/** Get Product Firmware Version string. -\param str Pointer to buffer to store the string (max 60 characters). -\return String length (including terminating NULL character) or 0 (no string). -*/ -__STATIC_INLINE uint8_t DAP_GetProductFirmwareVersionString(char* str) { - (void)str; - return 0; -} - -///@} - -//************************************************************************************************** -/** -\defgroup DAP_Config_PortIO_gr CMSIS-DAP Hardware I/O Pin Access -\ingroup DAP_ConfigIO_gr -@{ - -Standard I/O Pins of the CMSIS-DAP Hardware Debug Port support standard JTAG mode -and Serial Wire Debug (SWD) mode. In SWD mode only 2 pins are required to implement the debug -interface of a device. The following I/O Pins are provided: - -JTAG I/O Pin | SWD I/O Pin | CMSIS-DAP Hardware pin mode ----------------------------- | -------------------- | --------------------------------------------- -TCK: Test Clock | SWCLK: Clock | Output Push/Pull -TMS: Test Mode Select | SWDIO: Data I/O | Output Push/Pull; Input (for receiving data) -TDI: Test Data Input | | Output Push/Pull -TDO: Test Data Output | | Input -nTRST: Test Reset (optional) | | Output Open Drain with pull-up resistor -nRESET: Device Reset | nRESET: Device Reset | Output Open Drain with pull-up resistor - - -DAP Hardware I/O Pin Access Functions -------------------------------------- -The various I/O Pins are accessed by functions that implement the Read, Write, Set, or Clear to -these I/O Pins. - -For the SWDIO I/O Pin there are additional functions that are called in SWD I/O mode only. -This functions are provided to achieve faster I/O that is possible with some advanced GPIO -peripherals that can independently write/read a single I/O pin without affecting any other pins -of the same I/O port. The following SWDIO I/O Pin functions are provided: - - \ref PIN_SWDIO_OUT_ENABLE to enable the output mode from the DAP hardware. - - \ref PIN_SWDIO_OUT_DISABLE to enable the input mode to the DAP hardware. - - \ref PIN_SWDIO_IN to read from the SWDIO I/O pin with utmost possible speed. - - \ref PIN_SWDIO_OUT to write to the SWDIO I/O pin with utmost possible speed. -*/ - -// Configure DAP I/O pins ------------------------------ - -/** Setup JTAG I/O pins: TCK, TMS, TDI, TDO, nTRST, and nRESET. -Configures the DAP Hardware I/O pins for JTAG mode: - - TCK, TMS, TDI, nTRST, nRESET to output mode and set to high level. - - TDO to input mode. -*/ -__STATIC_INLINE void PORT_JTAG_SETUP(void) { } - -/** Setup SWD I/O pins: SWCLK, SWDIO, and nRESET. -Configures the DAP Hardware I/O pins for Serial Wire Debug (SWD) mode: - - SWCLK, SWDIO, nRESET to output mode and set to default high level. - - TDI, nTRST to HighZ mode (pins are unused in SWD mode). -*/ -__STATIC_INLINE void PORT_SWD_SETUP(void) { } - -/** Disable JTAG/SWD I/O Pins. -Disables the DAP Hardware I/O pins which configures: - - TCK/SWCLK, TMS/SWDIO, TDI, TDO, nTRST, nRESET to High-Z mode. -*/ -__STATIC_INLINE void PORT_OFF(void) { } - -// SWCLK/TCK I/O pin ------------------------------------- - -/** SWCLK/TCK I/O pin: Get Input. -\return Current status of the SWCLK/TCK DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN(void) { return 0; } - -/** SWCLK/TCK I/O pin: Set Output to High. -Set the SWCLK/TCK DAP hardware I/O pin to high level. -*/ -__STATIC_FORCEINLINE void PIN_SWCLK_TCK_SET(void) { } - -/** SWCLK/TCK I/O pin: Set Output to Low. -Set the SWCLK/TCK DAP hardware I/O pin to low level. -*/ -__STATIC_FORCEINLINE void PIN_SWCLK_TCK_CLR(void) { } - -// SWDIO/TMS Pin I/O -------------------------------------- - -/** SWDIO/TMS I/O pin: Get Input. -\return Current status of the SWDIO/TMS DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE uint32_t PIN_SWDIO_TMS_IN(void) { return 0; } - -/* PIN_SWDIO_TMS_SET and PIN_SWDIO_TMS_CLR are used by SWJ_Sequence */ - -/** SWDIO/TMS I/O pin: Set Output to High. -Set the SWDIO/TMS DAP hardware I/O pin to high level. -*/ -__STATIC_FORCEINLINE void PIN_SWDIO_TMS_SET(void) { } - -/** SWDIO/TMS I/O pin: Set Output to Low. -Set the SWDIO/TMS DAP hardware I/O pin to low level. -*/ -__STATIC_FORCEINLINE void PIN_SWDIO_TMS_CLR(void) { } - -/** SWDIO I/O pin: Get Input (used in SWD mode only). -\return Current status of the SWDIO DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE uint32_t PIN_SWDIO_IN(void) { return 0; } - -/** SWDIO I/O pin: Set Output (used in SWD mode only). -\param bit Output value for the SWDIO DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE void PIN_SWDIO_OUT(uint32_t bit) { (void)bit; } - -/** SWDIO I/O pin: Switch to Output mode (used in SWD mode only). -Configure the SWDIO DAP hardware I/O pin to output mode. This function is -called prior \ref PIN_SWDIO_OUT function calls. -*/ -__STATIC_FORCEINLINE void PIN_SWDIO_OUT_ENABLE(void) { } - -/** SWDIO I/O pin: Switch to Input mode (used in SWD mode only). -Configure the SWDIO DAP hardware I/O pin to input mode. This function is -called prior \ref PIN_SWDIO_IN function calls. -*/ -__STATIC_FORCEINLINE void PIN_SWDIO_OUT_DISABLE(void) { } - -// TDI Pin I/O --------------------------------------------- - -/** TDI I/O pin: Get Input. -\return Current status of the TDI DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE uint32_t PIN_TDI_IN(void) { return 0; } - -/** TDI I/O pin: Set Output. -\param bit Output value for the TDI DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE void PIN_TDI_OUT(uint32_t bit) { (void)bit; } - -// TDO Pin I/O --------------------------------------------- - -/** TDO I/O pin: Get Input. -\return Current status of the TDO DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE uint32_t PIN_TDO_IN(void) { return 0; } - -// nTRST Pin I/O ------------------------------------------- - -/** nTRST I/O pin: Get Input. -\return Current status of the nTRST DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE uint32_t PIN_nTRST_IN(void) { return 0; } - -/** nTRST I/O pin: Set Output. -\param bit JTAG TRST Test Reset pin status: - - 0: issue a JTAG TRST Test Reset. - - 1: release JTAG TRST Test Reset. -*/ -__STATIC_FORCEINLINE void PIN_nTRST_OUT(uint32_t bit) { (void)bit; } - -// nRESET Pin I/O------------------------------------------ - -/** nRESET I/O pin: Get Input. -\return Current status of the nRESET DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE uint32_t PIN_nRESET_IN(void) { return 0; } - -/** nRESET I/O pin: Set Output. -\param bit target device hardware reset pin status: - - 0: issue a device hardware reset. - - 1: release device hardware reset. -*/ -__STATIC_FORCEINLINE void PIN_nRESET_OUT(uint32_t bit) { (void)bit; } - -///@} - -//************************************************************************************************** -/** -\defgroup DAP_Config_LEDs_gr CMSIS-DAP Hardware Status LEDs -\ingroup DAP_ConfigIO_gr -@{ - -CMSIS-DAP Hardware may provide LEDs that indicate the status of the CMSIS-DAP Debug Unit. - -It is recommended to provide the following LEDs for status indication: - - Connect LED: is active when the DAP hardware is connected to a debugger. - - Running LED: is active when the debugger has put the target device into running state. -*/ - -/** Debug Unit: Set status of Connected LED. -\param bit status of the Connect LED. - - 1: Connect LED ON: debugger is connected to CMSIS-DAP Debug Unit. - - 0: Connect LED OFF: debugger is not connected to CMSIS-DAP Debug Unit. -*/ -__STATIC_INLINE void LED_CONNECTED_OUT(uint32_t bit) { (void)bit; } - -/** Debug Unit: Set status Target Running LED. -\param bit status of the Target Running LED. - - 1: Target Running LED ON: program execution in target started. - - 0: Target Running LED OFF: program execution in target stopped. -*/ -__STATIC_INLINE void LED_RUNNING_OUT(uint32_t bit) { (void)bit; } - -///@} - -//************************************************************************************************** -/** -\defgroup DAP_Config_Timestamp_gr CMSIS-DAP Timestamp -\ingroup DAP_ConfigIO_gr -@{ -Access function for Test Domain Timer. - -The value of the Test Domain Timer in the Debug Unit is returned by the function \ref TIMESTAMP_GET. -By default, the DWT timer is used. The frequency of this timer is configured with \ref -TIMESTAMP_CLOCK. - -*/ - -/** Get timestamp of Test Domain Timer. -\return Current timestamp value. -*/ -__STATIC_INLINE uint32_t TIMESTAMP_GET(void) { -#if TIMESTAMP_CLOCK > 0 - return (DWT->CYCCNT); -#else - return 0; -#endif -} - -///@} - -//************************************************************************************************** -/** -\defgroup DAP_Config_Initialization_gr CMSIS-DAP Initialization -\ingroup DAP_ConfigIO_gr -@{ - -CMSIS-DAP Hardware I/O and LED Pins are initialized with the function \ref DAP_SETUP. -*/ - -/** Setup of the Debug Unit I/O pins and LEDs (called when Debug Unit is initialized). -This function performs the initialization of the CMSIS-DAP Hardware I/O Pins and the -Status LEDs. In detail the operation of Hardware I/O and LED pins are enabled and set: - - I/O clock system enabled. - - all I/O pins: input buffer enabled, output pins are set to HighZ mode. - - for nTRST, nRESET a weak pull-up (if available) is enabled. - - LED output pins are enabled and LEDs are turned off. -*/ -__STATIC_INLINE void DAP_SETUP(void) { } - -/** Reset Target Device with custom specific I/O pin or command sequence. -This function allows the optional implementation of a device specific reset sequence. -It is called when the command \ref DAP_ResetTarget and is for example required -when a device needs a time-critical unlock sequence that enables the debug port. -\return 0 = no device specific reset sequence is implemented.\n - 1 = a device specific reset sequence is implemented. -*/ -__STATIC_INLINE uint8_t RESET_TARGET(void) { - return (0U); // change to '1' when a device reset sequence is implemented -} - -///@} - -#endif /* __DAP_CONFIG_H__ */ diff --git a/bsp/default/cdc_uart.c b/bsp/default/cdc_uart.c deleted file mode 100644 index 20ffd20..0000000 --- a/bsp/default/cdc_uart.c +++ /dev/null @@ -1,11 +0,0 @@ -// vim: set et: - -#include "protos.h" - -void cdc_uart_init(void) { } - -void cdc_uart_task(void) { } - -void cdc_uart_set_hwflow(bool enable) { (void)enable; } -void cdc_uart_set_baud_rate(uint32_t brate) { (void)brate; } - diff --git a/bsp/default/i2c_tinyusb.c b/bsp/default/i2c_tinyusb.c deleted file mode 100644 index 0f15073..0000000 --- a/bsp/default/i2c_tinyusb.c +++ /dev/null @@ -1,36 +0,0 @@ -// vim: set et: - -#include "i2ctinyusb.h" - -__attribute__((__const__)) enum ki2c_funcs i2ctu_get_func(void) { return 0; } - -void i2ctu_init(void) { } - -uint32_t i2ctu_set_freq(uint32_t freq, uint32_t us) { - (void)freq; - (void)us; - - return 0; -} - -enum itu_status i2ctu_write(enum ki2c_flags flags, enum itu_command startstopflags, uint16_t addr, - const uint8_t* buf, size_t len) { - (void)flags; - (void)startstopflags; - (void)addr; - (void)buf; - (void)len; - - return ITU_STATUS_ADDR_NAK; -} -enum itu_status i2ctu_read(enum ki2c_flags flags, enum itu_command startstopflags, uint16_t addr, - uint8_t* buf, size_t len) { - (void)flags; - (void)startstopflags; - (void)addr; - (void)buf; - (void)len; - - return ITU_STATUS_ADDR_NAK; -} - diff --git a/bsp/default/protocfg.h b/bsp/default/protocfg.h deleted file mode 100644 index 5a4744c..0000000 --- a/bsp/default/protocfg.h +++ /dev/null @@ -1,45 +0,0 @@ -// vim: set et: - -#ifndef PROTOCFG_H_ -#define PROTOCFG_H_ - -/*#define DBOARD_HAS_UART -#define DBOARD_HAS_CMSISDAP -#define DBOARD_HAS_SERPROG -#define DBOARD_HAS_I2C -#define DBOARD_HAS_TEMPSENSOR*/ - -enum { - /*HID_N_CMSISDAP = 0,*/ - - HID_N__NITF -}; -enum { -/*CDC_N_UART = 0, -CDC_N_SERPROG,*/ -#ifdef USE_USBCDC_FOR_STDIO - CDC_N_STDIO, -#endif - - CDC_N__NITF -}; -enum { VND_N__NITF = 0 }; - -#define CFG_TUD_HID 0 -#ifdef USE_USBCDC_FOR_STDIO -#define CFG_TUD_CDC 1 -#else -#define CFG_TUD_CDC 0 -#endif -#define CFG_TUD_VENDOR 0 - -/*#define USB_VID 0x2e8a*/ /* Raspberry Pi */ -#define USB_VID 0xcafe /* TinyUSB */ -/*#define USB_VID 0x1209*/ /* Generic */ -/*#define USB_VID 0x1d50*/ /* OpenMoko */ -#define USB_PID 0x1312 - -#define INFO_BOARDNAME "Unknown" - -#endif - diff --git a/bsp/default/spi_serprog.c b/bsp/default/spi_serprog.c deleted file mode 100644 index ce79052..0000000 --- a/bsp/default/spi_serprog.c +++ /dev/null @@ -1,26 +0,0 @@ -// vim: set et: - -#include "protos.h" -#include "serprog.h" - -void sp_spi_init(void) { } - -uint32_t __not_in_flash_func(sp_spi_set_freq)(uint32_t freq_wanted) { - (void)freq_wanted; - return 0; -} - -void __not_in_flash_func(sp_spi_cs_deselect)(void) { } -void __not_in_flash_func(sp_spi_cs_select)(void) { } -void __not_in_flash_func(sp_spi_op_begin)(void) { } -void __not_in_flash_func(sp_spi_op_end)(void) { } - -void __not_in_flash_func(sp_spi_op_write)(uint32_t write_len, const uint8_t* write_data) { - (void)write_len; - (void)write_data; -} -void __not_in_flash_func(sp_spi_op_read)(uint32_t read_len, uint8_t* read_data) { - (void)read_len; - (void)read_data; -} - diff --git a/bsp/default/tempsensor.c b/bsp/default/tempsensor.c deleted file mode 100644 index 6e067a3..0000000 --- a/bsp/default/tempsensor.c +++ /dev/null @@ -1,14 +0,0 @@ -// vim: set et: - -#include "tempsensor.h" - -void tempsense_dev_init(void) { } - -// clang-format off -// 8.4 -int16_t tempsense_dev_get_temp (void) { return 0 << 4; } -int16_t tempsense_dev_get_lower(void) { return trunc_8fix4(float2fix( 0)); } -int16_t tempsense_dev_get_upper(void) { return trunc_8fix4(float2fix( 0)); } -int16_t tempsense_dev_get_crit (void) { return trunc_8fix4(float2fix( 0)); } -// clang-format on - diff --git a/bsp/rp2040/DAP_config.h b/bsp/rp2040/DAP_config.h deleted file mode 100644 index 6e323b0..0000000 --- a/bsp/rp2040/DAP_config.h +++ /dev/null @@ -1,625 +0,0 @@ -// vim: set et: -/* - * The MIT License (MIT) - * - * Copyright (c) 2021 Peter Lawrence - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* -This DAP_config provides a CMSIS-DAP alternative to picoprobe and raspberrypi-swd.cfg -*/ - -#ifndef __DAP_CONFIG_H__ -#define __DAP_CONFIG_H__ - -//************************************************************************************************** -/** -\defgroup DAP_Config_Debug_gr CMSIS-DAP Debug Unit Information -\ingroup DAP_ConfigIO_gr -@{ -Provides definitions about the hardware and configuration of the Debug Unit. - -This information includes: - - Definition of Cortex-M processor parameters used in CMSIS-DAP Debug Unit. - - Debug Unit Identification strings (Vendor, Product, Serial Number). - - Debug Unit communication packet size. - - Debug Access Port supported modes and settings (JTAG/SWD and SWO). - - Optional information about a connected Target Device (for Evaluation Boards). -*/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bsp/board.h" -#include "cmsis_compiler.h" -#include "pinout.h" -#include "protos.h" -#include "util.h" - -#define PINOUT_SWCLK PINOUT_JTAG_TCK -#define PINOUT_SWDIO PINOUT_JTAG_TMS - -#define PINOUT_SWCLK_MASK (1UL << PINOUT_SWCLK) -#define PINOUT_SWDIO_MASK (1UL << PINOUT_SWDIO) - -#define PINOUT_TCK_MASK (1UL << PINOUT_JTAG_TCK) -#define PINOUT_TMS_MASK (1UL << PINOUT_JTAG_TMS) -#define PINOUT_TDI_MASK (1UL << PINOUT_JTAG_TDI) -#define PINOUT_TDO_MASK (1UL << PINOUT_JTAG_TDO) -#define PINOUT_nTRST_MASK (1UL << PINOUT_JTAG_nTRST) -#define PINOUT_nRESET_MASK (1UL << PINOUT_JTAG_nRESET) - -#define PINOUT_LED_MASK (1UL << PINOUT_LED) - -/// Processor Clock of the Cortex-M MCU used in the Debug Unit. -/// This value is used to calculate the SWD/JTAG clock speed. -#define CPU_CLOCK 48000000U ///< Specifies the CPU Clock in Hz. - -/// Number of processor cycles for I/O Port write operations. -/// This value is used to calculate the SWD/JTAG clock speed that is generated with I/O -/// Port write operations in the Debug Unit by a Cortex-M MCU. Most Cortex-M processors -/// require 2 processor cycles for a I/O Port Write operation. If the Debug Unit uses -/// a Cortex-M0+ processor with high-speed peripheral I/O only 1 processor cycle might be -/// required. -#define IO_PORT_WRITE_CYCLES 2U ///< I/O Cycles: 2=default, 1=Cortex-M0+ fast I/0. - -/// Indicate that Serial Wire Debug (SWD) communication mode is available at the Debug Access Port. -/// This information is returned by the command \ref DAP_Info as part of Capabilities. -#define DAP_SWD 1 ///< SWD Mode: 1 = available, 0 = not available. - -/// Indicate that JTAG communication mode is available at the Debug Port. -/// This information is returned by the command \ref DAP_Info as part of Capabilities. -#define DAP_JTAG 1 ///< JTAG Mode: 1 = available, 0 = not available. - -/// Configure maximum number of JTAG devices on the scan chain connected to the Debug Access Port. -/// This setting impacts the RAM requirements of the Debug Unit. Valid range is 1 .. 255. -#define DAP_JTAG_DEV_CNT 8U ///< Maximum number of JTAG devices on scan chain. - -/// Default communication mode on the Debug Access Port. -/// Used for the command \ref DAP_Connect when Port Default mode is selected. -#define DAP_DEFAULT_PORT 2U ///< Default JTAG/SWJ Port Mode: 1 = SWD, 2 = JTAG. - -/// Default communication speed on the Debug Access Port for SWD and JTAG mode. -/// Used to initialize the default SWD/JTAG clock frequency. -/// The command \ref DAP_SWJ_Clock can be used to overwrite this default setting. -#define DAP_DEFAULT_SWJ_CLOCK 1000000U ///< Default SWD/JTAG clock frequency in Hz. - -/// Maximum Package Size for Command and Response data. -/// This configuration settings is used to optimize the communication performance with the -/// debugger and depends on the USB peripheral. Typical vales are 64 for Full-speed USB HID or -/// WinUSB, 1024 for High-speed USB HID and 512 for High-speed USB WinUSB. -#define DAP_PACKET_SIZE CFG_TUD_HID_EP_BUFSIZE ///< Specifies Packet Size in bytes. - -/// Maximum Package Buffers for Command and Response data. -/// This configuration settings is used to optimize the communication performance with the -/// debugger and depends on the USB peripheral. For devices with limited RAM or USB buffer the -/// setting can be reduced (valid range is 1 .. 255). -#define DAP_PACKET_COUNT 1U ///< Specifies number of packets buffered. - -/// Indicate that UART Serial Wire Output (SWO) trace is available. -/// This information is returned by the command \ref DAP_Info as part of Capabilities. -#define SWO_UART 0 ///< SWO UART: 1 = available, 0 = not available. - -/// Maximum SWO UART Baudrate. -#define SWO_UART_MAX_BAUDRATE 10000000U ///< SWO UART Maximum Baudrate in Hz. - -/// Indicate that Manchester Serial Wire Output (SWO) trace is available. -/// This information is returned by the command \ref DAP_Info as part of Capabilities. -#define SWO_MANCHESTER 0 ///< SWO Manchester: 1 = available, 0 = not available. - -/// SWO Trace Buffer Size. -#define SWO_BUFFER_SIZE 4096U ///< SWO Trace Buffer Size in bytes (must be 2^n). - -/// SWO Streaming Trace. -#define SWO_STREAM 0 ///< SWO Streaming Trace: 1 = available, 0 = not available. - -/// Indicate that UART Communication Port is available. -/// This information is returned by the command \ref DAP_Info as part of Capabilities. -#define DAP_UART 0 ///< DAP UART: 1 = available, 0 = not available. - -/// USART Driver instance number for the UART Communication Port. -#define DAP_UART_DRIVER 1 ///< USART Driver instance number (Driver_USART#). - -/// UART Receive Buffer Size. -#define DAP_UART_RX_BUFFER_SIZE 64U ///< Uart Receive Buffer Size in bytes (must be 2^n). - -/// UART Transmit Buffer Size. -#define DAP_UART_TX_BUFFER_SIZE 64U ///< Uart Transmit Buffer Size in bytes (must be 2^n). - -/// Indicate that UART Communication via USB COM Port is available. -/// This information is returned by the command \ref DAP_Info as part of Capabilities. -#ifdef USE_USBCDC_FOR_STDIO -#define DAP_UART_USB_COM_PORT 1 ///< USB COM Port: 1 = available, 0 = not available. -#else -#define DAP_UART_USB_COM_PORT 0 -#endif - -/// Clock frequency of the Test Domain Timer. Timer value is returned with \ref TIMESTAMP_GET. -#define TIMESTAMP_CLOCK 0U ///< Timestamp clock in Hz (0 = timestamps not supported). - -/// Debug Unit is connected to fixed Target Device. -/// The Debug Unit may be part of an evaluation board and always connected to a fixed -/// known device. In this case a Device Vendor and Device Name string is stored which -/// may be used by the debugger or IDE to configure device parameters. -#define TARGET_DEVICE_FIXED 0 ///< Target Device: 1 = known, 0 = unknown; - -#if TARGET_DEVICE_FIXED -#define TARGET_DEVICE_VENDOR "Raspberry Pi" ///< String indicating the Silicon Vendor -#define TARGET_DEVICE_NAME "Pico" ///< String indicating the Target Device -#endif - -#include "DAP.h" - -/** Get Vendor ID string. -\param str Pointer to buffer to store the string. -\return String length. -*/ -__STATIC_INLINE uint8_t DAP_GetVendorString(char* str) { - static const char vnd[] = INFO_MANUFACTURER; - for (size_t i = 0; i < sizeof(vnd); ++i) str[i] = vnd[i]; - return sizeof(vnd) - 1; -} - -/** Get Product ID string. -\param str Pointer to buffer to store the string. -\return String length. -*/ -__STATIC_INLINE uint8_t DAP_GetProductString(char* str) { - static const char prd[] = INFO_PRODUCT(INFO_BOARDNAME); - for (size_t i = 0; i < sizeof(prd); ++i) str[i] = prd[i]; - return sizeof(prd) - 1; -} - -/** Get Serial Number string. -\param str Pointer to buffer to store the string. -\return String length. -*/ -__STATIC_INLINE uint8_t DAP_GetSerNumString(char* str) { return get_unique_id_u8((uint8_t*)str); } - -/** Get Target Device Vendor string. -\param str Pointer to buffer to store the string (max 60 characters). -\return String length (including terminating NULL character) or 0 (no string). -*/ -__STATIC_INLINE uint8_t DAP_GetTargetDeviceVendorString(char* str) { - (void)str; - return 0; -} - -/** Get Target Device Name string. -\param str Pointer to buffer to store the string (max 60 characters). -\return String length (including terminating NULL character) or 0 (no string). -*/ -__STATIC_INLINE uint8_t DAP_GetTargetDeviceNameString(char* str) { - (void)str; - return 0; -} - -/** Get Target Board Vendor string. -\param str Pointer to buffer to store the string (max 60 characters). -\return String length (including terminating NULL character) or 0 (no string). -*/ -__STATIC_INLINE uint8_t DAP_GetTargetBoardVendorString(char* str) { - (void)str; - return 0; -} - -/** Get Target Board Name string. -\param str Pointer to buffer to store the string (max 60 characters). -\return String length (including terminating NULL character) or 0 (no string). -*/ -__STATIC_INLINE uint8_t DAP_GetTargetBoardNameString(char* str) { - (void)str; - return 0; -} - -/* TODO! */ -/** Get Product Firmware Version string. -\param str Pointer to buffer to store the string (max 60 characters). -\return String length (including terminating NULL character) or 0 (no string). -*/ -__STATIC_INLINE uint8_t DAP_GetProductFirmwareVersionString(char* str) { - (void)str; - return 0; -} - -///@} - -//************************************************************************************************** -/** -\defgroup DAP_Config_PortIO_gr CMSIS-DAP Hardware I/O Pin Access -\ingroup DAP_ConfigIO_gr -@{ - -Standard I/O Pins of the CMSIS-DAP Hardware Debug Port support standard JTAG mode -and Serial Wire Debug (SWD) mode. In SWD mode only 2 pins are required to implement the debug -interface of a device. The following I/O Pins are provided: - -JTAG I/O Pin | SWD I/O Pin | CMSIS-DAP Hardware pin mode ----------------------------- | -------------------- | --------------------------------------------- -TCK: Test Clock | SWCLK: Clock | Output Push/Pull -TMS: Test Mode Select | SWDIO: Data I/O | Output Push/Pull; Input (for receiving data) -TDI: Test Data Input | | Output Push/Pull -TDO: Test Data Output | | Input -nTRST: Test Reset (optional) | | Output Open Drain with pull-up resistor -nRESET: Device Reset | nRESET: Device Reset | Output Open Drain with pull-up resistor - - -DAP Hardware I/O Pin Access Functions -------------------------------------- -The various I/O Pins are accessed by functions that implement the Read, Write, Set, or Clear to -these I/O Pins. - -For the SWDIO I/O Pin there are additional functions that are called in SWD I/O mode only. -This functions are provided to achieve faster I/O that is possible with some advanced GPIO -peripherals that can independently write/read a single I/O pin without affecting any other pins -of the same I/O port. The following SWDIO I/O Pin functions are provided: - - \ref PIN_SWDIO_OUT_ENABLE to enable the output mode from the DAP hardware. - - \ref PIN_SWDIO_OUT_DISABLE to enable the input mode to the DAP hardware. - - \ref PIN_SWDIO_IN to read from the SWDIO I/O pin with utmost possible speed. - - \ref PIN_SWDIO_OUT to write to the SWDIO I/O pin with utmost possible speed. -*/ - -// Configure DAP I/O pins ------------------------------ - -/** Setup JTAG I/O pins: TCK, TMS, TDI, TDO, nTRST, and nRESET. -Configures the DAP Hardware I/O pins for JTAG mode: - - TCK, TMS, TDI, nTRST, nRESET to output mode and set to high level. - - TDO to input mode. -*/ -__STATIC_INLINE void PORT_JTAG_SETUP(void) { - resets_hw->reset &= ~(RESETS_RESET_IO_BANK0_BITS | RESETS_RESET_PADS_BANK0_BITS); - - /* set to default high level */ - sio_hw->gpio_oe_set = PINOUT_TCK_MASK | PINOUT_TMS_MASK | PINOUT_TDI_MASK | PINOUT_nTRST_MASK | - PINOUT_nRESET_MASK; - sio_hw->gpio_set = PINOUT_TCK_MASK | PINOUT_TMS_MASK | PINOUT_TDI_MASK | PINOUT_nTRST_MASK | - PINOUT_nRESET_MASK; - /* TDO needs to be an input */ - sio_hw->gpio_oe_clr = PINOUT_TDO_MASK; - - hw_write_masked(&padsbank0_hw->io[PINOUT_JTAG_TCK], - PADS_BANK0_GPIO0_IE_BITS, // bits to set: input enable - PADS_BANK0_GPIO0_IE_BITS | - PADS_BANK0_GPIO0_OD_BITS); // bits to mask out: input enable, output disable - hw_write_masked(&padsbank0_hw->io[PINOUT_JTAG_TMS], PADS_BANK0_GPIO0_IE_BITS, - PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS); - hw_write_masked(&padsbank0_hw->io[PINOUT_JTAG_TDI], PADS_BANK0_GPIO0_IE_BITS, - PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS); - hw_write_masked(&padsbank0_hw->io[PINOUT_JTAG_TDO], - PADS_BANK0_GPIO0_IE_BITS | - PADS_BANK0_GPIO0_OD_BITS, // TDO needs to have its output disabled - PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS); - hw_write_masked(&padsbank0_hw->io[PINOUT_JTAG_nTRST], PADS_BANK0_GPIO0_IE_BITS, - PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS); - hw_write_masked(&padsbank0_hw->io[PINOUT_JTAG_nRESET], PADS_BANK0_GPIO0_IE_BITS, - PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS); - - // NOTE: hiZ: ctrl = (ctrl & ~(CTRL_OEOVER_BITS)) | (GPIO_OVERRIDE_LOW << CTRL_OEOVER_LSB); - // normal == 0, low == 2 - - // set pin modes to general IO (SIO) - iobank0_hw->io[PINOUT_JTAG_TCK].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB; - iobank0_hw->io[PINOUT_JTAG_TMS].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB; - iobank0_hw->io[PINOUT_JTAG_TDI].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB; - iobank0_hw->io[PINOUT_JTAG_TDO].ctrl = (GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB) - /*| (GPIO_OVERRIDE_LOW << IO_BANK0_GPIO0_CTRL_OEOVER_LSB)*/; - iobank0_hw->io[PINOUT_JTAG_nTRST].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB; - iobank0_hw->io[PINOUT_JTAG_nRESET].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB; -} - -/** Setup SWD I/O pins: SWCLK, SWDIO, and nRESET. -Configures the DAP Hardware I/O pins for Serial Wire Debug (SWD) mode: - - SWCLK, SWDIO, nRESET to output mode and set to default high level. - - TDI, nTRST to HighZ mode (pins are unused in SWD mode). -*/ -__STATIC_INLINE void PORT_SWD_SETUP(void) { - resets_hw->reset &= ~(RESETS_RESET_IO_BANK0_BITS | RESETS_RESET_PADS_BANK0_BITS); - - /* set to default high level */ - sio_hw->gpio_oe_set = PINOUT_SWCLK_MASK | PINOUT_SWDIO_MASK; - sio_hw->gpio_set = PINOUT_SWCLK_MASK | PINOUT_SWDIO_MASK; - - hw_write_masked(&padsbank0_hw->io[PINOUT_SWCLK], PADS_BANK0_GPIO0_IE_BITS, - PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS); - hw_write_masked(&padsbank0_hw->io[PINOUT_SWDIO], PADS_BANK0_GPIO0_IE_BITS, - PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS); - iobank0_hw->io[PINOUT_SWCLK].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB; - iobank0_hw->io[PINOUT_SWDIO].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB; -} - -/** Disable JTAG/SWD I/O Pins. -Disables the DAP Hardware I/O pins which configures: - - TCK/SWCLK, TMS/SWDIO, TDI, TDO, nTRST, nRESET to High-Z mode. -*/ -__STATIC_INLINE void PORT_OFF(void) { - sio_hw->gpio_oe_clr = PINOUT_SWCLK_MASK | PINOUT_SWDIO_MASK | - PINOUT_TDI_MASK //| PINOUT_TDO_MASK - | PINOUT_nTRST_MASK | PINOUT_nRESET_MASK; -} - -// SWCLK/TCK I/O pin ------------------------------------- - -/** SWCLK/TCK I/O pin: Get Input. -\return Current status of the SWCLK/TCK DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN(void) { - return (sio_hw->gpio_in & PINOUT_SWCLK_MASK) >> PINOUT_SWCLK; -} - -/** SWCLK/TCK I/O pin: Set Output to High. -Set the SWCLK/TCK DAP hardware I/O pin to high level. -*/ -__STATIC_FORCEINLINE void PIN_SWCLK_TCK_SET(void) { sio_hw->gpio_set = PINOUT_SWCLK_MASK; } - -/** SWCLK/TCK I/O pin: Set Output to Low. -Set the SWCLK/TCK DAP hardware I/O pin to low level. -*/ -__STATIC_FORCEINLINE void PIN_SWCLK_TCK_CLR(void) { sio_hw->gpio_clr = PINOUT_SWCLK_MASK; } - -// SWDIO/TMS Pin I/O -------------------------------------- - -/** SWDIO/TMS I/O pin: Get Input. -\return Current status of the SWDIO/TMS DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE uint32_t PIN_SWDIO_TMS_IN(void) { - return (sio_hw->gpio_in & PINOUT_SWDIO_MASK) >> PINOUT_SWDIO; -} - -/* PIN_SWDIO_TMS_SET and PIN_SWDIO_TMS_CLR are used by SWJ_Sequence */ - -/** SWDIO/TMS I/O pin: Set Output to High. -Set the SWDIO/TMS DAP hardware I/O pin to high level. -*/ -__STATIC_FORCEINLINE void PIN_SWDIO_TMS_SET(void) { sio_hw->gpio_set = PINOUT_SWDIO_MASK; } - -/** SWDIO/TMS I/O pin: Set Output to Low. -Set the SWDIO/TMS DAP hardware I/O pin to low level. -*/ -__STATIC_FORCEINLINE void PIN_SWDIO_TMS_CLR(void) { sio_hw->gpio_clr = PINOUT_SWDIO_MASK; } - -/** SWDIO I/O pin: Get Input (used in SWD mode only). -\return Current status of the SWDIO DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE uint32_t PIN_SWDIO_IN(void) { - return (sio_hw->gpio_in & PINOUT_SWDIO_MASK) ? 1U : 0U; -} - -/** SWDIO I/O pin: Set Output (used in SWD mode only). -\param bit Output value for the SWDIO DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE void PIN_SWDIO_OUT(uint32_t bit) { - if (bit & 1) - sio_hw->gpio_set = PINOUT_SWDIO_MASK; - else - sio_hw->gpio_clr = PINOUT_SWDIO_MASK; -} - -/** SWDIO I/O pin: Switch to Output mode (used in SWD mode only). -Configure the SWDIO DAP hardware I/O pin to output mode. This function is -called prior \ref PIN_SWDIO_OUT function calls. -*/ -__STATIC_FORCEINLINE void PIN_SWDIO_OUT_ENABLE(void) { sio_hw->gpio_oe_set = PINOUT_SWDIO_MASK; } - -/** SWDIO I/O pin: Switch to Input mode (used in SWD mode only). -Configure the SWDIO DAP hardware I/O pin to input mode. This function is -called prior \ref PIN_SWDIO_IN function calls. -*/ -__STATIC_FORCEINLINE void PIN_SWDIO_OUT_DISABLE(void) { sio_hw->gpio_oe_clr = PINOUT_SWDIO_MASK; } - -// TDI Pin I/O --------------------------------------------- - -/** TDI I/O pin: Get Input. -\return Current status of the TDI DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE uint32_t PIN_TDI_IN(void) { - return (sio_hw->gpio_in & PINOUT_TDI_MASK) >> PINOUT_JTAG_TDI; -} - -/** TDI I/O pin: Set Output. -\param bit Output value for the TDI DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE void PIN_TDI_OUT(uint32_t bit) { - if (bit & 1) - sio_hw->gpio_set = PINOUT_TDI_MASK; - else - sio_hw->gpio_clr = PINOUT_TDI_MASK; -} - -// TDO Pin I/O --------------------------------------------- - -/** TDO I/O pin: Get Input. -\return Current status of the TDO DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE uint32_t PIN_TDO_IN(void) { - return (sio_hw->gpio_in & PINOUT_TDO_MASK) >> PINOUT_JTAG_TDO; -} - -// nTRST Pin I/O ------------------------------------------- - -/** nTRST I/O pin: Get Input. -\return Current status of the nTRST DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE uint32_t PIN_nTRST_IN(void) { - return (sio_hw->gpio_in & PINOUT_nTRST_MASK) >> PINOUT_JTAG_nTRST; -} - -/** nTRST I/O pin: Set Output. -\param bit JTAG TRST Test Reset pin status: - - 0: issue a JTAG TRST Test Reset. - - 1: release JTAG TRST Test Reset. -*/ -__STATIC_FORCEINLINE void PIN_nTRST_OUT(uint32_t bit) { - if (bit & 1) - sio_hw->gpio_set = PINOUT_nTRST_MASK; - else - sio_hw->gpio_clr = PINOUT_nTRST_MASK; -} - -// nRESET Pin I/O------------------------------------------ - -/** nRESET I/O pin: Get Input. -\return Current status of the nRESET DAP hardware I/O pin. -*/ -__STATIC_FORCEINLINE uint32_t PIN_nRESET_IN(void) { - return (sio_hw->gpio_in & PINOUT_nRESET_MASK) >> PINOUT_JTAG_nRESET; -} - -/** nRESET I/O pin: Set Output. -\param bit target device hardware reset pin status: - - 0: issue a device hardware reset. - - 1: release device hardware reset. -*/ -__STATIC_FORCEINLINE void PIN_nRESET_OUT(uint32_t bit) { - if (bit & 1) - sio_hw->gpio_set = PINOUT_nRESET_MASK; - else - sio_hw->gpio_clr = PINOUT_nRESET_MASK; -} - -///@} - -//************************************************************************************************** -/** -\defgroup DAP_Config_LEDs_gr CMSIS-DAP Hardware Status LEDs -\ingroup DAP_ConfigIO_gr -@{ - -CMSIS-DAP Hardware may provide LEDs that indicate the status of the CMSIS-DAP Debug Unit. - -It is recommended to provide the following LEDs for status indication: - - Connect LED: is active when the DAP hardware is connected to a debugger. - - Running LED: is active when the debugger has put the target device into running state. -*/ - -/** Debug Unit: Set status of Connected LED. -\param bit status of the Connect LED. - - 1: Connect LED ON: debugger is connected to CMSIS-DAP Debug Unit. - - 0: Connect LED OFF: debugger is not connected to CMSIS-DAP Debug Unit. -*/ -__STATIC_INLINE void LED_CONNECTED_OUT(uint32_t bit) { -#if PINOUT_LED_CONNECTED - if (bit & 1) - sio_hw->gpio_set = PINOUT_LED_MASK; - else - sio_hw->gpio_clr = PINOUT_LED_MASK; -#else - (void)bit; -#endif -} - -/** Debug Unit: Set status Target Running LED. -\param bit status of the Target Running LED. - - 1: Target Running LED ON: program execution in target started. - - 0: Target Running LED OFF: program execution in target stopped. -*/ -__STATIC_INLINE void LED_RUNNING_OUT(uint32_t bit) { -#if PINOUT_LED_RUNNING - if (bit & 1) - sio_hw->gpio_set = PINOUT_LED_MASK; - else - sio_hw->gpio_clr = PINOUT_LED_MASK; -#else - (void)bit; -#endif -} - -///@} - -//************************************************************************************************** -/** -\defgroup DAP_Config_Timestamp_gr CMSIS-DAP Timestamp -\ingroup DAP_ConfigIO_gr -@{ -Access function for Test Domain Timer. - -The value of the Test Domain Timer in the Debug Unit is returned by the function \ref TIMESTAMP_GET. -By default, the DWT timer is used. The frequency of this timer is configured with \ref -TIMESTAMP_CLOCK. - -*/ - -/** Get timestamp of Test Domain Timer. -\return Current timestamp value. -*/ -__STATIC_INLINE uint32_t TIMESTAMP_GET(void) { -#if TIMESTAMP_CLOCK > 0 - return (DWT->CYCCNT); -#else - return 0; -#endif -} - -///@} - -//************************************************************************************************** -/** -\defgroup DAP_Config_Initialization_gr CMSIS-DAP Initialization -\ingroup DAP_ConfigIO_gr -@{ - -CMSIS-DAP Hardware I/O and LED Pins are initialized with the function \ref DAP_SETUP. -*/ - -/** Setup of the Debug Unit I/O pins and LEDs (called when Debug Unit is initialized). -This function performs the initialization of the CMSIS-DAP Hardware I/O Pins and the -Status LEDs. In detail the operation of Hardware I/O and LED pins are enabled and set: - - I/O clock system enabled. - - all I/O pins: input buffer enabled, output pins are set to HighZ mode. - - for nTRST, nRESET a weak pull-up (if available) is enabled. - - LED output pins are enabled and LEDs are turned off. -*/ -__STATIC_INLINE void DAP_SETUP(void) { - sio_hw->gpio_oe_set = PINOUT_LED_MASK; - sio_hw->gpio_clr = PINOUT_LED_MASK; - - hw_write_masked( - &padsbank0_hw->io[PINOUT_LED], 0, PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS); - iobank0_hw->io[PINOUT_LED].ctrl = GPIO_FUNC_SIO << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB; - - bi_decl(bi_2pins_with_names(PINOUT_JTAG_TCK, "TCK / SWCLK", PINOUT_JTAG_TMS, "TMS / SWDIO")); - bi_decl(bi_4pins_with_names(PINOUT_JTAG_TDI, "TDI", PINOUT_JTAG_TDO, "TDO", PINOUT_JTAG_nTRST, - "nTRST", PINOUT_JTAG_nRESET, "nRESET")); -} - -/** Reset Target Device with custom specific I/O pin or command sequence. -This function allows the optional implementation of a device specific reset sequence. -It is called when the command \ref DAP_ResetTarget and is for example required -when a device needs a time-critical unlock sequence that enables the debug port. -\return 0 = no device specific reset sequence is implemented.\n - 1 = a device specific reset sequence is implemented. -*/ -__STATIC_INLINE uint8_t RESET_TARGET(void) { - return (0U); // change to '1' when a device reset sequence is implemented -} - -///@} - -#endif /* __DAP_CONFIG_H__ */ diff --git a/bsp/rp2040/cdc_stdio.c b/bsp/rp2040/cdc_stdio.c index a4e4754..d632a7f 100644 --- a/bsp/rp2040/cdc_stdio.c +++ b/bsp/rp2040/cdc_stdio.c @@ -7,8 +7,8 @@ #include #include -#include "pinout.h" -#include "protocfg.h" +//#include "pinout.h" +//#include "protocfg.h" #include "tusb.h" #ifndef PICO_STDIO_USB_STDOUT_TIMEOUT_US @@ -18,6 +18,7 @@ // *mostly* the same as the SDK code, *except* we have to explicitely pass the // CDC interface number to the tusb functions, making the SDK code itself very // non-reusable >__> +#define CDC_N_STDIO 0 static mutex_t stdio_usb_mutex; diff --git a/bsp/rp2040/cdc_uart.c b/bsp/rp2040/cdc_uart.c deleted file mode 100644 index 239c239..0000000 --- a/bsp/rp2040/cdc_uart.c +++ /dev/null @@ -1,72 +0,0 @@ -// vim: set et: -/* - * The MIT License (MIT) - * - * Copyright (c) 2021 Raspberry Pi (Trading) Ltd. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -#include -#include - -#include "pinout.h" -#include "protos.h" -#include "tusb.h" - -static uint8_t rx_buf[CFG_TUD_CDC_RX_BUFSIZE]; -static uint8_t tx_buf[CFG_TUD_CDC_TX_BUFSIZE]; - -void cdc_uart_init(void) { - gpio_set_function(PINOUT_UART_TX, GPIO_FUNC_UART); - gpio_set_function(PINOUT_UART_RX, GPIO_FUNC_UART); - uart_init(PINOUT_UART_INTERFACE, PINOUT_UART_BAUDRATE); - - bi_decl(bi_2pins_with_func(PINOUT_UART_TX, PINOUT_UART_RX, GPIO_FUNC_UART)); -} - -void cdc_uart_task(void) { - // Consume uart fifo regardless even if not connected - uint rx_len = 0; - while (uart_is_readable(PINOUT_UART_INTERFACE) && (rx_len < sizeof(rx_buf))) { - rx_buf[rx_len++] = uart_getc(PINOUT_UART_INTERFACE); - } - - if (tud_cdc_n_connected(CDC_N_UART)) { - // Do we have anything to display on the host's terminal? - if (rx_len) { - for (uint i = 0; i < rx_len; i++) { tud_cdc_n_write_char(CDC_N_UART, rx_buf[i]); } - tud_cdc_n_write_flush(CDC_N_UART); - } - - if (tud_cdc_n_available(CDC_N_UART)) { - // Is there any data from the host for us to tx - uint tx_len = tud_cdc_n_read(CDC_N_UART, tx_buf, sizeof(tx_buf)); - uart_write_blocking(PINOUT_UART_INTERFACE, tx_buf, tx_len); - } - } -} - -void cdc_uart_set_hwflow(bool enable) { uart_set_hw_flow(PINOUT_UART_INTERFACE, enable, enable); } - -void cdc_uart_set_baudrate(uint32_t brate) { - uart_init(PINOUT_UART_INTERFACE, brate); -} - diff --git a/bsp/rp2040/i2c_tinyusb.c b/bsp/rp2040/i2c_tinyusb.c deleted file mode 100644 index f7303f5..0000000 --- a/bsp/rp2040/i2c_tinyusb.c +++ /dev/null @@ -1,449 +0,0 @@ -// vim: set et: - -#include - -#include -#include -#include -#include -#include -#include - -#include "i2ctinyusb.h" -#include "pinout.h" -#include "protocfg.h" - -static int delay = 10, delay2 = 5; - -// I2C bitbang reimpl because ugh, synopsys -// (mostly inspired by original I2CTinyUSB AVR firmware) -__attribute__((__always_inline__)) inline static void i2cio_set_sda(bool hi) { - if (hi) { - sio_hw->gpio_oe_clr = (1 << PINOUT_I2C_SDA); // SDA is input - // => pullup configured, so it'll go high - } else { - sio_hw->gpio_oe_set = (1 << PINOUT_I2C_SDA); // SDA is output - sio_hw->gpio_clr = (1 << PINOUT_I2C_SDA); // and drive it low - } -} -__attribute__((__always_inline__)) inline static bool i2cio_get_sda(void) { - return (sio_hw->gpio_in & (1 << PINOUT_I2C_SDA)) != 0; -} -__attribute__((__always_inline__)) inline static void i2cio_set_scl(bool hi) { - busy_wait_us_32(delay2); - sio_hw->gpio_oe_set = (1 << PINOUT_I2C_SCL); // SCL is output - if (hi) - sio_hw->gpio_set = (1 << PINOUT_I2C_SCL); // SCL is high - else - sio_hw->gpio_clr = (1 << PINOUT_I2C_SCL); // SCL is low - busy_wait_us_32(delay2); -} - -__attribute__((__always_inline__)) inline static void i2cio_scl_toggle(void) { - i2cio_set_scl(true); - i2cio_set_scl(false); -} - -static void __no_inline_not_in_flash_func(i2cio_start)(void) { // start condition - i2cio_set_sda(false); - i2cio_set_scl(false); -} -static void __no_inline_not_in_flash_func(i2cio_repstart)(void) { // repstart condition - i2cio_set_sda(true); - i2cio_set_scl(true); - - i2cio_set_sda(false); - i2cio_set_scl(false); -} -static void __no_inline_not_in_flash_func(i2cio_stop)(void) { // stop condition - i2cio_set_sda(false); - i2cio_set_scl(true); - i2cio_set_sda(true); -} - -static bool __no_inline_not_in_flash_func(i2cio_write7)( - uint8_t v) { // return value: acked? // needed for 10bitaddr xfers - for (int i = 6; i >= 0; --i) { - i2cio_set_sda((v & (1 << i)) != 0); - i2cio_scl_toggle(); - } - - i2cio_set_sda(true); - i2cio_set_scl(true); - - bool ack = !i2cio_get_sda(); - i2cio_set_scl(false); - - return ack; -} -static bool __no_inline_not_in_flash_func(i2cio_write8)(uint8_t v) { // return value: acked? - for (int i = 7; i >= 0; --i) { - i2cio_set_sda((v & (1 << i)) != 0); - i2cio_scl_toggle(); - } - - i2cio_set_sda(true); - i2cio_set_scl(true); - - bool ack = !i2cio_get_sda(); - i2cio_set_scl(false); - - return ack; -} -static uint8_t __no_inline_not_in_flash_func(i2cio_read8)(bool last) { - i2cio_set_sda(true); - i2cio_set_scl(false); - - uint8_t rv = 0; - for (int i = 7; i >= 0; --i) { - i2cio_set_scl(true); - bool c = i2cio_get_sda(); - rv <<= 1; - if (c) rv |= 1; - i2cio_set_scl(false); - } - - if (last) - i2cio_set_sda(true); - else - i2cio_set_sda(false); - - i2cio_scl_toggle(); - i2cio_set_sda(true); - - return rv; -} - -// replicating/rewriting some SDK functions because they don't do what I want -// so I'm making better ones - -static int __no_inline_not_in_flash_func(i2cex_probe_address)(uint16_t addr, bool a10bit) { - // I2C pins to SIO - gpio_set_function(PINOUT_I2C_SCL, GPIO_FUNC_SIO); - gpio_set_function(PINOUT_I2C_SDA, GPIO_FUNC_SIO); - - int rv; - i2cio_start(); - - if (a10bit) { - // A10 magic higher 2 addr bits r/#w bit - uint8_t addr1 = 0x70 | (((addr >> 8) & 3) << 1) | 0, addr2 = addr & 0xff; - - if (i2cio_write7(addr1)) { - if (i2cio_write8(addr2)) - rv = 0; - else - rv = PICO_ERROR_GENERIC; - } else - rv = PICO_ERROR_GENERIC; - } else { - if (i2cio_write8((addr << 1) & 0xff)) - rv = 0; // acked: ok - else - rv = PICO_ERROR_GENERIC; // nak :/ - } - i2cio_stop(); - - // I2C back to I2C - gpio_set_function(PINOUT_I2C_SCL, GPIO_FUNC_I2C); - gpio_set_function(PINOUT_I2C_SDA, GPIO_FUNC_I2C); - - return rv; -} - -inline static void i2cex_abort_xfer(i2c_inst_t* i2c) { -#if 1 - // may be bugged??? so doesnt do anything for now - (void)i2c; - return; -#else - // now do the abort - i2c->hw->enable = 1 /*| (1<<2)*/ | (1 << 1); - // wait for M_TX_ABRT irq - do { - /*if (timeout_check) { - timeout = timeout_check(ts); - abort |= timeout; - }*/ - tight_loop_contents(); - } while (/*!timeout &&*/ !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_ABRT_BITS)); - // reset irq - // if (!timeout) - (void)i2c->hw->clr_tx_abrt; -#endif -} - -static int i2cex_write_blocking_until(i2c_inst_t* i2c, uint16_t addr, bool a10bit, - const uint8_t* src, size_t len, bool nostop, absolute_time_t until) { - timeout_state_t ts_; - - struct timeout_state* ts = &ts_; - - check_timeout_fn timeout_check = init_single_timeout_until(&ts_, until); - - if ((int)len < 0) return PICO_ERROR_GENERIC; - if (a10bit) { // addr too high - if (addr & ~(uint16_t)((1 << 10) - 1)) return PICO_ERROR_GENERIC; - } else if (addr & 0x80) - return PICO_ERROR_GENERIC; - - if (len == 0) return i2cex_probe_address(addr, a10bit); - - bool abort = false, timeout = false; - uint32_t abort_reason = 0; - int byte_ctr; - - i2c->hw->enable = 0; - // enable 10bit mode if requested - // clang-format off - hw_write_masked(&i2c->hw->con, I2C_IC_CON_IC_10BITADDR_MASTER_BITS, - (a10bit ? I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_10BITS - : I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_7BITS) - << I2C_IC_CON_IC_10BITADDR_MASTER_LSB); - // clang-format on - i2c->hw->tar = addr; - i2c->hw->enable = 1; - - for (byte_ctr = 0; byte_ctr < (int)len; ++byte_ctr) { - bool first = byte_ctr == 0, last = byte_ctr == (int)len - 1; - - i2c->hw->data_cmd = (bool_to_bit(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB) - | (bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB) - | *src++; - - do { - if (timeout_check) { - timeout = timeout_check(ts); - abort |= timeout; - } - tight_loop_contents(); - } while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_TX_EMPTY_BITS)); - - if (!timeout) { - abort_reason = i2c->hw->tx_abrt_source; - if (abort_reason) { - (void)i2c->hw->clr_tx_abrt; - abort = true; - } - - if (abort || (last && !nostop)) { - do { - if (timeout_check) { - timeout = timeout_check(ts); - abort |= timeout; - } - tight_loop_contents(); - // clang-format off - } while (!timeout && !(i2c->hw->raw_intr_stat & I2C_IC_RAW_INTR_STAT_STOP_DET_BITS)); - // clang-format on - - if (!timeout) - (void)i2c->hw->clr_stop_det; - else - // if we had a timeout, send an abort request to the hardware, - // so that the bus gets released - i2cex_abort_xfer(i2c); - } - } else - i2cex_abort_xfer(i2c); - - if (abort) break; - } - - int rval; - - if (abort) { - // clang-format off - const int addr_noack = I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS - | I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR1_NOACK_BITS - | I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR2_NOACK_BITS; - // clang-format on - - if (timeout) - rval = PICO_ERROR_TIMEOUT; - else if (!abort_reason || (abort_reason & addr_noack)) - rval = PICO_ERROR_GENERIC; - else if (abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_TXDATA_NOACK_BITS) - rval = byte_ctr; - else - rval = PICO_ERROR_GENERIC; - } else - rval = byte_ctr; - - i2c->restart_on_next = nostop; - return rval; -} -static int i2cex_read_blocking_until(i2c_inst_t* i2c, uint16_t addr, bool a10bit, uint8_t* dst, - size_t len, bool nostop, absolute_time_t until) { - timeout_state_t ts_; - struct timeout_state* ts = &ts_; - check_timeout_fn timeout_check = init_single_timeout_until(&ts_, until); - - if ((int)len < 0) return PICO_ERROR_GENERIC; - if (a10bit) { // addr too high - if (addr & ~(uint16_t)((1 << 10) - 1)) return PICO_ERROR_GENERIC; - } else if (addr & 0x80) - return PICO_ERROR_GENERIC; - - i2c->hw->enable = 0; - // enable 10bit mode if requested - hw_write_masked(&i2c->hw->con, I2C_IC_CON_IC_10BITADDR_MASTER_BITS, - (a10bit ? I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_10BITS - : I2C_IC_CON_IC_10BITADDR_MASTER_VALUE_ADDR_7BITS) - << I2C_IC_CON_IC_10BITADDR_MASTER_LSB); - i2c->hw->tar = addr; - i2c->hw->enable = 1; - - if (len == 0) return i2cex_probe_address(addr, a10bit); - - bool abort = false, timeout = false; - uint32_t abort_reason = 0; - int byte_ctr; - - for (byte_ctr = 0; byte_ctr < (int)len; ++byte_ctr) { - bool first = byte_ctr == 0; - bool last = byte_ctr == (int)len - 1; - - while (!i2c_get_write_available(i2c) && !abort) { - tight_loop_contents(); - // ? - if (timeout_check) { - timeout = timeout_check(ts); - abort |= timeout; - } - } - - if (timeout) { - // if we had a timeout, send an abort request to the hardware, - // so that the bus gets released - i2cex_abort_xfer(i2c); - } - if (abort) break; - - i2c->hw->data_cmd = bool_to_bit(first && i2c->restart_on_next) - << I2C_IC_DATA_CMD_RESTART_LSB | - bool_to_bit(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB | - I2C_IC_DATA_CMD_CMD_BITS; // -> 1 for read - - do { - abort_reason = i2c->hw->tx_abrt_source; - abort = (bool)i2c->hw->clr_tx_abrt; - - if (timeout_check) { - timeout = timeout_check(ts); - abort |= timeout; - } - tight_loop_contents(); // ? - } while (!abort && !i2c_get_read_available(i2c)); - - if (timeout) { - // if we had a timeout, send an abort request to the hardware, - // so that the bus gets released - i2cex_abort_xfer(i2c); - } - if (abort) break; - - uint8_t v = (uint8_t)i2c->hw->data_cmd; - // printf("\ngot read %02x\n", v); - *dst++ = v; - } - - int rval; - - if (abort) { - // printf("\ngot abrt: "); - const int addr_noack = I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS | - I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR1_NOACK_BITS | - I2C_IC_TX_ABRT_SOURCE_ABRT_10ADDR2_NOACK_BITS; - - if (timeout) { /*printf("timeout\n");*/ - rval = PICO_ERROR_TIMEOUT; - } else if (!abort_reason || (abort_reason & addr_noack)) { // printf("disconn\n"); - rval = PICO_ERROR_GENERIC; - } else { /*printf("unk\n");*/ - rval = PICO_ERROR_GENERIC; - } - } else - rval = byte_ctr; - - i2c->restart_on_next = nostop; - return rval; -} -static inline int i2cex_write_timeout_us(i2c_inst_t* i2c, uint16_t addr, bool a10bit, - const uint8_t* src, size_t len, bool nostop, uint32_t timeout_us) { - absolute_time_t t = make_timeout_time_us(timeout_us); - return i2cex_write_blocking_until(i2c, addr, a10bit, src, len, nostop, t); -} -static inline int i2cex_read_timeout_us(i2c_inst_t* i2c, uint16_t addr, bool a10bit, uint8_t* dst, - size_t len, bool nostop, uint32_t timeout_us) { - absolute_time_t t = make_timeout_time_us(timeout_us); - return i2cex_read_blocking_until(i2c, addr, a10bit, dst, len, nostop, t); -} - -__attribute__((__const__)) enum ki2c_funcs i2ctu_get_func(void) { - // TODO: SMBUS_EMUL_ALL => I2C_M_RECV_LEN - // TODO: maybe also PROTOCOL_MANGLING, NOSTART - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; -} - -void i2ctu_init(void) { - // default to 100 kHz (SDK example default so should be ok) - delay = 10; - delay2 = 5; - i2c_init(PINOUT_I2C_DEV, 100 * 1000); - - gpio_set_function(PINOUT_I2C_SCL, GPIO_FUNC_I2C); - gpio_set_function(PINOUT_I2C_SDA, GPIO_FUNC_I2C); - gpio_pull_up(PINOUT_I2C_SCL); - gpio_pull_up(PINOUT_I2C_SDA); - - bi_decl(bi_2pins_with_func(PINOUT_I2C_SCL, PINOUT_I2C_SDA, GPIO_FUNC_I2C)); -} - -uint32_t i2ctu_set_freq(uint32_t freq, uint32_t us) { - delay = us; - delay2 = us >> 1; - if (!delay2) delay2 = 1; - - return i2c_set_baudrate(PINOUT_I2C_DEV, freq); -} - -enum itu_status i2ctu_write(enum ki2c_flags flags, enum itu_command startstopflags, uint16_t addr, - const uint8_t* buf, size_t len) { - bool nostop = !(startstopflags & ITU_CMD_I2C_IO_END); - bool bit10 = flags & I2C_M_TEN; - - /*if (len == 0) { - // do a read, that's less hazardous - uint8_t stuff = 0; - int rv = i2cex_read_timeout_us(PINOUT_I2C_DEV, addr, bit10, &stuff, 1, - nostop, 1000*1000); - if (rv < 0) return ITU_STATUS_ADDR_NAK; - return ITU_STATUS_ADDR_ACK; - } else*/ - { - int rv = i2cex_write_timeout_us(PINOUT_I2C_DEV, addr, bit10, buf, len, nostop, 1000 * 1000); - if (rv < 0 || (size_t)rv < len) return ITU_STATUS_ADDR_NAK; - return ITU_STATUS_ADDR_ACK; - } -} -enum itu_status i2ctu_read(enum ki2c_flags flags, enum itu_command startstopflags, uint16_t addr, - uint8_t* buf, size_t len) { - bool nostop = !(startstopflags & ITU_CMD_I2C_IO_END); - bool bit10 = flags & I2C_M_TEN; - - /*if (len == 0) { - uint8_t stuff = 0; - int rv = i2cex_read_timeout_us(PINOUT_I2C_DEV, addr, bit10, &stuff, 1, - nostop, 1000*1000); - if (rv < 0) return ITU_STATUS_ADDR_NAK; - return ITU_STATUS_ADDR_ACK; - } else*/ - { - int rv = i2cex_read_timeout_us(PINOUT_I2C_DEV, addr, bit10, buf, len, nostop, 1000 * 1000); - // printf("p le rv=%d buf=%02x ", rv, buf[0]); - if (rv < 0 || (size_t)rv < len) return ITU_STATUS_ADDR_NAK; - return ITU_STATUS_ADDR_ACK; - } -} - diff --git a/bsp/rp2040/pinout.h b/bsp/rp2040/pinout.h deleted file mode 100644 index 639f88a..0000000 --- a/bsp/rp2040/pinout.h +++ /dev/null @@ -1,51 +0,0 @@ -// vim: set et: - -#ifndef PINOUT_H_ -#define PINOUT_H_ - -// UART config -#define PINOUT_UART_TX 4 -#define PINOUT_UART_RX 5 -#define PINOUT_UART_CTS 10 -#define PINOUT_UART_RTS 11 -#define PINOUT_UART_INTERFACE uart1 -#define PINOUT_UART_BAUDRATE 115200 - -// JTAG config -#define PINOUT_JTAG_TCK 2 // == SWCLK -#define PINOUT_JTAG_TMS 3 // == SWDIO -#define PINOUT_JTAG_TDI 6 -#define PINOUT_JTAG_TDO 7 -#define PINOUT_JTAG_nTRST 8 -#define PINOUT_JTAG_nRESET 9 - -// SPI config -#define PINOUT_SPI_DEV spi1 -#define PINOUT_SPI_SCLK 14 -#define PINOUT_SPI_MOSI 15 -#define PINOUT_SPI_MISO 12 -#define PINOUT_SPI_nCS 13 - -// I2C config -#define PINOUT_I2C_DEV i2c0 -#define PINOUT_I2C_SCL 21 -#define PINOUT_I2C_SDA 20 - -// LED config - -// you can change these two as you like -#define PINOUT_LED_CONNECTED 1 -#define PINOUT_LED_RUNNING 0 - -#ifndef PINOUT_LED -#ifndef PICO_DEFAULT_LED_PIN -#error "PICO_DEFAULT_LED_PIN is not defined, run PICOPROBE_LED= cmake" -#elif PICO_DEFAULT_LED_PIN == -1 -#error "PICO_DEFAULT_LED_PIN is defined as -1, run PICOPROBE_LED= cmake" -#else -#define PINOUT_LED PICO_DEFAULT_LED_PIN -#endif -#endif /* PICOPROBE_LED */ - -#endif - diff --git a/bsp/rp2040/protocfg.h b/bsp/rp2040/protocfg.h index 2a709dd..f9f852d 100644 --- a/bsp/rp2040/protocfg.h +++ b/bsp/rp2040/protocfg.h @@ -3,38 +3,6 @@ #ifndef PROTOCFG_H_ #define PROTOCFG_H_ -#define DBOARD_HAS_UART -#define DBOARD_HAS_CMSISDAP -#define DBOARD_HAS_SERPROG -#define DBOARD_HAS_I2C -#define DBOARD_HAS_TEMPSENSOR - -enum { - HID_N_CMSISDAP = 0, - - HID_N__NITF -}; -enum { - CDC_N_UART = 0, - CDC_N_SERPROG, -#ifdef USE_USBCDC_FOR_STDIO - CDC_N_STDIO, -#endif - - CDC_N__NITF -}; -enum { - VND_N__NITF = 0 -}; - -#define CFG_TUD_HID 1 -#ifdef USE_USBCDC_FOR_STDIO -#define CFG_TUD_CDC 3 -#else -#define CFG_TUD_CDC 2 -#endif -#define CFG_TUD_VENDOR 0 - /*#define USB_VID 0x2e8a*/ /* Raspberry Pi */ #define USB_VID 0xcafe /* TinyUSB */ /*#define USB_VID 0x1209*/ /* Generic */ @@ -45,4 +13,3 @@ enum { #define INFO_BOARDNAME "RP2040 Pico" #endif - diff --git a/bsp/rp2040/spi_serprog.c b/bsp/rp2040/spi_serprog.c deleted file mode 100644 index 9f6b7f9..0000000 --- a/bsp/rp2040/spi_serprog.c +++ /dev/null @@ -1,72 +0,0 @@ -// vim: set et: - -#include - -#include -#include -#include - -#include "pinout.h" -#include "protos.h" -#include "serprog.h" - -static bool cs_asserted; - -void sp_spi_init(void) { - cs_asserted = false; - - spi_init(PINOUT_SPI_DEV, 512 * 1000); // default to 512 kHz - - gpio_set_function(PINOUT_SPI_MISO, GPIO_FUNC_SPI); - gpio_set_function(PINOUT_SPI_MOSI, GPIO_FUNC_SPI); - gpio_set_function(PINOUT_SPI_SCLK, GPIO_FUNC_SPI); - - // gpio_set_function(PINOUT_SPI_nCS, GPIO_FUNC_SIO); - gpio_init(PINOUT_SPI_nCS); - gpio_put(PINOUT_SPI_nCS, 1); - gpio_set_dir(PINOUT_SPI_nCS, GPIO_OUT); - - bi_decl(bi_3pins_with_func(PINOUT_SPI_MISO, PINOUT_SPI_MOSI, PINOUT_SPI_SCLK, GPIO_FUNC_SPI)); - bi_decl(bi_1pin_with_name(PINOUT_SPI_nCS, "SPI #CS")); -} -uint32_t __not_in_flash_func(sp_spi_set_freq)(uint32_t freq_wanted) { - return spi_set_baudrate(PINOUT_SPI_DEV, freq_wanted); -} -void __not_in_flash_func(sp_spi_cs_deselect)(void) { - asm volatile("nop\nnop\nnop"); // idk if this is needed - gpio_put(PINOUT_SPI_nCS, 1); - asm volatile("nop\nnop\nnop"); // idk if this is needed - cs_asserted = false; -} -void __not_in_flash_func(sp_spi_cs_select)(void) { - asm volatile("nop\nnop\nnop"); // idk if this is needed - gpio_put(PINOUT_SPI_nCS, 0); - asm volatile("nop\nnop\nnop"); // idk if this is needed - cs_asserted = true; -} - -void __not_in_flash_func(sp_spi_op_begin)(void) { - // sp_spi_cs_select(); - if (!cs_asserted) { - asm volatile("nop\nnop\nnop"); // idk if this is needed - gpio_put(PINOUT_SPI_nCS, 0); - asm volatile("nop\nnop\nnop"); // idk if this is needed - } -} -void __not_in_flash_func(sp_spi_op_end)(void) { - // sp_spi_cs_deselect(); - if (!cs_asserted) { // YES, this condition is the intended one! - asm volatile("nop\nnop\nnop"); // idk if this is needed - gpio_put(PINOUT_SPI_nCS, 1); - asm volatile("nop\nnop\nnop"); // idk if this is needed - } -} - -// TODO: use dma? -void __not_in_flash_func(sp_spi_op_write)(uint32_t write_len, const uint8_t* write_data) { - spi_write_blocking(PINOUT_SPI_DEV, write_data, write_len); -} -void __not_in_flash_func(sp_spi_op_read)(uint32_t read_len, uint8_t* read_data) { - spi_read_blocking(PINOUT_SPI_DEV, 0, read_data, read_len); -} - diff --git a/bsp/rp2040/tempsensor.c b/bsp/rp2040/tempsensor.c deleted file mode 100644 index d9fbce2..0000000 --- a/bsp/rp2040/tempsensor.c +++ /dev/null @@ -1,51 +0,0 @@ -// vim: set et: - -#include "tempsensor.h" - -#include - -#define T_SLOPE (-0.001721f) -#define T_BIAS (0.706f) -#define V_MAX (3.3f) -#define D_RANGE (4096) -#define T_OFF (27) - -// convert float to x.4 fixed format -#define float2fix(x) (int)((x) * (1 << 4)) - -// convert x.4 fixed to 8.4 fixed -__attribute__((__const__)) inline static int16_t trunc_8fix4(int fix) { - // clang-format off - if (fix > 4095) fix = 4095; - if (fix < -4096) fix = -4096; - // clang-format on - return fix; -} - -void tempsense_dev_init(void) { - adc_init(); - adc_set_temp_sensor_enabled(true); -} -// 8.4 -int16_t tempsense_dev_get_temp(void) { - adc_select_input(4); // select temp sensor - uint16_t result = adc_read(); - - float voltage = result * (V_MAX / D_RANGE); - - float tempf = T_OFF + (voltage - T_BIAS) / T_SLOPE; - - // FIXME: use fixed point instead! but something's wrong with the formula below - /*int temperature = float2fix(T_OFF - T_BIAS / T_SLOPE) - + (int)result * float2fix(V_MAX / (D_RANGE * T_SLOPE));*/ - - return trunc_8fix4(/*temperature*/ float2fix(tempf)); -} - -// RP2040 absolute min/max are -20/85 -// clang-format off -int16_t tempsense_dev_get_lower(void) { return trunc_8fix4(float2fix(-15)); } -int16_t tempsense_dev_get_upper(void) { return trunc_8fix4(float2fix( 75)); } -int16_t tempsense_dev_get_crit (void) { return trunc_8fix4(float2fix( 80)); } -// clang-format on - diff --git a/libco/libco.S b/libco/libco.S index 9a349fe..85ad0d9 100644 --- a/libco/libco.S +++ b/libco/libco.S @@ -84,6 +84,7 @@ co_switch:@(cothread_t handle r0) ldmia r0!, {r4-r7} ldr r2, [r0, #(0x28-0x10)] @ pc + @ldr r0, [r0, #(0x2c-0x10)] @ ud/r0 / retval mov pc, r2 bx lr @@ -94,9 +95,11 @@ co_switch:@(cothread_t handle r0) .type co_derive, %function .thumb_func .global co_derive -co_derive:@(void* memory r0, unsigned int size r1, void(*entrypoint)(void) r2) +co_derive:@(void* memory r0, unsigned int size r1, void(*entrypoint)(void*) r2, void* ud r3) push {r4} + @mov r12, r3 @ save ud for later + @ if (!co_active_handle) co_active_handle = &co_active_buffer ldr r3, =co_active_handle ldr r4, [r3] @@ -117,8 +120,9 @@ co_derive:@(void* memory r0, unsigned int size r1, void(*entrypoint)(void) r2) @ p(r3) = handle(r0) + offset(r3) add r3, r0 @ initialize stack, entrypoint - str r3, [r0, #( 9*4)] - str r2, [r0, #(10*4)] + @str r12, [r0, #(11*4)] @ init r0: user argument + str r3 , [r0, #( 9*4)] @ init sp/r13 + str r2 , [r0, #(10*4)] @ init pc/r15 .Lret: pop {r4} diff --git a/libco/libco.h b/libco/libco.h index d9cddca..a787b9c 100644 --- a/libco/libco.h +++ b/libco/libco.h @@ -8,8 +8,8 @@ typedef void* cothread_t; cothread_t co_active(void); -cothread_t co_derive(void* memory, unsigned int heapsize, void (*coentry)(void)); -void co_switch(cothread_t); +cothread_t co_derive(void* memory, unsigned int heapsize, void (*coentry)(void/***/)/*, void* ud*/); +void co_switch(cothread_t); // should we make this return void* (and thus `ud`)? int co_serializable(void); #endif diff --git a/src/cdc_serprog.c b/src/cdc_serprog.c deleted file mode 100644 index 4da9993..0000000 --- a/src/cdc_serprog.c +++ /dev/null @@ -1,242 +0,0 @@ -// vim: set et: - -#include - -#include "protocfg.h" -#include "tusb.h" - -#ifdef DBOARD_HAS_SERPROG - -#include "protos.h" -#include "rtconf.h" -#include "serprog.h" -#include "util.h" - -// TODO: refactor some of this stuff into another header & split off serprog -// protocol handling from the SPI stuff. one thing we should think about -// when performing this refactor is, would other boards support -// parallell, LPC, or FWH, or only SPI? if only SPI, the entire proto -// handler can just be made reusable verbatim. - -// kinda refactored this already but it still has a good note for non-SPI stuff, -// so leaving it here for now - -// clang-format off -static const uint8_t serprog_cmdmap[32] = { - 0x3f, // cmd 00..05 not 0x06 (Q_CHIPSIZE) and 0x07 (Q_OPBUF), as this is a SPI-only device - 0x01, // only cmd 08 - 0x1f, // cmd 10..15 supported - 0, // 18..1f - 0, // 20..27 - 0, // 28..2f - 0, // 30..37 - 0, // 38..3f - 0, // 4<0..47 - 0, // 48..4f - (1 << 3), // 50..57: enable 0x53 - 0, // 58..5f - 0, // rest is 0 -}; -// clang-format on -static const char serprog_pgmname[16] = INFO_PRODUCT_BARE; - -static uint8_t rx_buf[CFG_TUD_CDC_RX_BUFSIZE]; -static uint8_t tx_buf[CFG_TUD_CDC_TX_BUFSIZE]; - -static uint32_t rxavail, rxpos; - -void cdc_serprog_init(void) { - rxavail = 0; - rxpos = 0; - - sp_spi_init(); -} - -static uint8_t read_byte(void) { - while (rxavail <= 0) { - if (!tud_cdc_n_connected(CDC_N_SERPROG) || !tud_cdc_n_available(CDC_N_SERPROG)) { - thread_yield(); - continue; - } - - rxpos = 0; - rxavail = tud_cdc_n_read(CDC_N_SERPROG, rx_buf, sizeof rx_buf); - - if (rxavail == 0) thread_yield(); - } - - uint8_t rv = rx_buf[rxpos]; - ++rxpos; - --rxavail; - return rv; -} - -static void handle_cmd(void) { - uint32_t nresp = 0; - - uint8_t cmd = read_byte(); - switch (cmd) { - case S_CMD_NOP: - tx_buf[0] = S_ACK; - nresp = 1; - break; - case S_CMD_SYNCNOP: - tx_buf[0] = S_NAK; - tx_buf[1] = S_ACK; - nresp = 2; - break; - case S_CMD_Q_IFACE: - tx_buf[0] = S_ACK; - tx_buf[1] = SERPROG_IFACE_VERSION & 0xff; - tx_buf[2] = (SERPROG_IFACE_VERSION >> 8) & 0xff; - nresp = 3; - break; - case S_CMD_Q_CMDMAP: - tx_buf[0] = S_ACK; - memcpy(&tx_buf[1], serprog_cmdmap, sizeof serprog_cmdmap); - nresp = sizeof(serprog_cmdmap) + 1; - break; - case S_CMD_Q_PGMNAME: - tx_buf[0] = S_ACK; - memcpy(&tx_buf[1], serprog_pgmname, sizeof serprog_pgmname); - nresp = sizeof(serprog_pgmname) + 1; - break; - case S_CMD_Q_SERBUF: - tx_buf[0] = S_ACK; - tx_buf[1] = sizeof(rx_buf) & 0xff; - tx_buf[2] = (sizeof(rx_buf) >> 8) & 0xff; - nresp = 3; - break; - case S_CMD_Q_BUSTYPE: - tx_buf[0] = S_ACK; - tx_buf[1] = 1 << 3; // SPI only - nresp = 2; - break; - case S_CMD_Q_WRNMAXLEN: - tx_buf[0] = S_ACK; - tx_buf[1] = (sizeof(tx_buf) - 1) & 0xff; - tx_buf[2] = ((sizeof(tx_buf) - 1) >> 8) & 0xff; - tx_buf[3] = ((sizeof(tx_buf) - 1) >> 16) & 0xff; - nresp = 4; - break; - case S_CMD_Q_RDNMAXLEN: - tx_buf[0] = S_ACK; - tx_buf[1] = (sizeof(rx_buf) - 1) & 0xff; - tx_buf[2] = ((sizeof(rx_buf) - 1) >> 8) & 0xff; - tx_buf[3] = ((sizeof(rx_buf) - 1) >> 16) & 0xff; - nresp = 4; - break; - case S_CMD_S_BUSTYPE: - if (read_byte() /* bus type to set */ == (1 << 3)) { - tx_buf[0] = S_ACK; - } else { - tx_buf[0] = S_NAK; - } - nresp = 1; - break; - - case S_CMD_SPIOP: { - uint32_t slen, rlen; - - // clang-format off - slen = (uint32_t)read_byte(); - slen |= (uint32_t)read_byte() << 8; - slen |= (uint32_t)read_byte() << 16; - rlen = (uint32_t)read_byte(); - rlen |= (uint32_t)read_byte() << 8; - rlen |= (uint32_t)read_byte() << 16; - // clang-format on - - sp_spi_op_begin(); - size_t this_batch; - - // 1. write slen data bytes - // we're going to use the tx buf for all operations here - while (slen > 0) { - this_batch = sizeof(tx_buf); - if (this_batch > slen) this_batch = slen; - - for (size_t i = 0; i < this_batch; ++i) tx_buf[i] = read_byte(); - sp_spi_op_write(this_batch, tx_buf); - - slen -= this_batch; - } - - // 2. write data - // first, do a batch of 63, because we also need to send an ACK byte - this_batch = sizeof(tx_buf) - 1; - if (this_batch > rlen) this_batch = rlen; - sp_spi_op_read(this_batch, &tx_buf[1]); - tx_buf[0] = S_ACK; - tud_cdc_n_write(CDC_N_SERPROG, tx_buf, this_batch + 1); - rlen -= this_batch; - - // now do in batches of 64 - while (rlen > 0) { - this_batch = sizeof(tx_buf); - if (this_batch > rlen) this_batch = rlen; - - sp_spi_op_read(this_batch, tx_buf); - tud_cdc_n_write(CDC_N_SERPROG, tx_buf, this_batch); - - rlen -= this_batch; - } - tud_cdc_n_write_flush(CDC_N_SERPROG); - - // that's it! - sp_spi_op_end(); - nresp = 0; // we sent our own response manually - } break; - case S_CMD_S_SPI_FREQ: { - uint32_t freq; - // clang-format off - freq = (uint32_t)read_byte(); - freq |= (uint32_t)read_byte() << 8; - freq |= (uint32_t)read_byte() << 16; - freq |= (uint32_t)read_byte() << 24; - // clang-format on - - uint32_t nfreq = sp_spi_set_freq(freq); - - tx_buf[0] = S_ACK; - tx_buf[1] = nfreq & 0xff; - tx_buf[2] = (nfreq >> 8) & 0xff; - tx_buf[3] = (nfreq >> 16) & 0xff; - tx_buf[4] = (nfreq >> 24) & 0xff; - nresp = 5; - } break; - case S_CMD_S_PINSTATE: { - if (read_byte() == 0) - sp_spi_cs_deselect(); - else - sp_spi_cs_select(); - - tx_buf[0] = S_ACK; - nresp = 1; - } break; - - case S_CMD_MAGIC_SETTINGS: { - uint8_t a = read_byte(); - uint8_t b = read_byte(); - - tx_buf[0] = S_ACK; - tx_buf[1] = rtconf_do(a, b); - nresp = 2; - } break; - - default: - tx_buf[0] = S_NAK; - nresp = 1; - break; - } - - if (nresp > 0) { - tud_cdc_n_write(CDC_N_SERPROG, tx_buf, nresp); - tud_cdc_n_write_flush(CDC_N_SERPROG); - } -} - -void cdc_serprog_task(void) { handle_cmd(); } - -#endif /* DBOARD_HAS_SERPROG */ - diff --git a/src/i2ctinyusb.h b/src/i2ctinyusb.h deleted file mode 100644 index 7171625..0000000 --- a/src/i2ctinyusb.h +++ /dev/null @@ -1,102 +0,0 @@ -// vim: set et: - -#ifndef I2CTINYUSB_H_ -#define I2CTINYUSB_H_ - -#include -#include -#include - -#include "protocfg.h" - -enum itu_command { - ITU_CMD_ECHO = 0, - ITU_CMD_GET_FUNC = 1, - ITU_CMD_SET_DELAY = 2, - ITU_CMD_GET_STATUS = 3, - - ITU_CMD_I2C_IO_BEGIN_F = (1 << 0), - ITU_CMD_I2C_IO_END_F = (1 << 1), - ITU_CMD_I2C_IO_DIR_MASK = ITU_CMD_I2C_IO_BEGIN_F | ITU_CMD_I2C_IO_END_F, - - ITU_CMD_I2C_IO = 4, - ITU_CMD_I2C_IO_BEGIN = 4 | ITU_CMD_I2C_IO_BEGIN_F, - ITU_CMD_I2C_IO_END = 4 | ITU_CMD_I2C_IO_END_F, - ITU_CMD_I2C_IO_BEGINEND = 4 | ITU_CMD_I2C_IO_BEGIN_F | ITU_CMD_I2C_IO_END_F, -}; - -enum itu_status { ITU_STATUS_IDLE = 0, ITU_STATUS_ADDR_ACK = 1, ITU_STATUS_ADDR_NAK = 2 }; - -// these two are lifted straight from the linux kernel, lmao -enum ki2c_flags { - I2C_M_RD = 0x0001, /* guaranteed to be 0x0001! */ - I2C_M_TEN = 0x0010, /* use only if I2C_FUNC_10BIT_ADDR */ - I2C_M_DMA_SAFE = 0x0200, /* use only in kernel space */ - I2C_M_RECV_LEN = 0x0400, /* use only if I2C_FUNC_SMBUS_READ_BLOCK_DATA */ - I2C_M_NO_RD_ACK = 0x0800, /* use only if I2C_FUNC_PROTOCOL_MANGLING */ - I2C_M_IGNORE_NAK = 0x1000, /* use only if I2C_FUNC_PROTOCOL_MANGLING */ - I2C_M_REV_DIR_ADDR = 0x2000, /* use only if I2C_FUNC_PROTOCOL_MANGLING */ - I2C_M_NOSTART = 0x4000, /* use only if I2C_FUNC_NOSTART */ - I2C_M_STOP = 0x8000, /* use only if I2C_FUNC_PROTOCOL_MANGLING */ -}; - -enum ki2c_funcs { - I2C_FUNC_I2C = 0x00000001, - I2C_FUNC_10BIT_ADDR = 0x00000002, /* required for I2C_M_TEN */ - I2C_FUNC_PROTOCOL_MANGLING = 0x00000004, /* required for I2C_M_IGNORE_NAK etc. */ - I2C_FUNC_SMBUS_PEC = 0x00000008, - I2C_FUNC_NOSTART = 0x00000010, /* required for I2C_M_NOSTART */ - I2C_FUNC_SLAVE = 0x00000020, - I2C_FUNC_SMBUS_BLOCK_PROC_CALL = 0x00008000, /* SMBus 2.0 or later */ - I2C_FUNC_SMBUS_QUICK = 0x00010000, - I2C_FUNC_SMBUS_READ_BYTE = 0x00020000, - I2C_FUNC_SMBUS_WRITE_BYTE = 0x00040000, - I2C_FUNC_SMBUS_READ_BYTE_DATA = 0x00080000, - I2C_FUNC_SMBUS_WRITE_BYTE_DATA = 0x00100000, - I2C_FUNC_SMBUS_READ_WORD_DATA = 0x00200000, - I2C_FUNC_SMBUS_WRITE_WORD_DATA = 0x00400000, - I2C_FUNC_SMBUS_PROC_CALL = 0x00800000, - I2C_FUNC_SMBUS_READ_BLOCK_DATA = 0x01000000, /* required for I2C_M_RECV_LEN */ - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA = 0x02000000, - I2C_FUNC_SMBUS_READ_I2C_BLOCK = 0x04000000, /* I2C-like block xfer */ - I2C_FUNC_SMBUS_WRITE_I2C_BLOCK = 0x08000000, /* w/ 1-byte reg. addr. */ - I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 = 0x10000000, /* I2C-like block xfer */ - I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 = 0x20000000, /* w/ 2-byte reg. addr. */ - I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC = 0x40000000, /* SMBus 2.0 or later */ - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC = 0x80000000, /* SMBus 2.0 or later */ - - I2C_FUNC_SMBUS_BYTE = (I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE), - I2C_FUNC_SMBUS_BYTE_DATA = (I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA), - I2C_FUNC_SMBUS_WORD_DATA = (I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA), - I2C_FUNC_SMBUS_BLOCK_DATA = (I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_BLOCK_DATA), - I2C_FUNC_SMBUS_I2C_BLOCK = (I2C_FUNC_SMBUS_READ_I2C_BLOCK | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK), - - I2C_FUNC_SMBUS_EMUL = (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL | - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | I2C_FUNC_SMBUS_I2C_BLOCK | - I2C_FUNC_SMBUS_PEC), - - /* if I2C_M_RECV_LEN is also supported */ - I2C_FUNC_SMBUS_EMUL_ALL = - (I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL), -}; - -__attribute__((__packed__)) struct itu_cmd { - uint16_t flags; - uint16_t addr; - uint16_t len; - uint8_t cmd; -}; - -#ifdef DBOARD_HAS_I2C -__attribute__((__const__)) enum ki2c_funcs i2ctu_get_func(void); -void i2ctu_init(void); -uint32_t i2ctu_set_freq(uint32_t freq, uint32_t us); // returns selected frequency, or 0 on error -enum itu_status i2ctu_write(enum ki2c_flags flags, enum itu_command startstopflags, uint16_t addr, - const uint8_t* buf, size_t len); -enum itu_status i2ctu_read(enum ki2c_flags flags, enum itu_command startstopflags, uint16_t addr, - uint8_t* buf, size_t len); -#endif - -#endif - diff --git a/src/m_default/0def.c b/src/m_default/0def.c new file mode 100644 index 0000000..1cff5f3 --- /dev/null +++ b/src/m_default/0def.c @@ -0,0 +1,257 @@ +// vim: set et: + +#include + +#include "mode.h" +#include "vnd_cfg.h" + +#include "protocfg.h" +#include "util.h" + +void enter_cb(void) { + // TODO: init hw +} +void leave_cb(void) { + // TODO: deinit hw +} + +void task_cb(void) { + // TODO: do stuff +} + +void handle_cmd_cb(uint8_t cmd) { + uint8_t resp = 0; + + switch (cmd) { + case mode_cmd_get_features: + vnd_cfg_write_resp(cfg_resp_ok, 1, &resp); + break; + default: + vnd_cfg_write_resp(cfg_resp_illcmd, 0, NULL); + break; + } +} + +#define USB_BCD_BASE 0x8000 +#define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n)) +#define USB_BCD \ + (USB_BCD_BASE | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 3) | _PID_MAP(HID, 6) | _PID_MAP(MIDI, 9) | \ + _PID_MAP(VENDOR, 12)) \ + + +enum { + STRID_LANGID = 0, + STRID_MANUFACTURER, + STRID_PRODUCT, + STRID_SERIAL, + + STRID_CONFIG, + + STRID_IF_VND_CFG, + STRID_IF_CDC_STDIO, +}; +enum { + ITF_NUM_VND_CFG, +//#ifdef USE_USBCDC_FOR_STDIO + ITF_NUM_CDC_STDIO_COM, + ITF_NUM_CDC_STDIO_DATA, +//#endif + + ITF_NUM__TOTAL +}; +enum { + CONFIG_TOTAL_LEN + = TUD_CONFIG_DESC_LEN + + TUD_VENDOR_DESC_LEN +//#ifdef USE_USBCDC_FOR_STDIO + + TUD_CDC_DESC_LEN +//#endif +}; + +#define EPNUM_CDC_STDIO_OUT 0x03 +#define EPNUM_CDC_STDIO_IN 0x83 +#define EPNUM_CDC_STDIO_NOTIF 0x84 + +// TODO: are these ok numbers? +#define EPNUM_VND_CFG_OUT 0x02 +#define EPNUM_VND_CFG_IN 0x82 + +// clang-format off +static const tusb_desc_device_t desc_device = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0110, // TODO: 0x0200 ? + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + + .idVendor = USB_VID, + .idProduct = USB_PID, + .bcdDevice = USB_BCD, + + .iManufacturer = STRID_MANUFACTURER, + .iProduct = STRID_PRODUCT, + .iSerialNumber = STRID_SERIAL, + + .bNumConfigurations = 0x01 +}; + +static const uint8_t desc_hid_report[] = { +#if CFG_TUD_HID > 0 + TUD_HID_REPORT_DESC_GENERIC_INOUT(CFG_TUD_HID_EP_BUFSIZE) +#else + 0 +#endif +}; + +static const uint8_t desc_configuration[] = { + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM__TOTAL, STRID_CONFIG, CONFIG_TOTAL_LEN, + TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + + TUD_VENDOR_DESCRIPTOR(ITF_NUM_VND_CFG, STRID_IF_VND_CFG, EPNUM_VND_CFG_OUT, + EPNUM_VND_CFG_IN, 64), + +//#ifdef USE_USBCDC_FOR_STDIO + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_STDIO_COM, STRID_IF_CDC_STDIO, EPNUM_CDC_STDIO_NOTIF, 64, + EPNUM_CDC_STDIO_OUT, EPNUM_CDC_STDIO_IN, 64), +//#endif +}; +static const char* string_desc_arr[] = { + [STRID_LANGID] = (const char[]){0x09, 0x04}, // supported language is English (0x0409) + [STRID_MANUFACTURER] = "BLAHAJ CTF", // Manufacturer + [STRID_PRODUCT] = "Dragnbus (RP2040 Pico)", // Product + + [STRID_CONFIG] = "Configuration descriptor", + // max string length check: ||||||||||||||||||||||||||||||| + [STRID_IF_VND_CFG ] = "Device cfg/ctl interface", + [STRID_IF_CDC_STDIO] = "stdio CDC interface (debug)", +}; +// clang-format on + +// tinyusb callbacks + +#if CFG_TUD_HID > 0 +// Invoked when received GET_REPORT control request +// Application must fill buffer report's content and return its length. +// Return zero will cause the stack to STALL request +static uint16_t hid_get_report_cb(uint8_t instance, uint8_t report_id, + hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) { + (void)instance; + (void)report_id; + (void)report_type; + (void)buffer; + (void)reqlen; + + return 0; +} +static void hid_set_report_cb(uint8_t instance, uint8_t report_id, + hid_report_type_t report_type, uint8_t const* RxDataBuffer, uint16_t bufsize) { + static uint8_t TxDataBuffer[CFG_TUD_HID_EP_BUFSIZE]; + uint32_t response_size = TU_MIN(CFG_TUD_HID_EP_BUFSIZE, bufsize); + + // This doesn't use multiple report and report ID + (void)instance; + (void)report_id; + (void)report_type; + + tud_hid_report(0, TxDataBuffer, response_size); +} +#endif +static void cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* line_coding) { + (void)itf; + (void)line_coding; +} +static bool vendor_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, + tusb_control_request_t const* req) { + (void)rhport; + (void)ep_addr; + (void)req; + + return true; +} + +// Invoked when received GET HID REPORT DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +static const uint8_t* hid_descriptor_report_cb(uint8_t instance) { + (void)instance; + + return desc_hid_report; +} +// Invoked when received GET DEVICE DESCRIPTOR +// Application return pointer to descriptor +static const uint8_t* descriptor_device_cb(void) { + return (const uint8_t*)&desc_device; +} +// Invoked when received GET CONFIGURATION DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +static const uint8_t* descriptor_configuration_cb(uint8_t index) { + (void)index; // for multiple configurations + + return desc_configuration; +} +// Invoked when received GET STRING DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to +// complete +static const uint16_t* descriptor_string_cb(uint8_t index, uint16_t langid) { + static uint16_t _desc_str[32]; + + (void)langid; + + uint8_t chr_count = 0; + + if (STRID_LANGID == index) { + memcpy(&_desc_str[1], string_desc_arr[STRID_LANGID], 2); + chr_count = 1; + } else if (STRID_SERIAL == index) { + chr_count = get_unique_id_u16(_desc_str + 1); + } else { + // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. + // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors + + if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0]))) return NULL; + + const char* str = string_desc_arr[index]; + + // Cap at max char + chr_count = TU_MIN(strlen(str), 31); + + // Convert ASCII string into UTF-16 + for (int i = 0; i < chr_count; i++) { _desc_str[1 + i] = str[i]; } + } + + // first byte is length (including header), second byte is string type + _desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2); + + return _desc_str; +} + + +extern struct mode m_01_default; +// clang-format off +struct mode m_01_default = { + .name = "Default mode with misc features", + .usb_desc = desc_configuration, + .version = 0x0010, + + .enter = enter_cb, + .leave = leave_cb, + .task = task_cb, + .handle_cmd = handle_cmd_cb, + +#if CFG_TUD_HID > 0 + .tud_hid_get_report_cb = hid_get_report_cb, + .tud_hid_set_report_cb = hid_set_report_cb, +#endif + .tud_cdc_line_coding_cb = cdc_line_coding_cb, + .tud_vendor_control_xfer_cb = vendor_control_xfer_cb, + + .tud_hid_descriptor_report_cb = hid_descriptor_report_cb, + .tud_descriptor_device_cb = descriptor_device_cb, + .tud_descriptor_configuration_cb = descriptor_configuration_cb, + .tud_descriptor_string_cb = descriptor_string_cb, +}; +// clang-format on + diff --git a/src/main.c b/src/main.c index 8278f15..dc9e0d9 100644 --- a/src/main.c +++ b/src/main.c @@ -1,169 +1,61 @@ // vim: set et: -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ -#include -#include -#include +#include -// include order is sensitive here -// clang-format off #include "tusb_config.h" - #include "bsp/board.h" /* a tinyusb header */ #include "tusb.h" -#include "DAP_config.h" /* ARM code *assumes* this is included prior to DAP.h */ -#include "DAP.h" +#include "mode.h" +#include "thread.h" +#include "vnd_cfg.h" -#include "util.h" -#include "protocfg.h" -#include "protos.h" -#include "libco.h" -// clang-format on +static cothread_t vndcfg_thread; +static uint8_t vndcfg_stack[THREAD_STACK_SIZE]; -#ifdef PICO_BOARD -#include +#ifdef USE_USBCDC_FOR_STDIO +void stdio_usb_init(void); #endif -static cothread_t mainthread; - -void thread_yield(void) { co_switch(mainthread); } - -#define DEFAULT_STACK_SIZE 1024 - -#ifdef DBOARD_HAS_UART -static cothread_t uartthread; -static uint8_t uartstack[DEFAULT_STACK_SIZE]; - -static void uart_thread_fn(void) { - cdc_uart_init(); +static void vndcfg_thread_fn(void) { + vnd_cfg_init(); thread_yield(); while (1) { - cdc_uart_task(); + vnd_cfg_task(); thread_yield(); } } -#endif -#ifdef DBOARD_HAS_SERPROG -static cothread_t serprogthread; -static uint8_t serprogstack[DEFAULT_STACK_SIZE]; +int main() { + thread_init(); -static void serprog_thread_fn(void) { - cdc_serprog_init(); - thread_yield(); - while (1) { - cdc_serprog_task(); - thread_yield(); - } -} -#endif + board_init(); // tinyusb hardware support function -// FIXME -extern uint32_t co_active_buffer[64]; -uint32_t co_active_buffer[64]; -extern cothread_t co_active_handle; -cothread_t co_active_handle; + vndcfg_thread = co_derive(vndcfg_stack, sizeof vndcfg_stack, vndcfg_thread_fn); + co_switch(vndcfg_thread); -int main(void) { - mainthread = co_active(); - - // TODO: split this out in a bsp-specific file -#if defined(PICO_BOARD) && !defined(USE_USBCDC_FOR_STDIO) - // use hardcoded values from TinyUSB board.h - bi_decl(bi_2pins_with_func(0, 1, GPIO_FUNC_UART)); -#endif - board_init(); - -#ifdef DBOARD_HAS_UART - uartthread = co_derive(uartstack, sizeof uartstack, uart_thread_fn); - co_switch(uartthread); // will call cdc_uart_init() on correct thread -#endif -#ifdef DBOARD_HAS_SERPROG - serprogthread = co_derive(serprogstack, sizeof serprogstack, serprog_thread_fn); - co_switch(serprogthread); // will call cdc_serprog_init() on correct thread -#endif -#ifdef DBOARD_HAS_CMSISDAP - DAP_Setup(); -#endif + modes_init(); + if (mode_current) mode_current->enter(); tusb_init(); + // FIXME: put elsewhere? #ifdef USE_USBCDC_FOR_STDIO stdio_usb_init(); #endif while (1) { - tud_task(); // tinyusb device task -#ifdef DBOARD_HAS_UART - co_switch(uartthread); -#endif + tud_task(); + if (mode_current) mode_current->task(); - tud_task(); // tinyusb device task -#ifdef DBOARD_HAS_SERPROG - co_switch(serprogthread); -#endif + tud_task(); + co_switch(vndcfg_thread); + + // do this here instead of in a callback or in the vnd_cfg_task fn + if (mode_next_id != -1) { + modes_switch(mode_next_id); + mode_next_id = -1; + } } - - return 0; -} - -//--------------------------------------------------------------------+ -// USB HID -//--------------------------------------------------------------------+ - -// Invoked when received GET_REPORT control request -// Application must fill buffer report's content and return its length. -// Return zero will cause the stack to STALL request -uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, - uint8_t* buffer, uint16_t reqlen) { - // TODO not Implemented - (void)instance; - (void)report_id; - (void)report_type; - (void)buffer; - (void)reqlen; - - return 0; -} - -void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, - uint8_t const* RxDataBuffer, uint16_t bufsize) { - static uint8_t TxDataBuffer[CFG_TUD_HID_EP_BUFSIZE]; - uint32_t response_size = TU_MIN(CFG_TUD_HID_EP_BUFSIZE, bufsize); - - // This doesn't use multiple report and report ID - (void)instance; - (void)report_id; - (void)report_type; - -#ifdef DBOARD_HAS_CMSISDAP - DAP_ProcessCommand(RxDataBuffer, TxDataBuffer); -#endif - - tud_hid_report(0, TxDataBuffer, response_size); } diff --git a/src/mode.h b/src/mode.h new file mode 100644 index 0000000..dd9195d --- /dev/null +++ b/src/mode.h @@ -0,0 +1,59 @@ +// vim: set et: + +#ifndef MODE_H_ +#define MODE_H_ + +#include +#include + +#include "tusb_config.h" +#include + +// clang-format off + +struct mode { + const char* name; + const uint8_t* usb_desc; + uint16_t version; + + void (*enter)(void); // claim required hardware. no tusb calls here please + void (*leave)(void); // release current in-use hardware. no tusb calls here please + void (*task )(void); + void (*handle_cmd)(uint8_t cmd); // handle a command coming from the vnd_cfg itf + + // tinyusb callbacks +#if CFG_TUD_HID > 0 + uint16_t (*tud_hid_get_report_cb)(uint8_t instance, uint8_t report_id, + hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen); + void (*tud_hid_set_report_cb)(uint8_t instance, uint8_t report_id, + hid_report_type_t report_type, uint8_t const* rxbuf, uint16_t bufsize); +#endif +#if CFG_TUD_CDC > 0 + void (*tud_cdc_line_coding_cb)(uint8_t itf, cdc_line_coding_t const* line_coding); +#endif +#if CFG_TUD_VENDOR > 0 + bool (*tud_vendor_control_xfer_cb)(uint8_t rhport, uint8_t ep_addr, + tusb_control_request_t const* req); +#endif + + uint8_t const* (*tud_hid_descriptor_report_cb)(uint8_t instance); + uint8_t const* (*tud_descriptor_device_cb)(void); + uint8_t const* (*tud_descriptor_configuration_cb)(uint8_t index); + uint16_t const* (*tud_descriptor_string_cb)(uint8_t index, uint16_t langid); +}; + +// call this BEFORE tusb_init! +void modes_init(void); + +void modes_switch(uint8_t newmode); + +extern int mode_current_id; +extern int mode_next_id; +extern const struct mode* mode_list[16]; +#define mode_default (mode_list[1]) +#define mode_current (((mode_current_id)==-1)?NULL:(mode_list[mode_current_id])) + +// clang-format on + +#endif + diff --git a/src/modeset.c b/src/modeset.c new file mode 100644 index 0000000..845614e --- /dev/null +++ b/src/modeset.c @@ -0,0 +1,112 @@ +// vim: set et: + +#include "mode.h" + +extern struct mode m_01_default; + +// clang-format off +const struct mode* mode_list[16] = { + NULL, // dummy 0 entry + &m_01_default, + NULL, // terminating entry + +}; +// clang-format on + +int mode_current_id = 1; +int mode_next_id = -1; + +extern void* tusb_got[]; + +enum tusbgot_index { + tusbgot_hid_get_report = 0, + tusbgot_hid_set_report, + tusbgot_cdc_line_coding, + tusbgot_vendor_control_xfer, + tusbgot_hid_descriptor_report, + tusbgot_descriptor_device, + tusbgot_descriptor_configuration, + tusbgot_descriptor_string +}; + +void modes_init(void) { + // switch to the default mode, but without doing a USB reboot thing + mode_current_id = &mode_default - mode_list; + mode_next_id = -1; + + if (!mode_default) return; + + // clang-format off +#if CFG_TUD_HID > 0 + tusb_got[tusbgot_hid_get_report ] = mode_default->tud_hid_get_report_cb; + tusb_got[tusbgot_hid_set_report ] = mode_default->tud_hid_set_report_cb; +#else + tusb_got[tusbgot_hid_get_report ] = NULL; + tusb_got[tusbgot_hid_set_report ] = NULL; +#endif +#if CFG_TUD_CDC > 0 + tusb_got[tusbgot_cdc_line_coding ] = mode_default->tud_cdc_line_coding_cb; +#else + tusb_got[tusbgot_cdc_line_coding ] = NULL; +#endif +#if CFG_TUD_VENDOR > 0 + tusb_got[tusbgot_vendor_control_xfer] = mode_default->tud_vendor_control_xfer_cb; +#else + tusb_got[tusbgot_vendor_control_xfer] = NULL; +#endif + + tusb_got[tusbgot_hid_descriptor_report ] = mode_default->tud_hid_descriptor_report_cb; + tusb_got[tusbgot_descriptor_device ] = mode_default->tud_descriptor_device_cb; + tusb_got[tusbgot_descriptor_configuration] = mode_default->tud_descriptor_configuration_cb; + tusb_got[tusbgot_descriptor_string ] = mode_default->tud_descriptor_string_cb; + // clang-format on +} +void modes_switch(uint8_t newmode) { + if (mode_current) mode_current->leave(); + + // to force a reconfig from the device, we basically have to kill the USB + // physical connection for a while + tud_disconnect(); + + // maybe wait a second or so for the host to notice this + sleep_ms(750); + + // now apply the new tusb settings + mode_current_id = (newmode >= 16 || newmode == 0) ? (-1) : newmode; + //mode_next_id = -1; + if (mode_current) { + // clang-format off +#if CFG_TUD_HID > 0 + tusb_got[tusbgot_hid_get_report ] = mode_current->tud_hid_get_report_cb; + tusb_got[tusbgot_hid_set_report ] = mode_current->tud_hid_set_report_cb; +#else + tusb_got[tusbgot_hid_get_report ] = NULL; + tusb_got[tusbgot_hid_set_report ] = NULL; +#endif +#if CFG_TUD_CDC > 0 + tusb_got[tusbgot_cdc_line_coding ] = mode_current->tud_cdc_line_coding_cb; +#else + tusb_got[tusbgot_cdc_line_coding ] = NULL; +#endif +#if CFG_TUD_VENDOR > 0 + tusb_got[tusbgot_vendor_control_xfer] = mode_current->tud_vendor_control_xfer_cb; +#else + tusb_got[tusbgot_vendor_control_xfer] = NULL; +#endif + + tusb_got[tusbgot_hid_descriptor_report ] = mode_current->tud_hid_descriptor_report_cb; + tusb_got[tusbgot_descriptor_device ] = mode_current->tud_descriptor_device_cb; + tusb_got[tusbgot_descriptor_configuration] = mode_current->tud_descriptor_configuration_cb; + tusb_got[tusbgot_descriptor_string ] = mode_current->tud_descriptor_string_cb; + // clang-format on + } else { + // TODO: invalid mode??? + } + + // and reconnect + tud_connect(); + while (!tud_mounted()) sleep_ms(5); + + if (mode_current) mode_current->enter(); +} + diff --git a/src/protos.h b/src/protos.h deleted file mode 100644 index 06d8fb8..0000000 --- a/src/protos.h +++ /dev/null @@ -1,40 +0,0 @@ -// vim: set et: - -#ifndef PROTOS_H_ -#define PROTOS_H_ - -#include -#include - -#include "protocfg.h" - -#define INFO_MANUFACTURER "BLAHAJ CTF" -#define INFO_PRODUCT_BARE "Dragnbus" -#define INFO_PRODUCT(board) "Dragnbus (" board ")" - -#ifdef DBOARD_HAS_UART -void cdc_uart_init(void); -void cdc_uart_task(void); - -void cdc_uart_set_hwflow(bool enable); -void cdc_uart_set_baudrate(uint32_t brate); -#endif - -#ifdef DBOARD_HAS_SERPROG -void cdc_serprog_init(void); -void cdc_serprog_task(void); -#endif - -#ifdef USE_USBCDC_FOR_STDIO -//#ifdef PICO_BOARD -bool stdio_usb_init(void); -//#endif -#endif - -#ifdef DBOARD_HAS_I2C -void itu_init(void); -void itu_task(void); -#endif - -#endif - diff --git a/src/rtconf.c b/src/rtconf.c deleted file mode 100644 index 1eb6bfa..0000000 --- a/src/rtconf.c +++ /dev/null @@ -1,58 +0,0 @@ -// vim: set et: - -#include "rtconf.h" - -#include -#include - -#include "protos.h" -#include "tempsensor.h" - -enum { - implmap_val = 0 -#ifdef DBOARD_HAS_CMSISDAP - | 1 -#endif -#ifdef DBOARD_HAS_UART - | 2 -#endif -#ifdef DBOARD_HAS_SERPROG - | 4 -#endif -#ifdef DBOARD_HAS_I2C - | 4 -#endif -#ifdef DBOARD_HAS_TEMPSENSOR - | 8 -#endif - -#ifdef USE_USBCDC_FOR_STDIO - | 128 -#endif -}; - -uint8_t rtconf_do(uint8_t a, uint8_t b) { - switch ((enum rtconf_opt)a) { -#ifdef DBOARD_HAS_UART - case opt_uart_hwfc_endis: cdc_uart_set_hwflow(b != 0); return 0; -#endif -#ifdef DBOARD_HAS_TEMPSENSOR - case opt_tempsense_enaddr: { - bool act = tempsense_get_active(); - uint8_t addr = tempsense_get_addr(); - printf("act=%c addr=%02x arg=%02x\n", act ? 't' : 'f', addr, b); - uint8_t rv = tempsense_get_active() ? tempsense_get_addr() : 0xff; - if (b == 0x00) - return rv; - else if (b == 0xff) - tempsense_set_active(false); - else - tempsense_set_addr(b); - return rv; - } -#endif - case opt_get_implmap: return implmap_val; - default: return 0xff; - } -} - diff --git a/src/rtconf.h b/src/rtconf.h deleted file mode 100644 index 7e71a86..0000000 --- a/src/rtconf.h +++ /dev/null @@ -1,30 +0,0 @@ -// vim: set et: - -#ifndef RTCONF_H_ -#define RTCONF_H_ - -#include - -#include "protocfg.h" - -enum rtconf_opt { -#ifdef DBOARD_HAS_UART - // enable_disable UART flow control - // b: 0 -> disable, nonzero -> enable - // return: 0 - opt_uart_hwfc_endis = 1, -#endif -#ifdef DBOARD_HAS_TEMPSENSOR - // 0x00: get I2C address or enable/disable status - // 0xff: disable - // other: set I2C address - opt_tempsense_enaddr = 2, -#endif - - opt_get_implmap = 0xff -}; - -uint8_t rtconf_do(uint8_t a, uint8_t b); - -#endif - diff --git a/src/serprog.h b/src/serprog.h deleted file mode 100644 index d62e81f..0000000 --- a/src/serprog.h +++ /dev/null @@ -1,56 +0,0 @@ -// vim: set et: - -#ifndef SERPROG_H_ -#define SERPROG_H_ - -enum serprog_cmd { - S_CMD_NOP = 0x00, - S_CMD_Q_IFACE = 0x01, - S_CMD_Q_CMDMAP = 0x02, - S_CMD_Q_PGMNAME = 0x03, - S_CMD_Q_SERBUF = 0x04, - S_CMD_Q_BUSTYPE = 0x05, - S_CMD_Q_CHIPSIZE = 0x06, - S_CMD_Q_OPBUF = 0x07, - S_CMD_Q_WRNMAXLEN = 0x08, - S_CMD_R_BYTE = 0x09, - S_CMD_R_NBYTES = 0x0a, - S_CMD_O_INIT = 0x0b, - S_CMD_O_WRITEB = 0x0c, - S_CMD_O_WRITEN = 0x0d, - S_CMD_O_DELAY = 0x0e, - S_CMD_O_EXEC = 0x0f, - S_CMD_SYNCNOP = 0x10, - S_CMD_Q_RDNMAXLEN = 0x11, - S_CMD_S_BUSTYPE = 0x12, - S_CMD_SPIOP = 0x13, - S_CMD_S_SPI_FREQ = 0x14, - S_CMD_S_PINSTATE = 0x15, - - S_CMD_MAGIC_SETTINGS = 0x53 -}; - -enum serprog_response { S_ACK = 0x06, S_NAK = 0x15 }; - -#define SERPROG_IFACE_VERSION 0x0001 - -uint32_t /*freq_applied*/ sp_spi_set_freq(uint32_t freq_wanted); - -void sp_spi_init(void); -void sp_spi_cs_deselect(void); -void sp_spi_cs_select(void); -void sp_spi_op_begin(void); -void sp_spi_op_write(uint32_t write_len, const uint8_t* write_data); -void sp_spi_op_read(uint32_t read_len, uint8_t* read_data); -void sp_spi_op_end(void); - -static inline void sp_spi_op_do( - uint32_t write_len, const uint8_t* write_data, uint32_t read_len, uint8_t* read_data) { - sp_spi_op_begin(); - sp_spi_op_write(write_len, write_data); - sp_spi_op_write(read_len, read_data); - sp_spi_op_end(); -} - -#endif - diff --git a/src/t/.gitignore b/src/t/.gitignore deleted file mode 100644 index 8206030..0000000 --- a/src/t/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tstest diff --git a/src/t/tstest.c b/src/t/tstest.c deleted file mode 100644 index ce19c1e..0000000 --- a/src/t/tstest.c +++ /dev/null @@ -1,73 +0,0 @@ - -#define DBOARD_HAS_TEMPSENSOR -#define VERY_FAKE - -#include - -static inline void tempsense_dev_init(void) { } -static inline int16_t tempsense_dev_get_temp(void) { return 42 << 4; } - -static inline int16_t tempsense_dev_get_lower(void) { return 0 << 4; } -static inline int16_t tempsense_dev_get_upper(void) { return 75 << 4; } -static inline int16_t tempsense_dev_get_crit(void) { return 80 << 4; } - -#include "../tempsensor.c" - -static int do_pkt(uint8_t cmd, bool read, uint16_t addr, uint16_t len, uint8_t* buf) { - int rv; - - if (cmd & 1) tempsense_do_start(); - - if (read) { - rv = tempsense_do_read(len, buf); - } else { - rv = tempsense_do_write(len, buf); - } - - if (cmd & 2) tempsense_do_stop(); - - printf("-> %d: %s\n", rv, (rv < 0 || rv != len) ? "nak" : "ack"); - - return rv; -} - -static void pbuf(size_t len, const uint8_t* buf) { - printf("--> "); - size_t i; - for (i = 0; i < len; ++i) { - printf("%02x ", buf[i]); - if ((i & 0xf) == 0xf) printf("%c", '\n'); - } - if ((i & 0xf) != 0x0) printf("%c", '\n'); -} - -int main(int argc, char* argv[]) { - tempsense_init(); - - tempsense_set_addr(0x18); - - // initial probe - uint8_t pk1[1] = {0}; - do_pkt(0x05, false, 0x18, 1, pk1); - uint8_t pk2[2]; - do_pkt(0x06, true, 0x18, 2, pk2); - pbuf(2, pk2); - - uint8_t pk3[1] = {1}; - do_pkt(0x05, false, 0x18, 1, pk3); - uint8_t pk4[2]; - do_pkt(0x06, true, 0x18, 2, pk4); - pbuf(2, pk4); - - // sensor data get - - // out 0x05 cmd5 - // in 2byte cmd6 - // out 0x04 cmd5 - // in 2byte cmd6 - // out 0x03 cmd5 - // in 2byte cmd6 - // out 0x02 cmd5 - // in 2byte cmd6 -} - diff --git a/src/tempsensor.c b/src/tempsensor.c deleted file mode 100644 index ea2eecc..0000000 --- a/src/tempsensor.c +++ /dev/null @@ -1,245 +0,0 @@ -// vim: set et: - -#include -#include -#include -#include - -#ifndef VERY_FAKE -#include "protocfg.h" -// clang-format off -#define printf(fmt, ...) do { } while (0) \ - -// clang-format on -#endif - -#ifdef DBOARD_HAS_TEMPSENSOR - -#include "tempsensor.h" - -static bool active; -static uint8_t addr; -static uint8_t reg; -static size_t index; -static bool instartstop, hasreg; - -enum regid { cap = 0, config, t_upper, t_lower, t_crit, t_a, manuf_id, dev_idrev, reso }; - -#define MANUF_ID 0x0054 -#define DEV_IDREV 0x0400 - -struct { - uint16_t config; - uint16_t t_upper, t_lower, t_crit; - uint8_t reso; -} mcp9808; - -#define float2fix(x) (int)((x) * (1 << 4)) -__attribute__((__const__)) inline static int16_t trunc_8fix4(int fix) { - // clang-format off - if (fix > 4095) fix = 4095; - if (fix < -4096) fix = -4096; - // clang-format on - return fix; -} -void tempsense_init(void) { - active = false; - addr = 0xff; - reg = 0; - index = 0; - instartstop = false; - hasreg = false; - - tempsense_dev_init(); - - // clang-format off - mcp9808.t_lower = tempsense_dev_get_lower(); - mcp9808.t_upper = tempsense_dev_get_upper(); - mcp9808.t_crit = tempsense_dev_get_crit (); - // clang-format on -} - -bool tempsense_get_active(void) { return active; } -void tempsense_set_active(bool act) { - active = act; - if (!act) addr = 0xff; -} -uint8_t tempsense_get_addr(void) { return addr; } -void tempsense_set_addr(uint8_t a) { - addr = a; - active = addr >= 0x8 && addr <= 0x77; - printf("set: ad=%02x ac=%c\n", addr, active ? 't' : 'f'); -} - -void tempsense_do_start(void) { - printf("ts start\n"); - // reg = 0; - index = 0; - instartstop = true; - hasreg = false; -} -void tempsense_do_stop(void) { - printf("ts stop\n"); - instartstop = false; -} - -int tempsense_do_read(int length, uint8_t* buf) { - printf("read l=%d reg=%02x ", length, reg); - - if (!instartstop || length < 0) return -1; // nak - if (length == 0) return 0; // ack - // if (!hasreg) return -1; // nak - - int i; - for (i = 0; i < length; ++i, ++index) { - switch (reg) { - // TODO: big or little endian? seems to be big - case cap: buf[index] = 0; break; - case config: - if (index == 0) - buf[0] = (mcp9808.config >> 8) & 0xff; - else if (index == 1) - buf[1] = (mcp9808.config >> 0) & 0xff; - else - return index; - break; - case t_upper: - if (index == 0) - buf[0] = (mcp9808.t_upper >> 8) & 0xff; - else if (index == 1) - buf[1] = (mcp9808.t_upper >> 0) & 0xff; - else - return index; - break; - case t_lower: - if (index == 0) - buf[0] = (mcp9808.t_lower >> 8) & 0xff; - else if (index == 1) - buf[1] = (mcp9808.t_lower >> 0) & 0xff; - else - return index; - break; - case t_crit: - if (index == 0) - buf[0] = (mcp9808.t_crit >> 8) & 0xff; - else if (index == 1) - buf[1] = (mcp9808.t_crit >> 0) & 0xff; - else - return index; - break; - case t_a: { - static uint16_t temp; - if (index == 0) { - int16_t res = tempsense_dev_get_temp(); - - // clang-format off - uint32_t tup = mcp9808.t_upper & 0x1ffc; - if (tup & 0x1000) tup |= 0xffffe000; // make negative - uint32_t tlo = mcp9808.t_lower & 0x1ffc; - if (tlo & 0x1000) tlo |= 0xffffe000; // make negative - uint32_t tcr = mcp9808.t_crit & 0x1ffc; - if (tcr & 0x1000) tcr |= 0xffffe000; // make negative - // clang-format on - - temp = res & 0x1fff; // data bits and sign bit - - if ((int32_t)tlo > res) temp |= 0x2000; - if ((int32_t)tup < res) temp |= 0x4000; - if ((int32_t)tcr < res) temp |= 0x8000; - - buf[0] = (temp >> 8) & 0xff; - } else if (index == 1) - buf[1] = (temp >> 0) & 0xff; - else - return index; - } break; - case manuf_id: - if (index == 0) - buf[0] = (MANUF_ID >> 8) & 0xff; - else if (index == 1) - buf[1] = (MANUF_ID >> 0) & 0xff; - else - return index; - break; - case dev_idrev: - if (index == 0) - buf[0] = (DEV_IDREV >> 8) & 0xff; - else if (index == 1) - buf[1] = (DEV_IDREV >> 0) & 0xff; - else - return index; - break; - case reso: - if (index == 0) - buf[0] = mcp9808.reso; - else - return index; - break; - default: return -1; - } - } - - return i; -} -int tempsense_do_write(int length, const uint8_t* buf) { - printf("write l=%d reg=%02x iss=%c ", length, reg, instartstop ? 't' : 'f'); - - if (!instartstop || length < 0) return -1; // nak - if (length == 0) return 0; // ack - - if (!hasreg) { - printf("get reg %02x ", reg); - - reg = *buf & 0xf; - ++buf; - --length; - hasreg = true; - } - - if (length == 0) return 1; // ack, probably a read following - - int i; - for (i = 0; i < length; ++i, ++index) { - switch (reg) { - case config: - if (index == 0) { - mcp9808.config = (mcp9808.config & 0x00ff) | ((uint16_t)buf[0] << 8); - } else if (index == 1) { - mcp9808.config = (mcp9808.config & 0xff00) | ((uint16_t)buf[1] << 0); - } else - return index; - break; - case t_upper: - if (index == 0) { - mcp9808.t_upper = (mcp9808.t_upper & 0x00ff) | ((uint16_t)buf[0] << 8); - } else if (index == 1) { - mcp9808.t_upper = (mcp9808.t_upper & 0xff00) | ((uint16_t)buf[1] << 0); - } else - return index; - break; - case t_lower: - if (index == 0) { - mcp9808.t_lower = (mcp9808.t_lower & 0x00ff) | ((uint16_t)buf[0] << 8); - } else if (index == 1) { - mcp9808.t_lower = (mcp9808.t_lower & 0xff00) | ((uint16_t)buf[1] << 0); - } else - return index; - break; - case t_crit: - if (index == 0) { - mcp9808.t_crit = (mcp9808.t_crit & 0x00ff) | ((uint16_t)buf[0] << 8); - } else if (index == 1) { - mcp9808.t_crit = (mcp9808.t_crit & 0xff00) | ((uint16_t)buf[1] << 0); - } else - return index; - break; - case reso: mcp9808.reso = buf[index]; break; - default: printf("unk reg\n"); return -1; - } - } - - return i; -} - -#endif - diff --git a/src/tempsensor.h b/src/tempsensor.h deleted file mode 100644 index 6bf2e22..0000000 --- a/src/tempsensor.h +++ /dev/null @@ -1,32 +0,0 @@ -// vim: set et: - -#ifndef TEMPSENSOR_H_ -#define TEMPSENSOR_H_ - -#include -#include - -void tempsense_init(void); - -bool tempsense_get_active(void); -void tempsense_set_active(bool active); -uint8_t tempsense_get_addr(void); -void tempsense_set_addr(uint8_t addr); - -void tempsense_do_start(void); // start cond -int tempsense_do_read(int length, uint8_t* buf); -int tempsense_do_write(int length, const uint8_t* buf); -void tempsense_do_stop(void); // stop cond - -#ifdef DBOARD_HAS_TEMPSENSOR -void tempsense_dev_init(void); -// 8.4 -int16_t tempsense_dev_get_temp(void); - -int16_t tempsense_dev_get_lower(void); -int16_t tempsense_dev_get_upper(void); -int16_t tempsense_dev_get_crit(void); -#endif - -#endif - diff --git a/src/thread.c b/src/thread.c new file mode 100644 index 0000000..f528974 --- /dev/null +++ b/src/thread.c @@ -0,0 +1,16 @@ +// vim: set et: + +#include + +#include "thread.h" + +extern uint32_t co_active_buffer[64]; +uint32_t co_active_buffer[64]; +extern cothread_t co_active_handle; +cothread_t co_active_handle; + +static cothread_t mainthread; + +void thread_init (void) { mainthread = co_active(); } +void thread_yield(void) { co_switch(mainthread); } + diff --git a/src/thread.h b/src/thread.h new file mode 100644 index 0000000..2664774 --- /dev/null +++ b/src/thread.h @@ -0,0 +1,14 @@ +// vim: set et: + +#ifndef THREAD_H_ +#define THREAD_H_ + +#include + +#define THREAD_STACK_SIZE 1024 + +void thread_init (void); +void thread_yield(void); + +#endif + diff --git a/src/tusb_config.h b/src/tusb_config.h index 3f36553..99059ac 100644 --- a/src/tusb_config.h +++ b/src/tusb_config.h @@ -31,7 +31,7 @@ extern "C" { #endif -#include "protocfg.h" +//#include "protocfg.h" //-------------------------------------------------------------------- // COMMON CONFIGURATION @@ -108,12 +108,21 @@ extern "C" { #define CFG_TUD_MIDI 0 #define CFG_TUD_NET 0 // see also: bsp//protocfg.h +#define CFG_TUD_HID 0 +#ifdef USE_USBCDC_FOR_STDIO +#define CFG_TUD_CDC 1 +#else +#define CFG_TUD_CDC 0 +#endif +#define CFG_TUD_VENDOR 1 #define CFG_TUD_HID_EP_BUFSIZE 64 // CDC FIFO size of TX and RX #define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) #define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) +#define CFG_TUD_VENDOR_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) +#define CFG_TUD_VENDOR_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) #ifdef __cplusplus } diff --git a/src/tusb_plt.S b/src/tusb_plt.S new file mode 100644 index 0000000..a90d72c --- /dev/null +++ b/src/tusb_plt.S @@ -0,0 +1,108 @@ +@ vim: set ft=armv5: + +.cpu cortex-m0 +.thumb + +.section .data.tusb_gotplt, "awx", %progbits +.global tusb_plt +tusb_plt: + + @ sigh, thumb... +.type tud_hid_get_report_cb, %function +.global tud_hid_get_report_cb +tud_hid_get_report_cb: + push {r0} + ldr r0, .Lhid_get_report + mov r12, r0 + pop {r0} + bx r12 + +.type tud_hid_set_report_cb, %function +.global tud_hid_set_report_cb +tud_hid_set_report_cb: + push {r0} + ldr r0, .Lhid_set_report + mov r12, r0 + pop {r0} + bx r12 + +.type tud_cdc_line_coding_cb, %function +.global tud_cdc_line_coding_cb +tud_cdc_line_coding_cb: + push {r0} + ldr r0, .Lcdc_line_coding + mov r12, r0 + pop {r0} + bx r12 + +.type tud_vendor_control_xfer_cb, %function +.global tud_vendor_control_xfer_cb +tud_vendor_control_xfer_cb: + push {r0} + ldr r0, .Lvendor_control_xfer + mov r12, r0 + pop {r0} + bx r12 + + + +.type tud_hid_descriptor_report_cb, %function +.global tud_hid_descriptor_report_cb +tud_hid_descriptor_report_cb: + push {r0} + ldr r0, .Lhid_descriptor_report + mov r12, r0 + pop {r0} + bx r12 + +.type tud_descriptor_device_cb, %function +.global tud_descriptor_device_cb +tud_descriptor_device_cb: + push {r0} + ldr r0, .Ldescriptor_device + mov r12, r0 + pop {r0} + bx r12 + +.type tud_descriptor_configuration_cb, %function +.global tud_descriptor_configuration_cb +tud_descriptor_configuration_cb: + push {r0} + ldr r0, .Ldescriptor_configuration + mov r12, r0 + pop {r0} + bx r12 + +.type tud_descriptor_string_cb, %function +.global tud_descriptor_string_cb +tud_descriptor_string_cb: + push {r0} + ldr r0, .Ldescriptor_string + mov r12, r0 + pop {r0} + bx r12 + + + +.type tusb_got, %object +.size tusb_got, 4*8 +.global tusb_got +tusb_got: +.Lhid_get_report: + .4byte 0 @ tud_hid_get_report_cb +.Lhid_set_report: + .4byte 0 @ tud_hid_set_report_cb +.Lcdc_line_coding: + .4byte 0 @ tud_cdc_line_coding_cb +.Lvendor_control_xfer: + .4byte 0 @ tud_vendor_control_xfer_cb + +.Lhid_descriptor_report: + .4byte 0 @ tud_hid_descriptor_report_cb +.Ldescriptor_device: + .4byte 0 @ tud_descriptor_device_cb +.Ldescriptor_configuration: + .4byte 0 @ tud_descriptor_configuration_cb +.Ldescriptor_string: + .4byte 0 @ tud_descriptor_string_cb + diff --git a/src/usb_descriptors.c b/src/usb_descriptors.c deleted file mode 100644 index 5f9f881..0000000 --- a/src/usb_descriptors.c +++ /dev/null @@ -1,277 +0,0 @@ -// vim: set et: -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -#include "protos.h" -#include "tusb.h" -#include "util.h" - -/* A combination of interfaces must have a unique product id, since PC will save device driver after - * the first plug. Same VID/PID with different interface e.g MSC (first), then CDC (later) will - * possibly cause system error on PC. - * - * Auto ProductID layout's Bitmap: - * [MSB] HID | MSC | CDC [LSB] - */ -#ifdef DBOARD_HAS_I2C -#define USB_BCD_BASE 0x6000 -#else -#define USB_BCD_BASE 0x4000 -#endif -#define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n)) -#define USB_BCD \ - (USB_BCD_BASE | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 3) | _PID_MAP(HID, 6) | _PID_MAP(MIDI, 9) | \ - _PID_MAP(VENDOR, 12)) \ - - -// String Descriptor Index -enum { - STRID_LANGID = 0, - STRID_MANUFACTURER, - STRID_PRODUCT, - STRID_SERIAL, - - STRID_CONFIG, - - STRID_IF_HID_CMSISDAP, - STRID_IF_VND_I2CTINYUSB, - STRID_IF_CDC_UART, - STRID_IF_CDC_SERPROG, - STRID_IF_CDC_STDIO, -}; - -//--------------------------------------------------------------------+ -// Device Descriptors -//--------------------------------------------------------------------+ -// clang-format off -tusb_desc_device_t const desc_device = { - .bLength = sizeof(tusb_desc_device_t), - .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0110, // TODO: 0x0200 ? - .bDeviceClass = 0x00, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0x00, - .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - - .idVendor = USB_VID, - .idProduct = USB_PID, - .bcdDevice = USB_BCD, - - .iManufacturer = STRID_MANUFACTURER, - .iProduct = STRID_PRODUCT, - .iSerialNumber = STRID_SERIAL, - - .bNumConfigurations = 0x01 -}; -// clang-format on - -// Invoked when received GET DEVICE DESCRIPTOR -// Application return pointer to descriptor -uint8_t const* tud_descriptor_device_cb(void) { return (uint8_t const*)&desc_device; } - -//--------------------------------------------------------------------+ -// HID Report Descriptor -//--------------------------------------------------------------------+ - -// clang-format off -static uint8_t const desc_hid_report[] = { - TUD_HID_REPORT_DESC_GENERIC_INOUT(CFG_TUD_HID_EP_BUFSIZE) -}; -// clang-format on - -// Invoked when received GET HID REPORT DESCRIPTOR -// Application return pointer to descriptor -// Descriptor contents must exist long enough for transfer to complete -uint8_t const* tud_hid_descriptor_report_cb(uint8_t instance) { - (void)instance; - - return desc_hid_report; -} - -//--------------------------------------------------------------------+ -// Configuration Descriptor -//--------------------------------------------------------------------+ - -enum { -#ifdef DBOARD_HAS_I2C - ITF_NUM_VND_I2CTINYUSB, -#endif -#ifdef DBOARD_HAS_CMSISDAP - ITF_NUM_HID_CMSISDAP, -#endif -#ifdef DBOARD_HAS_UART - ITF_NUM_CDC_UART_COM, - ITF_NUM_CDC_UART_DATA, -#endif -#ifdef DBOARD_HAS_SERPROG - ITF_NUM_CDC_SERPROG_COM, - ITF_NUM_CDC_SERPROG_DATA, -#endif -#ifdef USE_USBCDC_FOR_STDIO - ITF_NUM_CDC_STDIO_COM, - ITF_NUM_CDC_STDIO_DATA, -#endif - - ITF_NUM_TOTAL -}; - -#define TUD_I2CTINYUSB_LEN (9) -#define TUD_I2CTINYUSB_DESCRIPTOR(_itfnum, _stridx) \ - 9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, 0, 0, 0, _stridx \ - - -enum { - CONFIG_TOTAL_LEN = TUD_CONFIG_DESC_LEN -#ifdef DBOARD_HAS_I2C - + TUD_I2CTINYUSB_LEN -#endif -#ifdef DBOARD_HAS_UART - + TUD_CDC_DESC_LEN -#endif -#ifdef DBOARD_HAS_CMSISDAP - + TUD_HID_INOUT_DESC_LEN -#endif -#ifdef DBOARD_HAS_SERPROG - + TUD_CDC_DESC_LEN -#endif -#ifdef USE_USBCDC_FOR_STDIO - + TUD_CDC_DESC_LEN -#endif -}; - -#define EPNUM_CDC_UART_OUT 0x02 -#define EPNUM_CDC_UART_IN 0x82 -#define EPNUM_CDC_UART_NOTIF 0x83 -#define EPNUM_HID_CMSISDAP 0x04 -#define EPNUM_CDC_SERPROG_OUT 0x05 -#define EPNUM_CDC_SERPROG_IN 0x85 -#define EPNUM_CDC_SERPROG_NOTIF 0x86 -#define EPNUM_CDC_STDIO_OUT 0x07 -#define EPNUM_CDC_STDIO_IN 0x87 -#define EPNUM_CDC_STDIO_NOTIF 0x88 - -// NOTE: if you modify this table, don't forget to keep tusb_config.h up to date as well! -// TODO: maybe add some strings to all these interfaces -// clang-format off -uint8_t const desc_configuration[] = { - TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, STRID_CONFIG, CONFIG_TOTAL_LEN, - TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), - -#ifdef DBOARD_HAS_CMSISDAP - TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID_CMSISDAP, STRID_IF_HID_CMSISDAP, - 0 /*HID_PROTOCOL_NONE*/, sizeof(desc_hid_report), EPNUM_HID_CMSISDAP, - 0x80 | (EPNUM_HID_CMSISDAP + 0), CFG_TUD_HID_EP_BUFSIZE, 1), -#endif - -#ifdef DBOARD_HAS_I2C - TUD_I2CTINYUSB_DESCRIPTOR(ITF_NUM_VND_I2CTINYUSB, STRID_IF_VND_I2CTINYUSB), -#endif - -#ifdef DBOARD_HAS_UART - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_UART_COM, STRID_IF_CDC_UART, EPNUM_CDC_UART_NOTIF, 64, - EPNUM_CDC_UART_OUT, EPNUM_CDC_UART_IN, 64), -#endif - -#ifdef DBOARD_HAS_SERPROG - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_SERPROG_COM, STRID_IF_CDC_SERPROG, EPNUM_CDC_SERPROG_NOTIF, - 64, EPNUM_CDC_SERPROG_OUT, EPNUM_CDC_SERPROG_IN, 64), -#endif - -#ifdef USE_USBCDC_FOR_STDIO - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_STDIO_COM, STRID_IF_CDC_STDIO, EPNUM_CDC_STDIO_NOTIF, 64, - EPNUM_CDC_STDIO_OUT, EPNUM_CDC_STDIO_IN, 64), -#endif -}; -// clang-format on - -// Invoked when received GET CONFIGURATION DESCRIPTOR -// Application return pointer to descriptor -// Descriptor contents must exist long enough for transfer to complete -uint8_t const* tud_descriptor_configuration_cb(uint8_t index) { - (void)index; // for multiple configurations - return desc_configuration; -} - -//--------------------------------------------------------------------+ -// String Descriptors -//--------------------------------------------------------------------+ - -// array of pointer to string descriptors -// clang-format off -char const* string_desc_arr[] = { - [STRID_LANGID] = (const char[]){0x09, 0x04}, // supported language is English (0x0409) - [STRID_MANUFACTURER] = INFO_MANUFACTURER, // Manufacturer - [STRID_PRODUCT] = INFO_PRODUCT(INFO_BOARDNAME), // Product - - [STRID_CONFIG] = "Configuration descriptor", - // max string length check: ||||||||||||||||||||||||||||||| - [STRID_IF_HID_CMSISDAP] = "CMSIS-DAP HID interface", - [STRID_IF_VND_I2CTINYUSB] = "I2C-Tiny-USB interface", - [STRID_IF_CDC_UART] = "UART CDC interface", - [STRID_IF_CDC_SERPROG] = "Serprog CDC interface", - [STRID_IF_CDC_STDIO] = "stdio CDC interface (debug)", -}; -// clang-format on - -// Invoked when received GET STRING DESCRIPTOR request -// Application return pointer to descriptor, whose contents must exist long enough for transfer to -// complete -uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) { - static uint16_t _desc_str[32]; - - (void)langid; - - uint8_t chr_count = 0; - - if (STRID_LANGID == index) { - memcpy(&_desc_str[1], string_desc_arr[STRID_LANGID], 2); - chr_count = 1; - } else if (STRID_SERIAL == index) { - chr_count = get_unique_id_u16(_desc_str + 1); - } else { - // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. - // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors - - if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0]))) return NULL; - - const char* str = string_desc_arr[index]; - - // Cap at max char - chr_count = TU_MIN(strlen(str), 31); - - // Convert ASCII string into UTF-16 - for (int i = 0; i < chr_count; i++) { _desc_str[1 + i] = str[i]; } - } - - // first byte is length (including header), second byte is string type - _desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2); - - return _desc_str; -} - -void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* line_coding) { - if (itf == CDC_N_UART) { cdc_uart_set_baudrate(line_coding->bit_rate); } -} - diff --git a/src/util.h b/src/util.h index dc07bb0..ae47e2d 100644 --- a/src/util.h +++ b/src/util.h @@ -10,8 +10,6 @@ static inline char nyb2hex(int x) { return 'A' + (x - 0xa); } -void thread_yield(void); - // clang-format off uint8_t get_unique_id_u8 (uint8_t * desc_str); uint8_t get_unique_id_u16(uint16_t* desc_str); diff --git a/src/vnd_cfg.c b/src/vnd_cfg.c new file mode 100644 index 0000000..52ef925 --- /dev/null +++ b/src/vnd_cfg.c @@ -0,0 +1,143 @@ +// vim: set et: + +#include +#include + +#include "mode.h" +#include "vnd_cfg.h" + +#include "thread.h" + +static uint8_t rx_buf[CFG_TUD_VENDOR_TX_BUFSIZE]; +static uint8_t tx_buf[CFG_TUD_VENDOR_TX_BUFSIZE]; + +static uint32_t rxavail, rxpos, txpos; + +void vnd_cfg_init(void) { + rxavail = 0; + rxpos = 0; + txpos = 0; +} + +uint8_t vnd_cfg_read_byte(void) { + while (rxavail <= 0) { + if (!tud_vendor_n_mounted(0) && !tud_vendor_n_available(0)) { + thread_yield(); + continue; + } + + rxpos = 0; + rxavail = tud_vendor_n_read(0, rx_buf, sizeof rx_buf); + + if (rxavail == 0) thread_yield(); + } + + uint8_t rv = rx_buf[rxpos]; + ++rxpos; + --rxavail; + + return rv; +} +void vnd_cfg_write_flush(void) { + // TODO: is this needed? + while (tud_vendor_n_write_available(0) < txpos) { + thread_yield(); + } + + tud_vendor_n_write(0, tx_buf, txpos); + txpos = 0; +} +void vnd_cfg_write_byte(uint8_t v) { + if (txpos == CFG_TUD_VENDOR_TX_BUFSIZE) { + vnd_cfg_write_flush(); + } + + tx_buf[txpos] = v; + ++txpos; +} +void vnd_cfg_write_resp(enum cfg_resp stat, uint16_t len, const void* data) { + if (len > 0x7fff) len = 0x7fff; // aaaaaaaaaaaaaaaaa // TODO: throw some kind of error + + vnd_cfg_write_byte(stat); + if (len < 0x80) { + vnd_cfg_write_byte(len); + } else { + vnd_cfg_write_byte((len & 0x7f) | 0x80); + vnd_cfg_write_byte(len >> 7); + } + + for (size_t i = 0; i < len; ++i) { + vnd_cfg_write_byte(((const uint8_t*)data)[i]); + } + + vnd_cfg_write_flush(); +} + +void vnd_cfg_task(void) { + uint8_t cmd = vnd_cfg_read_byte(); + uint8_t verbuf[2]; + + if (cmd & 0xf0) { + uint8_t mode = (uint8_t)(cmd & 0xf0) >> 4; + uint8_t mcmd = cmd & 0x0f; + if (mode != mode_current_id && mcmd > mode_cmd_get_features) { + vnd_cfg_write_resp(cfg_resp_badmode, 0, NULL); + } else if (mode_list[mode] == NULL) { + vnd_cfg_write_resp(cfg_resp_nosuchmode, 0, NULL); + } else { + switch (mcmd) { + case mode_cmd_get_name: + vnd_cfg_write_resp(cfg_resp_ok, strlen(mode_list[mode]->name), + mode_list[mode]->name); + break; + case mode_cmd_get_version: + verbuf[0] = (mode_list[mode]->version >> 0) & 0xff; + verbuf[1] = (mode_list[mode]->version >> 8) & 0xff; + + vnd_cfg_write_resp(cfg_resp_ok, 2, verbuf); + break; + default: + mode_list[mode]->handle_cmd(mcmd); + break; + } + } + } else { + switch (cmd) { + case cfg_cmd_get_version: + verbuf[0] = (VND_CFG_PROTO_VER >> 0) & 0xff; + verbuf[1] = (VND_CFG_PROTO_VER >> 8) & 0xff; + + vnd_cfg_write_resp(cfg_resp_ok, 2, verbuf); + break; + case cfg_cmd_get_modes: + verbuf[0] = 0x01; + for (size_t i = 1; i < 16; ++i) { + if (mode_list[i] != NULL) verbuf[0] |= 1 << i; + } + + vnd_cfg_write_resp(cfg_resp_ok, 1, verbuf); + break; + case cfg_cmd_get_cur_mode: + verbuf[0] = mode_current_id; + vnd_cfg_write_resp(cfg_resp_ok, 1, verbuf); + break; + case cfg_cmd_set_cur_mode: + verbuf[0] = vnd_cfg_read_byte(); + if (verbuf[0] == 0 || verbuf[0] >= 0x10 || mode_list[verbuf[0]] == NULL) { + vnd_cfg_write_resp(cfg_resp_nosuchmode, 0, NULL); + } else { + // will be handled later so the USB stack won't break, whcih might happen if reconfig would happen now + mode_next_id = verbuf[0]; + vnd_cfg_write_resp(cfg_resp_ok, 0, NULL); + } + break; + case cfg_cmd_get_infostr: + vnd_cfg_write_resp(cfg_resp_ok, strlen("Dragnbus"), "Dragnbus"); + break; + default: + vnd_cfg_write_resp(cfg_resp_illcmd, 0, NULL); + break; + } + } +} + diff --git a/src/vnd_cfg.h b/src/vnd_cfg.h new file mode 100644 index 0000000..3769a2f --- /dev/null +++ b/src/vnd_cfg.h @@ -0,0 +1,79 @@ +// vim: set et: + +#ifndef VND_CFG_H_ +#define VND_CFG_H_ + +#include + +/* the configuration vendor interface must always be the first vendor itf. */ + +#define VND_CFG_PROTO_VER 0x0010 + +void vnd_cfg_init(void); +void vnd_cfg_task(void); + +// commands meant for configuring and initializing the device +enum cfg_cmd { + cfg_cmd_get_version = 0x00, + cfg_cmd_get_modes = 0x01, + cfg_cmd_get_cur_mode = 0x02, + cfg_cmd_set_cur_mode = 0x03, + cfg_cmd_get_infostr = 0x04, +}; + +// common commands for every mode +// for non-active modes, only these three can be used, others will result in a +// 'badmode' error +enum mode_cmd { + mode_cmd_get_name = 0x00, + mode_cmd_get_version = 0x01, + mode_cmd_get_features = 0x02, +}; + +enum cfg_resp { + cfg_resp_ok = 0x00, + cfg_resp_illcmd = 0x01, + cfg_resp_badmode = 0x02, + cfg_resp_nosuchmode = 0x03, +}; + +uint8_t vnd_cfg_read_byte (void); +void vnd_cfg_write_flush(void); +void vnd_cfg_write_byte(uint8_t v); +void vnd_cfg_write_resp(enum cfg_resp stat, uint16_t len, const void* data); + +/* + * wire protocol: + * host sends messages, device sends replies. the device never initiates a xfer + * + * the first byte of a command is the combination of the mode it is meant for + * in the high nybble, and the command number itself in the low nybble. optional + * extra command bytes may follow, depending on the command itself. + * a high nybble is 0 signifies a general configuration command, not meant for + * a particular mode + * + * a response consists of a response status byte (enum cfg_resp), followed by + * a 7- or 15-bit VLQ int (little-endian) for the payload length, followed by + * the payload itself. + * + * general commands: + * * get vesion (0x00): returns a payload of 2 bytes with version data. should + * currently be 0x10 0x00 (00.10h) + * * get modes (0x01): returns 2 bytes with a bitmap containing all supported + * modes (bit 0 is for general cfg and must always be 1) + * * get cur mode (0x02): returns a single byte containing the current mode number + * * set cur mode (0x03): sets the current mode. one extra request byte, no + * response payload + * * get info string (0x04): get a string containing human-readable info about + * the device. for display only + * + * common mode commands: + * * get name (0x00): returns a name or other descriptive string in the payload. + * for display only + * * get version (0x01): returns a 2-byte version number in the payload + * * get_features (0x02): gets a bitmap of supported features. length and meaning + * of the bits depends on the mode + */ + +#endif + diff --git a/src/vnd_i2ctinyusb.c b/src/vnd_i2ctinyusb.c deleted file mode 100644 index cfa9afa..0000000 --- a/src/vnd_i2ctinyusb.c +++ /dev/null @@ -1,266 +0,0 @@ - -#include "protos.h" - -#ifdef DBOARD_HAS_I2C - -// clang-format off -#include -#include -#include - -#include - -#include "tusb.h" -#include "device/usbd_pvt.h" - -#include "protocfg.h" -#include "pinout.h" - -#include "i2ctinyusb.h" - -#include "tempsensor.h" -// clang-format on - -static uint8_t itf_num; - -static enum itu_status status; -static struct itu_cmd curcmd; - -static uint8_t rxbuf[128]; -static uint8_t txbuf[128]; - -static void iub_init(void) { - status = ITU_STATUS_IDLE; - memset(&curcmd, 0, sizeof curcmd); - - i2ctu_init(); -#ifdef DBOARD_HAS_TEMPSENSOR - tempsense_init(); -#endif -} - -static void iub_reset(uint8_t rhport) { - (void)rhport; - - status = ITU_STATUS_IDLE; - memset(&curcmd, 0, sizeof curcmd); - - i2ctu_init(); -#ifdef DBOARD_HAS_TEMPSENSOR - tempsense_init(); -#endif - - itf_num = 0; -} - -static uint16_t iub_open(uint8_t rhport, tusb_desc_interface_t const* itf_desc, uint16_t max_len) { - (void)rhport; - - // clang-format off - TU_VERIFY(itf_desc->bInterfaceClass == 0 - && itf_desc->bInterfaceSubClass == 0 - && itf_desc->bInterfaceProtocol == 0, - 0); - // clang-format on - - const uint16_t drv_len = sizeof(tusb_desc_interface_t); - TU_VERIFY(max_len >= drv_len, 0); - - itf_num = itf_desc->bInterfaceNumber; - - return drv_len; -} - -static bool iub_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const* req) { - (void)rhport; - - /*static char* stages[]={"SETUP","DATA","ACK"}; - static char* types[]={"STD","CLS","VND","INV"}; - - printf("ctl req stage=%s rt=%s, wIndex=%04x, bReq=%02x, wValue=%04x wLength=%04x\n", - stages[stage], types[req->bmRequestType_bit.type], - req->wIndex, req->bRequest, req->wValue, req->wLength);*/ - - if (req->bmRequestType_bit.type != TUSB_REQ_TYPE_VENDOR) return true; - - if (stage == CONTROL_STAGE_DATA) { - struct itu_cmd cmd = curcmd; - - if (req->bRequest >= ITU_CMD_I2C_IO && req->bRequest <= ITU_CMD_I2C_IO_BEGINEND && - cmd.cmd == req->bRequest && cmd.flags == req->wValue && cmd.addr == req->wIndex && - cmd.len == req->wLength) { - // printf("WDATA a=%04hx l=%04hx ", cmd.addr, cmd.len); - - // printf("data=%02x %02x...\n", rxbuf[0], rxbuf[1]); -#ifdef DBOARD_HAS_TEMPSENSOR - if (tempsense_get_active() && tempsense_get_addr() == cmd.addr) { - if (cmd.cmd & ITU_CMD_I2C_IO_BEGIN_F) tempsense_do_start(); - // FIXME: fix status handling - int rv = tempsense_do_write(cmd.len > sizeof rxbuf ? sizeof rxbuf : cmd.len, rxbuf); - if (rv < 0 || rv != cmd.len) - status = ITU_STATUS_ADDR_NAK; - else - status = ITU_STATUS_ADDR_ACK; - if (cmd.cmd & ITU_CMD_I2C_IO_END_F) tempsense_do_stop(); - } else -#endif - { - status = i2ctu_write(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK, cmd.addr, rxbuf, - cmd.len > sizeof rxbuf ? sizeof rxbuf : cmd.len); - } - - // cancel curcmd - curcmd.cmd = 0xff; - } - return true; - } else if (stage == CONTROL_STAGE_SETUP) { - switch (req->bRequest) { - case ITU_CMD_ECHO: { // flags to be echoed back, addr unused, len=2 - - if (req->wLength != 2) return false; // bad length -> let's stall - - uint8_t rv[2]; - rv[0] = req->wValue & 0xff; - rv[1] = (req->wValue >> 8) & 0xff; - return tud_control_xfer(rhport, req, rv, sizeof rv); - } break; - case ITU_CMD_GET_FUNC: { // flags unused, addr unused, len=4 - if (req->wLength != 4) return false; - - const uint32_t func = i2ctu_get_func(); - txbuf[0] = func & 0xff; - txbuf[1] = (func >> 8) & 0xff; - txbuf[2] = (func >> 16) & 0xff; - txbuf[3] = (func >> 24) & 0xff; - return tud_control_xfer(rhport, req, txbuf, 4); - } break; - case ITU_CMD_SET_DELAY: { // flags=delay, addr unused, len=0 - if (req->wLength != 0) return false; - - uint32_t us = req->wValue ? req->wValue : 1; - uint32_t freq = 1000 * 1000 / us; - - // printf("set freq us=%u freq=%u\n", us, freq); - if (i2ctu_set_freq(freq, us) != 0) // returned an ok frequency - return tud_control_status(rhport, req); - else - return false; - } break; - case ITU_CMD_GET_STATUS: { // flags unused, addr unused, len=1 - if (req->wLength != 1) return false; - - uint8_t rv = status; - return tud_control_xfer(rhport, req, &rv, 1); - } break; - - case ITU_CMD_I2C_IO: // flags: ki2c_flags - case ITU_CMD_I2C_IO_BEGIN: // addr: I2C address - case ITU_CMD_I2C_IO_END: // len: transfer size - case ITU_CMD_I2C_IO_BEGINEND: { // (transfer dir is in flags) - struct itu_cmd cmd; - cmd.flags = req->wValue; - cmd.addr = req->wIndex; - cmd.len = req->wLength; - cmd.cmd = req->bRequest; - - if (cmd.flags & I2C_M_RD) { // read from I2C device - // printf("read addr=%04hx len=%04hx ", cmd.addr, cmd.len); -#ifdef DBOARD_HAS_TEMPSENSOR - if (tempsense_get_active() && tempsense_get_addr() == cmd.addr) { - if (cmd.cmd & ITU_CMD_I2C_IO_BEGIN_F) tempsense_do_start(); - int rv = tempsense_do_read( - cmd.len > sizeof txbuf ? sizeof txbuf : cmd.len, txbuf); - if (rv < 0 || rv != cmd.len) - status = ITU_STATUS_ADDR_NAK; - else - status = ITU_STATUS_ADDR_ACK; - if (cmd.cmd & ITU_CMD_I2C_IO_END_F) tempsense_do_stop(); - } else -#endif - { - status = i2ctu_read(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK, cmd.addr, - txbuf, cmd.len > sizeof txbuf ? sizeof txbuf : cmd.len); - } - // printf("data=%02x %02x...\n", txbuf[0], txbuf[1]); - return tud_control_xfer( - rhport, req, txbuf, cmd.len > sizeof txbuf ? sizeof txbuf : cmd.len); - } else { // write - // printf("write addr=%04hx len=%04hx ", cmd.addr, cmd.len); - if (cmd.len == 0) { // address probe -> do this here - uint8_t bleh = 0; -#ifdef DBOARD_HAS_TEMPSENSOR - if (tempsense_get_active() && tempsense_get_addr() == cmd.addr) { - if (cmd.cmd & ITU_CMD_I2C_IO_BEGIN_F) tempsense_do_start(); - int rv = tempsense_do_write(0, &bleh); - if (rv < 0 || rv != cmd.len) - status = ITU_STATUS_ADDR_NAK; - else - status = ITU_STATUS_ADDR_ACK; - if (cmd.cmd & ITU_CMD_I2C_IO_END_F) tempsense_do_stop(); - } else -#endif - { - status = i2ctu_write(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK, - cmd.addr, &bleh, 0); - } - // printf("probe -> %d\n", status); - return tud_control_status(rhport, req); - } else { - // handled in DATA stage! - curcmd = cmd; - bool rv = tud_control_xfer(rhport, req, rxbuf, - cmd.len > sizeof rxbuf ? sizeof rxbuf : cmd.len); - return rv; - } - } - } break; - default: - // printf("I2C-Tiny-USB: unknown command %02x\n", req->bRequest); - return false; - } - } else - return true; // other stage... -} - -// never actually called fsr -static bool iub_xfer( - uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { - (void)rhport; - (void)ep_addr; - (void)result; - (void)xferred_bytes; - - return true; -} - -// interfacing stuff for TinyUSB API, actually defines the driver - -// clang-format off -static usbd_class_driver_t const i2ctinyusb_driver = { -#if CFG_TUSB_DEBUG >= 2 - .name = "i2c-tiny-usb", -#endif - - .init = iub_init, - .reset = iub_reset, - .open = iub_open, - .control_xfer_cb = iub_ctl_req, - .xfer_cb = iub_xfer, - .sof = NULL -}; -// clang-format on - -usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) { - *driver_count = 1; - return &i2ctinyusb_driver; -} - -// we need to implement this one, because tinyusb uses hardcoded stuff for -// endpoint 0, which is what the i2c-tiny-usb kernel module uses -bool tud_vendor_control_xfer_cb( - uint8_t rhport, uint8_t ep_addr, tusb_control_request_t const* req) { - return iub_ctl_req(rhport, ep_addr, req); -} - -#endif /* DBOARD_HAS_I2C */ -