From 04f8da5c497367442d75654da69e9d08149ead6a Mon Sep 17 00:00:00 2001 From: Setare Maleki <72472685+setaremalekiii@users.noreply.github.com> Date: Sat, 11 Jan 2025 11:16:20 -0800 Subject: [PATCH] USB Drivers (#1404) ### Changelist added a hw_usb layer, which contains CDC class USB calls for transmitting and receiving function calls. initialized a queue in the cdc_recieve function to place the information received under the hood into the queue one byte at a time ### Testing Done tested the receive by sending a message through python client tested the transmit function by sending a message and receiving it on the python end tested hot-plugging the USB device and seeing if the status is changing ### Resolved Tickets --------- Co-authored-by: Liam Ilan --- firmware/dev/f4dev/CMakeLists.txt | 6 +- .../dev/f4dev/src/cubemx/Src/usbd_cdc_if.c | 7 +- firmware/quadruna/VC/CMakeLists.txt | 1 - firmware/shared/src/hw/hw_usb.c | 95 +++++++++++++++++++ firmware/shared/src/hw/hw_usb.h | 28 ++++++ firmware/shared/src/io/io_log.c | 16 ---- scripts/usb_experiments/mirror_test.py | 42 ++++++++ 7 files changed, 172 insertions(+), 23 deletions(-) create mode 100644 firmware/shared/src/hw/hw_usb.c create mode 100644 firmware/shared/src/hw/hw_usb.h delete mode 100644 firmware/shared/src/io/io_log.c create mode 100644 scripts/usb_experiments/mirror_test.py diff --git a/firmware/dev/f4dev/CMakeLists.txt b/firmware/dev/f4dev/CMakeLists.txt index 08342ac7d2..706fbc8205 100644 --- a/firmware/dev/f4dev/CMakeLists.txt +++ b/firmware/dev/f4dev/CMakeLists.txt @@ -8,9 +8,11 @@ set(LINKER_SCRIPT "${LINKER_DIR}/stm32f412rgtx/stm32f412rgtx_app_only.ld") file(GLOB_RECURSE EMBEDDED_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.c") list(APPEND EMBEDDED_SRCS "${SHARED_HW_INCLUDE_DIR}/hw_sd.c" - "${SHARED_HW_INCLUDE_DIR}/hw_uart.c") + "${SHARED_HW_INCLUDE_DIR}/hw_uart.c" + "${SHARED_HW_INCLUDE_DIR}/hw_usb.c" +) list(REMOVE_ITEM EMBEDDED_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/src/cubemx/Src/sysmem.c") -set(EMBEDDED_INCLUDE_DIRS "${SHARED_IO_INCLUDE_DIR}" "${SHARED_HW_INCLUDE_DIR}") +set(EMBEDDED_INCLUDE_DIRS "${SHARED_IO_INCLUDE_DIR}" "${SHARED_HW_INCLUDE_DIR}" "${SHARED_APP_INCLUDE_DIR}") IF ("${TARGET}" STREQUAL "binary") generate_stm32cube_code( diff --git a/firmware/dev/f4dev/src/cubemx/Src/usbd_cdc_if.c b/firmware/dev/f4dev/src/cubemx/Src/usbd_cdc_if.c index ea535d7f88..5574bc8b57 100644 --- a/firmware/dev/f4dev/src/cubemx/Src/usbd_cdc_if.c +++ b/firmware/dev/f4dev/src/cubemx/Src/usbd_cdc_if.c @@ -26,7 +26,7 @@ #include "usbd_cdc_if.h" /* USER CODE BEGIN INCLUDE */ - +#include "hw_usb.h" /* USER CODE END INCLUDE */ /* Private typedef -----------------------------------------------------------*/ @@ -268,9 +268,8 @@ static int8_t CDC_Receive_FS(uint8_t *Buf, uint32_t *Len) USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]); USBD_CDC_ReceivePacket(&hUsbDeviceFS); - // Test: Send data back - uint16_t len = (uint16_t)*Len; - CDC_Transmit_FS(Buf, len); + // hook to hw_usb + hw_usb_pushRxMsgToQueue(Buf, *Len); return (USBD_OK); /* USER CODE END 6 */ diff --git a/firmware/quadruna/VC/CMakeLists.txt b/firmware/quadruna/VC/CMakeLists.txt index 21fca8ebae..d27af3a24e 100644 --- a/firmware/quadruna/VC/CMakeLists.txt +++ b/firmware/quadruna/VC/CMakeLists.txt @@ -25,7 +25,6 @@ list(APPEND IO_SRCS "${SHARED_IO_INCLUDE_DIR}/io_chimera.c" "${SHARED_IO_INCLUDE_DIR}/io_led.c" "${SHARED_IO_INCLUDE_DIR}/io_time.c" - "${SHARED_IO_INCLUDE_DIR}/io_log.c" ) set(IO_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src/io" "${SHARED_IO_INCLUDE_DIR}" "${SHARED_IO_INCLUDE_QUADRUNA_DIR}") diff --git a/firmware/shared/src/hw/hw_usb.c b/firmware/shared/src/hw/hw_usb.c new file mode 100644 index 0000000000..55d117b4e5 --- /dev/null +++ b/firmware/shared/src/hw/hw_usb.c @@ -0,0 +1,95 @@ +#include "hw_usb.h" +#include "usbd_cdc_if.h" +#include "cmsis_os.h" +#include "io_log.h" + +// setup rx queue +static StaticQueue_t rx_queue_control_block; +static uint8_t rx_queue_buf[RX_QUEUE_SIZE]; +static osMessageQueueId_t rx_queue_id = NULL; +static USBD_HandleTypeDef hUsbDeviceFS; + +static const osMessageQueueAttr_t rx_queue_attr = { .name = "USB RX Queue", + .attr_bits = 0, + .cb_mem = &rx_queue_control_block, + .cb_size = sizeof(StaticQueue_t), + .mq_mem = rx_queue_buf, + .mq_size = sizeof(rx_queue_buf) }; + +void hw_usb_init() +{ + if (rx_queue_id == NULL) + { + rx_queue_id = osMessageQueueNew(RX_QUEUE_SIZE, sizeof(uint8_t), &rx_queue_attr); + } +} + +bool hw_usb_checkConnection() +{ + return hUsbDeviceFS.dev_state != USBD_STATE_SUSPENDED; +} + +void hw_usb_transmit(uint8_t *msg, uint16_t len) +{ + CDC_Transmit_FS(msg, len); +} + +uint8_t hw_usb_recieve() +{ + // receive pops off the byte queue and returns + uint8_t res = 0; + osStatus_t status = osMessageQueueGet(rx_queue_id, &res, NULL, 100); + if (status == osOK) + return res; + return 0; +} + +void hw_usb_pushRxMsgToQueue(uint8_t *packet, uint32_t len) +{ + uint32_t space = osMessageQueueGetSpace(rx_queue_id); + if (len < space) + { + LOG_WARN("usb message queue overflow"); + } + + for (uint32_t i = 0; i < len; i += 1) + { + // write one byte at a time + osStatus_t status = osMessageQueuePut(rx_queue_id, &packet[i], 0, 0); + } +} + +void hw_usb_transmit_example() +{ + // init usb peripheral + hw_usb_init(); + osDelay(1000); + + int msg_count = 0; + for (;;) + { + // send hello (without null terminator) + char msg[] = "hello"; + uint8_t *packet = (uint8_t *)msg; + hw_usb_transmit(packet, 5); + + msg_count += 1; + LOG_INFO("transmitted \"hello\" %d times", msg_count); + + osDelay(1000); + } +} + +void hw_usb_recieve_example() +{ + // init usb peripheral + hw_usb_init(); + + // dump the queue. + for (int i = 0; true; i += 1) + { + uint8_t result = hw_usb_recieve(); + LOG_INFO("char %d: %c", i, (char)result); + osDelay(1000); + } +} diff --git a/firmware/shared/src/hw/hw_usb.h b/firmware/shared/src/hw/hw_usb.h new file mode 100644 index 0000000000..d65c5ee6cd --- /dev/null +++ b/firmware/shared/src/hw/hw_usb.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#define RX_QUEUE_SIZE 2048 + +// initialize the usb peripheral +void hw_usb_init(); + +// checks if the usb port is connected +bool hw_usb_checkConnection(); + +// transmits usb message of arbritrary length +void hw_usb_transmit(uint8_t *msg, uint16_t len); + +// receive a single byte over usb +uint8_t hw_usb_recieve(); + +// pushes a message onto the internal usb queue, +// for use in CDC_Receive_FS/CDC_Receive_HS +void hw_usb_pushRxMsgToQueue(uint8_t *packet, uint32_t len); + +// runs an example loop where the message "hello" is tx-ed repeatedly +void hw_usb_transmit_example(); + +// runs an example loop that logs all received bytes as chars +void hw_usb_recieve_example(); diff --git a/firmware/shared/src/io/io_log.c b/firmware/shared/src/io/io_log.c deleted file mode 100644 index a542b0788a..0000000000 --- a/firmware/shared/src/io/io_log.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "io_log.h" -#include "app_canAlerts.h" -#define MAX_FAULT_COUNT 50 - -void LOG_ALL_FAULTS(void) -{ - Fault_Warning_Info buffer[MAX_FAULT_COUNT] = { 0 }; - const uint8_t fault_count = app_canAlerts_FaultInfo(buffer); - LOG_INFO("=================================="); - LOG_INFO("All Faults:"); - for (uint8_t i = 0; i < fault_count; i++) - { - LOG_INFO("%s", buffer[i].name); - } - LOG_INFO("=================================="); -} diff --git a/scripts/usb_experiments/mirror_test.py b/scripts/usb_experiments/mirror_test.py new file mode 100644 index 0000000000..1038f0adca --- /dev/null +++ b/scripts/usb_experiments/mirror_test.py @@ -0,0 +1,42 @@ +import sys +import usb.core +import usb.util +import time +import importlib + +devboard = usb.core.find(idVendor=0x0483, idProduct=0x5740) +interface = devboard[0][(1,0)] + +endpointW = interface[0] +endpointR = interface[1] + +while True: + if devboard.is_kernel_driver_active(interface.bInterfaceNumber): + try: + + devboard.detach_kernel_driver(interface.bInterfaceNumber) + usb.util.claim_interface(devboard, interface.bInterfaceNumber) + except usb.core.USBError as e: + sys.exit("Could not detatch kernel driver from interface({0}): {1}".format(i, str(e))) + + print("input your data, if you want to end the program input: exit ") + dataIn = input() + if dataIn == "exit": + break + bytesWritten = devboard.write(endpointW.bEndpointAddress, dataIn) + print(f"Endpoint Address (Read): {endpointR.bEndpointAddress}") + print(f"Endpoint Attributes: {endpointR.bmAttributes}") + print(f"Endpoint Address (Read): {endpointW.bEndpointAddress}") + print(f"Endpoint Attributes: {endpointW.bmAttributes}") + + print(f"Wrote {bytesWritten} bytes") + time.sleep(1) + buf = devboard.read(endpointR.bEndpointAddress, len(dataIn)) + + res = bytes(buf).decode() + print(res) + +usb.util.release_interface(devboard, interface.bInterfaceNumber) + +# Note: We might need this - it throws resource busy errors, may be a problem later-on. +# devboard.attach_kernel_driver(interface.bInterfaceNumber)