From ee7e416a84faf50c9564d8d05e249c19884abc06 Mon Sep 17 00:00:00 2001 From: Greg Burns Date: Thu, 8 Feb 2024 13:49:46 -0800 Subject: [PATCH 01/16] Initial commit for MIDI usb host support Signed-off-by: Greg Burns --- Makefile | 2 + .../Class/MIDI/Inc/usbh_midi.h | 85 +++++++ .../Class/MIDI/Src/usbh_midi.c | 215 ++++++++++++++++++ src/dev/mcp23x17.h | 4 +- src/hid/usb_host.cpp | 74 +++--- src/hid/usb_host.h | 24 +- src/hid/usb_midi.cpp | 66 ++++-- src/hid/usb_midi.h | 4 +- src/usbh/usbh_conf.h | 2 +- 9 files changed, 423 insertions(+), 53 deletions(-) create mode 100644 Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h create mode 100644 Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c diff --git a/Makefile b/Makefile index 239c867f8..980a615a9 100644 --- a/Makefile +++ b/Makefile @@ -213,6 +213,7 @@ Middlewares/Third_Party/FatFs/src/ff_gen_drv.c \ Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_bot.c \ Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_scsi.c \ Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc.c \ +Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c \ Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c \ Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_ctlreq.c \ Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_ioreq.c \ @@ -302,6 +303,7 @@ C_INCLUDES = \ -IMiddlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc \ -IMiddlewares/ST/STM32_USB_Host_Library/Core/Inc \ -IMiddlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc \ +-IMiddlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc \ -IMiddlewares/Third_Party/FatFs/src \ -I$(MODULE_DIR) \ -I. diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h new file mode 100644 index 000000000..3aa661ff0 --- /dev/null +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h @@ -0,0 +1,85 @@ +/** + ****************************************************************************** + * @file usbh_midi.h + * @author Greg Burns + * @author MCD Application Team + * @brief This file contains all the prototypes for the usbh_midi.c + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2015 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +/* Define to prevent recursive ----------------------------------------------*/ +#ifndef __USBH_MIDI_H +#define __USBH_MIDI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "usbh_core.h" + +typedef enum { + MIDI_INIT = 0, + MIDI_IDLE, + MIDI_RX, + MIDI_FAIL +} MIDI_StateTypeDef; + +typedef enum { + MIDI_OK, + MIDI_NOT_READY, + MIDI_ERROR +} MIDI_ErrorTypeDef; + +typedef void (*USBH_MIDI_RxCallback)(uint8_t* buff, size_t len, void* pUser); + +#define USBH_MIDI_RX_BUF_SIZE 64 + +/* Structure for MIDI process */ +typedef struct _MIDI_Process { + uint8_t InPipe; + uint8_t InEp; + uint16_t InEpSize; + uint8_t OutPipe; + uint8_t OutEp; + uint16_t OutEpSize; + MIDI_StateTypeDef state; + MIDI_ErrorTypeDef error; + USBH_MIDI_RxCallback callback; + void* pUser; + uint8_t rxBuffer[USBH_MIDI_RX_BUF_SIZE]; +} MIDI_HandleTypeDef; + +/* MIDI Class Codes */ +#define USB_AUDIO_CLASS 0x01U +#define USB_MIDI_STREAMING_SUBCLASS 0x03U + +extern USBH_ClassTypeDef USBH_midi; +#define USBH_MIDI_CLASS &USBH_midi + +uint8_t USBH_MIDI_IsReady(USBH_HandleTypeDef *phost); + +MIDI_ErrorTypeDef USBH_MIDI_Transmit(USBH_HandleTypeDef *phost, + uint8_t* data, size_t len); + +void USBH_MIDI_SetReceiveCallback(USBH_HandleTypeDef *phost, + USBH_MIDI_RxCallback cb, void* pUser); + +#ifdef __cplusplus +} +#endif + +#endif /* __USBH_MIDI_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c new file mode 100644 index 000000000..786268179 --- /dev/null +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c @@ -0,0 +1,215 @@ +/** + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2015 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ + +#include "usbh_midi.h" +#include "daisy_core.h" + +static MIDI_HandleTypeDef DMA_BUFFER_MEM_SECTION static_midi; + +static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_MIDI_InterfaceDeInit(USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_MIDI_ClassRequest(USBH_HandleTypeDef *phost); +static USBH_StatusTypeDef USBH_MIDI_SOFProcess(USBH_HandleTypeDef *phost); + +USBH_ClassTypeDef USBH_midi = { + "MIDI", + USB_AUDIO_CLASS, + USBH_MIDI_InterfaceInit, + USBH_MIDI_InterfaceDeInit, + USBH_MIDI_ClassRequest, + USBH_MIDI_Process, + USBH_MIDI_SOFProcess, + NULL, +}; + +#define EP_IN 0x80U + +/** + * @brief USBH_MIDI_InterfaceInit + * The function init the MIDI class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost) +{ + USBH_StatusTypeDef status; + MIDI_HandleTypeDef *MIDI_Handle; + uint8_t interface = USBH_FindInterface(phost, phost->pActiveClass->ClassCode, + USB_MIDI_STREAMING_SUBCLASS, 0xFFU); + + if ((interface == 0xFFU) || (interface >= USBH_MAX_NUM_INTERFACES)) { + USBH_DbgLog("Cannot Find the interface for %s class.", phost->pActiveClass->Name); + return USBH_FAIL; + } + + status = USBH_SelectInterface(phost, interface); + if (status != USBH_OK) { + return USBH_FAIL; + } + + // Single static instance of midi handle + phost->pActiveClass->pData = &static_midi; + MIDI_Handle = (MIDI_HandleTypeDef*)phost->pActiveClass->pData; + + /* Initialize midi handler */ + USBH_memset(MIDI_Handle, 0, sizeof(MIDI_HandleTypeDef)); + + /* Find the endpoints */ + for (int ep = 0; ep <= 1; ++ep) { + if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].bEndpointAddress & EP_IN) { + MIDI_Handle->InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].bEndpointAddress; + MIDI_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].wMaxPacketSize; + } else { + MIDI_Handle->OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].bEndpointAddress; + MIDI_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].wMaxPacketSize; + } + } + + MIDI_Handle->state = MIDI_INIT; + MIDI_Handle->error = MIDI_OK; + MIDI_Handle->InPipe = USBH_AllocPipe(phost, MIDI_Handle->InEp); + + /* Open input pipe */ + USBH_OpenPipe(phost, MIDI_Handle->InPipe, MIDI_Handle->InEp, + phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, + MIDI_Handle->InEpSize); + + USBH_LL_SetToggle(phost, MIDI_Handle->InPipe, 0U); + + /* Open input pipe */ + USBH_OpenPipe(phost, MIDI_Handle->OutPipe, MIDI_Handle->OutEp, + phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, + MIDI_Handle->OutEpSize); + + USBH_LL_SetToggle(phost, MIDI_Handle->OutPipe, 0U); + + return USBH_OK; +} + +/** + * @brief USBH_MIDI_InterfaceDeInit + * The function DeInit the Pipes used for the MIDI class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_MIDI_InterfaceDeInit(USBH_HandleTypeDef *phost) +{ + MIDI_HandleTypeDef *MIDI_Handle = (MIDI_HandleTypeDef *) phost->pActiveClass->pData; + if (MIDI_Handle->InPipe) { + USBH_ClosePipe(phost, MIDI_Handle->InPipe); + USBH_FreePipe(phost, MIDI_Handle->InPipe); + MIDI_Handle->InPipe = 0U; /* Reset the Channel as Free */ + } + if (phost->pActiveClass->pData) { + phost->pActiveClass->pData = 0U; + } + return USBH_OK; +} + +/** + * @brief USBH_MIDI_ClassRequest + * The function is responsible for handling Standard requests + * for MIDI class. + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_MIDI_ClassRequest(USBH_HandleTypeDef *phost) +{ + phost->pUser(phost, HOST_USER_CLASS_ACTIVE); + return USBH_OK; +} + +/** + * @brief USBH_MIDI_Process + * The function is for managing state machine for MIDI data transfers + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) +{ + MIDI_HandleTypeDef *hMidi = (MIDI_HandleTypeDef*)phost->pActiveClass->pData; + USBH_StatusTypeDef error = USBH_OK; + USBH_URBStateTypeDef rxStatus; + + switch (hMidi->state) { + case MIDI_INIT: + hMidi->state = MIDI_IDLE; + break; + case MIDI_IDLE: + USBH_BulkReceiveData(phost, hMidi->rxBuffer, USBH_MIDI_RX_BUF_SIZE, hMidi->InPipe); + hMidi->state = MIDI_RX; + break; + case MIDI_RX: + rxStatus = USBH_LL_GetURBState(phost, hMidi->InPipe); + if (rxStatus == USBH_URB_DONE) { + size_t sz = USBH_LL_GetLastXferSize(phost, hMidi->InPipe); + hMidi->state = MIDI_IDLE; + hMidi->callback(hMidi->rxBuffer, sz, hMidi->pUser); + } else if (rxStatus == USBH_URB_ERROR || rxStatus == USBH_URB_STALL) { + hMidi->state = MIDI_FAIL; + error = USBH_FAIL; + } + break; + case MIDI_FAIL: + error = USBH_ClrFeature(phost, 0); + if (error == USBH_OK) { + hMidi->state = MIDI_IDLE; + } + break; + } + return error; +} + +/** + * @brief USBH_MIDI_SOFProcess + * The function is for SOF state + * @param phost: Host handle + * @retval USBH Status + */ +static USBH_StatusTypeDef USBH_MIDI_SOFProcess(USBH_HandleTypeDef *phost) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(phost); + return USBH_OK; +} + +void USBH_MIDI_SetReceiveCallback(USBH_HandleTypeDef *phost, USBH_MIDI_RxCallback cb, void* pUser) +{ + MIDI_HandleTypeDef *hMidi = (MIDI_HandleTypeDef*)phost->pActiveClass->pData; + hMidi->callback = cb; + hMidi->pUser = pUser; +} + +MIDI_ErrorTypeDef USBH_MIDI_Transmit(USBH_HandleTypeDef *phost, uint8_t* data, size_t len) +{ + MIDI_HandleTypeDef *hMidi = (MIDI_HandleTypeDef*)phost->pActiveClass->pData; + // TODO - This is currently always a blocking write + while (len) { + size_t sz = (len <= hMidi->OutEpSize) ? len : hMidi->OutEpSize; + USBH_BulkSendData(phost, data, sz, hMidi->OutPipe, 1); + USBH_URBStateTypeDef txStatus; + do { + txStatus = USBH_LL_GetURBState(phost, hMidi->OutPipe); + if (txStatus == USBH_URB_ERROR || txStatus == USBH_URB_STALL) { + return MIDI_ERROR; + } + } while (txStatus != USBH_URB_DONE); + len -= sz; + } + return MIDI_OK; +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/dev/mcp23x17.h b/src/dev/mcp23x17.h index fcc4db790..135ada61d 100644 --- a/src/dev/mcp23x17.h +++ b/src/dev/mcp23x17.h @@ -3,6 +3,8 @@ #include "per/gpio.h" #include "per/i2c.h" +#undef SetBit + namespace daisy { // Adapted from https://github.com/blemasle/arduino-mcp23017 @@ -398,4 +400,4 @@ class Mcp23X17 }; using Mcp23017 = Mcp23X17; -} // namespace daisy \ No newline at end of file +} // namespace daisy diff --git a/src/hid/usb_host.cpp b/src/hid/usb_host.cpp index f3c1ea6b4..8099662da 100644 --- a/src/hid/usb_host.cpp +++ b/src/hid/usb_host.cpp @@ -8,7 +8,6 @@ using namespace daisy; extern "C" { - extern HCD_HandleTypeDef hhcd_USB_OTG_HS; USBH_HandleTypeDef DMA_BUFFER_MEM_SECTION hUsbHostHS; } @@ -20,17 +19,23 @@ class USBHostHandle::Impl Impl() {} ~Impl() {} - Result Init(Config config); + Result Init(Config config, USBH_ClassTypeDef* pClass); Result Deinit(); Result Process(); Result ReEnumerate(); bool GetReady(); - inline Config &GetConfig() { return config_; } + inline Config& GetConfig(USBH_ClassTypeDef* pClass) { + for (uint32_t i = 0; i < hUsbHostHS.ClassNumber; ++i) { + if(hUsbHostHS.pClass[i] == pClass) + return config_[i]; + } + return config_[0]; + } private: - Config config_; + Config config_[USBH_MAX_NUM_SUPPORTED_CLASS]; /** @brief Maps ST Middleware USBH_StatusTypeDef to USBHostHandle::Result codes */ Result ConvertStatus(USBH_StatusTypeDef sta) @@ -52,31 +57,38 @@ class USBHostHandle::Impl } }; -// Global dfu handle -USBHostHandle::Impl msd_impl; +// Global handle +static USBHostHandle::Impl usbh_impl; static void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id); -USBHostHandle::Result USBHostHandle::Impl::Init(USBHostHandle::Config config) +USBHostHandle::Result USBHostHandle::Impl::Init(USBHostHandle::Config config, USBH_ClassTypeDef* pClass) { - config_ = config; /* Init host Library, add supported class and start the library. */ USBH_StatusTypeDef sta; - sta = USBH_Init(&hUsbHostHS, USBH_UserProcess, HOST_HS); - if(sta != USBH_OK) + bool firstTime = (hUsbHostHS.ClassNumber == 0); + if(firstTime) { - return ConvertStatus(sta); + sta = USBH_Init(&hUsbHostHS, USBH_UserProcess, HOST_HS); + if(sta != USBH_OK) + { + return ConvertStatus(sta); + } } - sta = USBH_RegisterClass(&hUsbHostHS, USBH_MSC_CLASS); + sta = USBH_RegisterClass(&hUsbHostHS, pClass); if(sta != USBH_OK) { return ConvertStatus(sta); } - sta = USBH_Start(&hUsbHostHS); - if(sta != USBH_OK) + if(firstTime) { - return ConvertStatus(sta); + sta = USBH_Start(&hUsbHostHS); + if(sta != USBH_OK) + { + return ConvertStatus(sta); + } } + config_[hUsbHostHS.ClassNumber] = config; return ConvertStatus(sta); } @@ -99,15 +111,13 @@ USBHostHandle::Result USBHostHandle::Impl::ReEnumerate() bool USBHostHandle::Impl::GetReady() { - return (bool)USBH_MSC_IsReady(&hUsbHostHS); + return Appli_state == APPLICATION_READY; } -// MSDHandle -> Impl - -USBHostHandle::Result USBHostHandle::Init(Config config) +USBHostHandle::Result USBHostHandle::Init(Config config, USBH_ClassTypeDef* pClass) { - pimpl_ = &msd_impl; - return pimpl_->Init(config); + pimpl_ = &usbh_impl; + return pimpl_->Init(config, pClass); } USBHostHandle::Result USBHostHandle::Deinit() @@ -115,10 +125,12 @@ USBHostHandle::Result USBHostHandle::Deinit() return pimpl_->Deinit(); } +#if 0 bool USBHostHandle::GetReady() { return pimpl_->GetReady(); } +#endif USBHostHandle::Result USBHostHandle::Process() { @@ -130,22 +142,30 @@ USBHostHandle::Result USBHostHandle::ReEnumerate() return pimpl_->ReEnumerate(); } +bool USBHostHandle::IsActiveClass(USBH_ClassTypeDef* pClass) +{ + return pClass == hUsbHostHS.pActiveClass; +} + +#if 0 bool USBHostHandle::GetPresent() { auto state = hUsbHostHS.gState; return (state != HOST_IDLE && state != HOST_ABORT_STATE && state != HOST_DEV_DISCONNECTED); } +#endif // Shared USB IRQ Handlers are located in sys/System.cpp // This isn't super useful for our typical code structure static void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id) { - auto &conf = msd_impl.GetConfig(); + auto &conf = usbh_impl.GetConfig(phost->pActiveClass); switch(id) { - case HOST_USER_SELECT_CONFIGURATION: break; + case HOST_USER_SELECT_CONFIGURATION: + break; case HOST_USER_CLASS_ACTIVE: Appli_state = APPLICATION_READY; if(conf.class_active_callback) @@ -154,7 +174,8 @@ static void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id) cb(conf.userdata); } break; - case HOST_USER_CLASS_SELECTED: break; + case HOST_USER_CLASS_SELECTED: + break; case HOST_USER_CONNECTION: Appli_state = APPLICATION_START; if(conf.connect_callback) @@ -178,6 +199,7 @@ static void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id) cb(conf.userdata); } break; - default: break; + default: + break; } -} \ No newline at end of file +} diff --git a/src/hid/usb_host.h b/src/hid/usb_host.h index 102b5ae5a..89ae71418 100644 --- a/src/hid/usb_host.h +++ b/src/hid/usb_host.h @@ -1,7 +1,8 @@ -#ifndef DSY_MSD -#define DSY_MSD +#ifndef USB_HOST_H +#define USB_HOST_H #include +#include "usbh_def.h" namespace daisy { @@ -49,7 +50,7 @@ class USBHostHandle typedef void (*DisconnectCallback)(void* data); /** @brief User defineable callback upon completion of class initialization - * For example, when a USB drive is connected and the mass storage class + * For example, when a USB drive is connected and the usb device class * initialization has finished, this callback will fire. * * @param userdata a pointer to some arbitrary data for use by the user. @@ -66,7 +67,7 @@ class USBHostHandle */ typedef void (*ErrorCallback)(void* data); - /** @brief Configuration structure for interfacing with MSD Driver */ + /** @brief Configuration structure for interfacing with USB host Driver */ struct Config { Config() @@ -88,13 +89,18 @@ class USBHostHandle * * \param config Configuration struct for initialization */ - Result Init(Config config); + Result Init(Config config, USBH_ClassTypeDef* usbClass); - /** Deinitializes MSD-related peripherals + /** Deinitializes USB host-related peripherals * */ Result Deinit(); + /** + * Returns true if the specified class is active + */ + bool IsActiveClass(USBH_ClassTypeDef* usbClass); + /** Manages usb host functionality * */ @@ -107,13 +113,13 @@ class USBHostHandle * and ready for communicaton * */ - bool GetReady(); + //bool GetReady(); /** Run after the first `Process` call to detect if * a device is present * */ - bool GetPresent(); + //bool GetPresent(); USBHostHandle() : pimpl_(nullptr) {} USBHostHandle(const USBHostHandle& other) = default; @@ -127,4 +133,4 @@ class USBHostHandle } // namespace daisy -#endif // DSY_MSD \ No newline at end of file +#endif // DSY_MSD diff --git a/src/hid/usb_midi.cpp b/src/hid/usb_midi.cpp index 811b1c404..91f254ad4 100644 --- a/src/hid/usb_midi.cpp +++ b/src/hid/usb_midi.cpp @@ -1,8 +1,15 @@ #include "system.h" #include "usbd_cdc.h" +#include "usbh_midi.h" #include "hid/usb_midi.h" #include +extern "C" { + extern USBH_HandleTypeDef hUsbHostHS; +} + +#define pUSB_Host &hUsbHostHS + using namespace daisy; class MidiUsbTransport::Impl @@ -33,6 +40,9 @@ class MidiUsbTransport::Impl UsbHandle usb_handle_; Config config_; + // When transport is configured for USB host + USBHostHandle usbh_handle_; + static constexpr size_t kBufferSize = 1024; bool rx_active_; // This corresponds to 256 midi messages @@ -80,6 +90,12 @@ void ReceiveCallback(uint8_t* buffer, uint32_t* length) } } +static void HostReceiveCallback(uint8_t* buffer, size_t sz, void* pUser) +{ + uint32_t len = sz; + ReceiveCallback(buffer, &len); +} + void MidiUsbTransport::Impl::Init(Config config) { // Borrowed from logger @@ -88,36 +104,56 @@ void MidiUsbTransport::Impl::Init(Config config) */ // static_assert(1u == sizeof(MidiUsbTransport::Impl::usb_handle_), "UsbHandle is not static"); - // This tells the USB middleware to send out MIDI descriptors instead of CDC - usbd_mode = USBD_MODE_MIDI; - config_ = config; + if(config_.periph == Config::HOST) + { + // Assume that a USB midi host device was detected but check anyhow + if(usbh_handle_.IsActiveClass(USBH_MIDI_CLASS)) + { + USBH_MIDI_SetReceiveCallback(pUSB_Host, HostReceiveCallback, nullptr); + } + } + else + { + // This tells the USB middleware to send out MIDI descriptors instead of CDC + usbd_mode = USBD_MODE_MIDI; + config_ = config; - UsbHandle::UsbPeriph periph = UsbHandle::FS_INTERNAL; - if(config_.periph == Config::EXTERNAL) - periph = UsbHandle::FS_EXTERNAL; + UsbHandle::UsbPeriph periph = UsbHandle::FS_INTERNAL; + if(config_.periph == Config::EXTERNAL) + periph = UsbHandle::FS_EXTERNAL; - usb_handle_.Init(periph); + usb_handle_.Init(periph); - rx_active_ = false; - System::Delay(10); - usb_handle_.SetReceiveCallback(ReceiveCallback, periph); + rx_active_ = false; + System::Delay(10); + usb_handle_.SetReceiveCallback(ReceiveCallback, periph); + } } void MidiUsbTransport::Impl::Tx(uint8_t* buffer, size_t size) { - UsbHandle::Result result; int attempt_count = config_.tx_retry_count; bool should_retry; MidiToUsb(buffer, size); do { - if(config_.periph == Config::EXTERNAL) - result = usb_handle_.TransmitExternal(tx_buffer_, tx_ptr_); + if(config_.periph == Config::HOST) + { + MIDI_ErrorTypeDef result; + result = USBH_MIDI_Transmit(pUSB_Host, tx_buffer_, tx_ptr_); + should_retry = (result == MIDI_ERROR) && attempt_count--; + } else - result = usb_handle_.TransmitInternal(tx_buffer_, tx_ptr_); + { + UsbHandle::Result result; + if(config_.periph == Config::EXTERNAL) + result = usb_handle_.TransmitExternal(tx_buffer_, tx_ptr_); + else + result = usb_handle_.TransmitInternal(tx_buffer_, tx_ptr_); + should_retry = (result == UsbHandle::Result::ERR) && attempt_count--; + } - should_retry = (result == UsbHandle::Result::ERR) && attempt_count--; if(should_retry) System::DelayUs(100); diff --git a/src/hid/usb_midi.h b/src/hid/usb_midi.h index 78e5cd983..c264b3b64 100644 --- a/src/hid/usb_midi.h +++ b/src/hid/usb_midi.h @@ -3,6 +3,7 @@ #define __DSY_MIDIUSBTRANSPORT_H__ #include "hid/usb.h" +#include "hid/usb_host.h" #include "sys/system.h" #include "util/ringbuffer.h" @@ -23,7 +24,8 @@ class MidiUsbTransport enum Periph { INTERNAL = 0, - EXTERNAL + EXTERNAL, + HOST }; Periph periph; diff --git a/src/usbh/usbh_conf.h b/src/usbh/usbh_conf.h index 6d26b89c7..2abacb1d6 100644 --- a/src/usbh/usbh_conf.h +++ b/src/usbh/usbh_conf.h @@ -76,7 +76,7 @@ extern "C" #define USBH_KEEP_CFG_DESCRIPTOR 1U /*---------- -----------*/ -#define USBH_MAX_NUM_SUPPORTED_CLASS 1U +#define USBH_MAX_NUM_SUPPORTED_CLASS 2U /*---------- -----------*/ #define USBH_MAX_SIZE_CONFIGURATION 256U From 6341891638e1daeda0013f9735adad85702db3fb Mon Sep 17 00:00:00 2001 From: Greg Burns Date: Fri, 9 Feb 2024 17:54:03 -0800 Subject: [PATCH 02/16] MIDI USB host example Signed-off-by: Greg Burns --- .../Class/MIDI/Inc/usbh_midi.h | 2 +- .../Class/MIDI/Src/usbh_midi.c | 28 ++-- core/Makefile | 1 + examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp | 143 ++++++++++++++++++ examples/MIDI_USBH_Input/Makefile | 12 ++ src/hid/usb_midi.cpp | 2 +- 6 files changed, 177 insertions(+), 11 deletions(-) create mode 100644 examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp create mode 100644 examples/MIDI_USBH_Input/Makefile diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h index 3aa661ff0..ae54f16a1 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h @@ -38,7 +38,7 @@ typedef enum { typedef enum { MIDI_OK, - MIDI_NOT_READY, + MIDI_BUSY, MIDI_ERROR } MIDI_ErrorTypeDef; diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c index 786268179..86617e853 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c @@ -196,18 +196,28 @@ void USBH_MIDI_SetReceiveCallback(USBH_HandleTypeDef *phost, USBH_MIDI_RxCallbac MIDI_ErrorTypeDef USBH_MIDI_Transmit(USBH_HandleTypeDef *phost, uint8_t* data, size_t len) { MIDI_HandleTypeDef *hMidi = (MIDI_HandleTypeDef*)phost->pActiveClass->pData; - // TODO - This is currently always a blocking write - while (len) { - size_t sz = (len <= hMidi->OutEpSize) ? len : hMidi->OutEpSize; - USBH_BulkSendData(phost, data, sz, hMidi->OutPipe, 1); - USBH_URBStateTypeDef txStatus; - do { - txStatus = USBH_LL_GetURBState(phost, hMidi->OutPipe); - if (txStatus == USBH_URB_ERROR || txStatus == USBH_URB_STALL) { + int numUrbs = 0; + // This only blocks if data won't fit into one URB + while(len) + { + USBH_URBStateTypeDef txStatus = USBH_LL_GetURBState(phost, hMidi->OutPipe); + while(txStatus != USBH_URB_IDLE && txStatus != USBH_URB_DONE) + { + if(txStatus == USBH_URB_ERROR || txStatus == USBH_URB_STALL) + { + USBH_ClrFeature(phost, hMidi->OutPipe); return MIDI_ERROR; } - } while (txStatus != USBH_URB_DONE); + if(numUrbs == 0) + return MIDI_BUSY; + + // Give previous URB time to complete + USBH_Delay(2); + } + size_t sz = (len <= hMidi->OutEpSize) ? len : hMidi->OutEpSize; + USBH_BulkSendData(phost, data, sz, hMidi->OutPipe, 1); len -= sz; + ++numUrbs; } return MIDI_OK; } diff --git a/core/Makefile b/core/Makefile index 646543157..3185f3725 100644 --- a/core/Makefile +++ b/core/Makefile @@ -139,6 +139,7 @@ C_INCLUDES += \ -I$(LIBDAISY_DIR)/Middlewares/ST/STM32_USB_Device_Library/Core/Inc \ -I$(LIBDAISY_DIR)/Middlewares/ST/STM32_USB_Host_Library/Core/Inc \ -I$(LIBDAISY_DIR)/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc \ +-I$(LIBDAISY_DIR)/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc \ -I$(SYSTEM_FILES_DIR)/ ifdef DAISYSP_DIR diff --git a/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp b/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp new file mode 100644 index 000000000..68cdd5757 --- /dev/null +++ b/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp @@ -0,0 +1,143 @@ +/** Example of setting reading MIDI Input via USB Host + * + * + * This requires a USB-A connector + * + * This example will also log incoming messages to the serial port for general MIDI troubleshooting + */ +#include "daisy_seed.h" +#include "usbh_midi.h" + +/** This prevents us from having to type "daisy::" in front of a lot of things. */ +using namespace daisy; + +/** Fills string with string representation of MidiEvent::Type + * str needs to be at least 16 bytes long to store the data + * TODO: Move this into MIDI lib or something +*/ +void GetMidiTypeAsString(MidiEvent& msg, char* str) +{ + switch(msg.type) + { + case NoteOff: strcpy(str, "NoteOff"); break; + case NoteOn: strcpy(str, "NoteOn"); break; + case PolyphonicKeyPressure: strcpy(str, "PolyKeyPres."); break; + case ControlChange: strcpy(str, "CC"); break; + case ProgramChange: strcpy(str, "Prog. Change"); break; + case ChannelPressure: strcpy(str, "Chn. Pressure"); break; + case PitchBend: strcpy(str, "PitchBend"); break; + case SystemCommon: strcpy(str, "Sys. Common"); break; + case SystemRealTime: strcpy(str, "Sys. Realtime"); break; + case ChannelMode: strcpy(str, "Chn. Mode"); break; + default: strcpy(str, "Unknown"); break; + } +} + +/** Global Hardware access */ +DaisySeed hw; +MidiUsbHandler midi; +USBHostHandle usbHost; + +/** FIFO to hold messages as we're ready to print them */ +FIFO event_log; + +void USBH_MIDI_Connect(void* data) +{ + hw.PrintLine("MIDI device connected"); + MidiUsbHandler::Config midi_config; + midi_config.transport_config.periph = MidiUsbTransport::Config::Periph::HOST; + midi_config.transport_config.tx_retry_count = 3; + midi.Init(midi_config); + midi.StartReceive(); +} + +void USBH_MIDI_Disconnect(void* data) +{ + hw.PrintLine("MIDI device disconnected"); +} + +void USBH_MIDI_ClassActive(void* data) +{ + hw.PrintLine("MIDI device class active"); +} + +void USBH_MIDI_Error(void* data) +{ + hw.PrintLine("MIDI device error"); +} + +int main(void) +{ + /** Initialize our hardware */ + hw.Init(); + + hw.StartLog(); + + /** Configure USB host */ + USBHostHandle::Config usbhConfig; + usbhConfig.connect_callback = USBH_MIDI_Connect, + usbhConfig.disconnect_callback = USBH_MIDI_Disconnect, + usbhConfig.class_active_callback = USBH_MIDI_ClassActive, + usbhConfig.error_callback = USBH_MIDI_Error, + usbHost.Init(usbhConfig, USBH_MIDI_CLASS); + + uint32_t now = System::GetNow(); + uint32_t log_time = System::GetNow(); + + /** Infinite Loop */ + while(1) + { + now = System::GetNow(); + + /** Process MIDI in the background */ + midi.Listen(); + + /** Loop through any MIDI Events */ + while(midi.HasEvents()) + { + MidiEvent msg = midi.PopEvent(); + + /** Handle messages as they come in + * See DaisyExamples for some examples of this + */ + switch(msg.type) + { + case NoteOn: + // Do something on Note On events + { + uint8_t bytes[3] = {0x90, 0x00, 0x00}; + bytes[1] = msg.data[0]; + bytes[2] = msg.data[1]; + midi.SendMessage(bytes, 3); + } + break; + default: break; + } + + /** Regardless of message, let's add the message data to our queue to output */ + event_log.PushBack(msg); + } + + /** Now separately, every 5ms we'll print the top message in our queue if there is one */ + if(now - log_time > 5) + { + log_time = now; + if(!event_log.IsEmpty()) + { + auto msg = event_log.PopFront(); + char outstr[128]; + char type_str[16]; + GetMidiTypeAsString(msg, type_str); + sprintf(outstr, + "time:\t%ld\ttype: %s\tChannel: %d\tData MSB: " + "%d\tData LSB: %d\n", + now, + type_str, + msg.channel, + msg.data[0], + msg.data[1]); + hw.PrintLine(outstr); + } + } + } +} diff --git a/examples/MIDI_USBH_Input/Makefile b/examples/MIDI_USBH_Input/Makefile new file mode 100644 index 000000000..b7ad88a33 --- /dev/null +++ b/examples/MIDI_USBH_Input/Makefile @@ -0,0 +1,12 @@ +# Project Name +TARGET = MIDI_USBH_Input + +# Sources +CPP_SOURCES = MIDI_USBH_Input.cpp + +# Library Locations +LIBDAISY_DIR = ../.. + +# Core location, and generic Makefile. +SYSTEM_FILES_DIR = $(LIBDAISY_DIR)/core +include $(SYSTEM_FILES_DIR)/Makefile diff --git a/src/hid/usb_midi.cpp b/src/hid/usb_midi.cpp index 91f254ad4..b10a8e56b 100644 --- a/src/hid/usb_midi.cpp +++ b/src/hid/usb_midi.cpp @@ -142,7 +142,7 @@ void MidiUsbTransport::Impl::Tx(uint8_t* buffer, size_t size) { MIDI_ErrorTypeDef result; result = USBH_MIDI_Transmit(pUSB_Host, tx_buffer_, tx_ptr_); - should_retry = (result == MIDI_ERROR) && attempt_count--; + should_retry = (result == MIDI_BUSY) && attempt_count--; } else { From 086730079224f06b3d0a8a3805e99edad7aaba9b Mon Sep 17 00:00:00 2001 From: Greg Burns Date: Sun, 11 Feb 2024 17:40:22 -0800 Subject: [PATCH 03/16] USB MIDI host working (debug output is on) Signed-off-by: Greg Burns --- Makefile | 1 - .../Class/MIDI/Src/usbh_midi.c | 11 ++- examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp | 32 +++++-- src/hid/usb_host.cpp | 91 +++++++++++-------- src/hid/usb_host.h | 8 +- src/hid/usb_midi.cpp | 13 +-- src/usbh/usbh_conf.h | 19 ++-- 7 files changed, 106 insertions(+), 69 deletions(-) diff --git a/Makefile b/Makefile index 980a615a9..c3d3495aa 100644 --- a/Makefile +++ b/Makefile @@ -289,7 +289,6 @@ C_DEFS = \ -DDATA_IN_D2_SRAM # ^ added for easy startup access - C_INCLUDES = \ -I$(MODULE_DIR) \ -I$(MODULE_DIR)/sys \ diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c index 86617e853..964319356 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c @@ -128,7 +128,7 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceDeInit(USBH_HandleTypeDef *phost) */ static USBH_StatusTypeDef USBH_MIDI_ClassRequest(USBH_HandleTypeDef *phost) { - phost->pUser(phost, HOST_USER_CLASS_ACTIVE); + phost->pUser(phost, HOST_CLASS_REQUEST); return USBH_OK; } @@ -146,24 +146,31 @@ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) switch (hMidi->state) { case MIDI_INIT: + USBH_UsrLog("MIDI state INIT"); hMidi->state = MIDI_IDLE; + phost->pUser(phost, HOST_USER_CLASS_ACTIVE); break; case MIDI_IDLE: + USBH_UsrLog("MIDI state IDLE"); USBH_BulkReceiveData(phost, hMidi->rxBuffer, USBH_MIDI_RX_BUF_SIZE, hMidi->InPipe); hMidi->state = MIDI_RX; break; case MIDI_RX: + //USBH_UsrLog("MIDI state RX"); rxStatus = USBH_LL_GetURBState(phost, hMidi->InPipe); if (rxStatus == USBH_URB_DONE) { size_t sz = USBH_LL_GetLastXferSize(phost, hMidi->InPipe); hMidi->state = MIDI_IDLE; - hMidi->callback(hMidi->rxBuffer, sz, hMidi->pUser); + if (hMidi->callback) { + hMidi->callback(hMidi->rxBuffer, sz, hMidi->pUser); + } } else if (rxStatus == USBH_URB_ERROR || rxStatus == USBH_URB_STALL) { hMidi->state = MIDI_FAIL; error = USBH_FAIL; } break; case MIDI_FAIL: + USBH_UsrLog("MIDI state FAIL"); error = USBH_ClrFeature(phost, 0); if (error == USBH_OK) { hMidi->state = MIDI_IDLE; diff --git a/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp b/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp index 68cdd5757..f8b64674f 100644 --- a/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp +++ b/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp @@ -37,6 +37,7 @@ void GetMidiTypeAsString(MidiEvent& msg, char* str) DaisySeed hw; MidiUsbHandler midi; USBHostHandle usbHost; +bool deviceActive = false; /** FIFO to hold messages as we're ready to print them */ FIFO event_log; @@ -44,21 +45,22 @@ FIFO event_log; void USBH_MIDI_Connect(void* data) { hw.PrintLine("MIDI device connected"); - MidiUsbHandler::Config midi_config; - midi_config.transport_config.periph = MidiUsbTransport::Config::Periph::HOST; - midi_config.transport_config.tx_retry_count = 3; - midi.Init(midi_config); - midi.StartReceive(); } void USBH_MIDI_Disconnect(void* data) { hw.PrintLine("MIDI device disconnected"); + deviceActive = false; } void USBH_MIDI_ClassActive(void* data) { hw.PrintLine("MIDI device class active"); + MidiUsbHandler::Config midi_config; + midi_config.transport_config.periph = MidiUsbTransport::Config::Periph::HOST; + midi.Init(midi_config); + midi.StartReceive(); + deviceActive = true; } void USBH_MIDI_Error(void* data) @@ -71,7 +73,9 @@ int main(void) /** Initialize our hardware */ hw.Init(); - hw.StartLog(); + hw.StartLog(true); + + hw.PrintLine("MIDI USB Host start"); /** Configure USB host */ USBHostHandle::Config usbhConfig; @@ -83,12 +87,28 @@ int main(void) uint32_t now = System::GetNow(); uint32_t log_time = System::GetNow(); + uint32_t blink_time = 0; + bool ledState = false; + + hw.PrintLine("MIDI USB Host initialized"); /** Infinite Loop */ while(1) { now = System::GetNow(); + if (now > blink_time) + { + hw.SetLed(ledState); + ledState = !ledState; + blink_time = now + 200; + } + /** Run USB host process */ + usbHost.Process(); + + if (!deviceActive) + continue; + /** Process MIDI in the background */ midi.Listen(); diff --git a/src/hid/usb_host.cpp b/src/hid/usb_host.cpp index 8099662da..6d13f13be 100644 --- a/src/hid/usb_host.cpp +++ b/src/hid/usb_host.cpp @@ -3,58 +3,70 @@ #include "daisy_core.h" #include "usbh_core.h" #include "usbh_msc.h" +#include "logger.h" using namespace daisy; extern "C" { USBH_HandleTypeDef DMA_BUFFER_MEM_SECTION hUsbHostHS; + void USBH_LogPrint(const char* format, ...); +} + +void USBH_LogPrint(const char* format, ...) +{ + va_list va; + va_start(va, format); + Logger::PrintLineV(format, va); + va_end(va); } ApplicationTypeDef Appli_state = APPLICATION_IDLE; class USBHostHandle::Impl { - public: - Impl() {} - ~Impl() {} + public: + Impl() { + memset(&hUsbHostHS, 0, sizeof(hUsbHostHS)); + } + ~Impl() {} - Result Init(Config config, USBH_ClassTypeDef* pClass); - Result Deinit(); - Result Process(); - Result ReEnumerate(); + Result Init(Config config, USBH_ClassTypeDef* pClass); + Result Deinit(); + Result Process(); + Result ReEnumerate(); - bool GetReady(); + bool GetReady(); - inline Config& GetConfig(USBH_ClassTypeDef* pClass) { - for (uint32_t i = 0; i < hUsbHostHS.ClassNumber; ++i) { - if(hUsbHostHS.pClass[i] == pClass) - return config_[i]; + inline Config& GetConfig(USBH_ClassTypeDef* pClass) { + for (uint32_t i = 0; i < hUsbHostHS.ClassNumber; ++i) { + if(hUsbHostHS.pClass[i] == pClass) + return config_[i]; + } + return config_[0]; } - return config_[0]; - } - private: - Config config_[USBH_MAX_NUM_SUPPORTED_CLASS]; + private: + Config config_[USBH_MAX_NUM_SUPPORTED_CLASS]; - /** @brief Maps ST Middleware USBH_StatusTypeDef to USBHostHandle::Result codes */ - Result ConvertStatus(USBH_StatusTypeDef sta) - { - if(sta != USBH_OK) + /** @brief Maps ST Middleware USBH_StatusTypeDef to USBHostHandle::Result codes */ + Result ConvertStatus(USBH_StatusTypeDef sta) { - return Result::FAIL; - } - switch(sta) - { - case USBH_OK: return Result::OK; - case USBH_BUSY: return Result::BUSY; - case USBH_NOT_SUPPORTED: return Result::NOT_SUPPORTED; - case USBH_UNRECOVERED_ERROR: return Result::UNRECOVERED_ERROR; - case USBH_ERROR_SPEED_UNKNOWN: return Result::ERROR_SPEED_UNKNOWN; - case USBH_FAIL: - default: return Result::FAIL; + if(sta != USBH_OK) + { + return Result::FAIL; + } + switch(sta) + { + case USBH_OK: return Result::OK; + case USBH_BUSY: return Result::BUSY; + case USBH_NOT_SUPPORTED: return Result::NOT_SUPPORTED; + case USBH_UNRECOVERED_ERROR: return Result::UNRECOVERED_ERROR; + case USBH_ERROR_SPEED_UNKNOWN: return Result::ERROR_SPEED_UNKNOWN; + case USBH_FAIL: + default: return Result::FAIL; + } } - } }; // Global handle @@ -64,10 +76,12 @@ static void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id); USBHostHandle::Result USBHostHandle::Impl::Init(USBHostHandle::Config config, USBH_ClassTypeDef* pClass) { + USBH_UsrLog("USBHostHandle:Init %d", hUsbHostHS.ClassNumber); /* Init host Library, add supported class and start the library. */ USBH_StatusTypeDef sta; - bool firstTime = (hUsbHostHS.ClassNumber == 0); - if(firstTime) + int classNumber = hUsbHostHS.ClassNumber; + // Initialize USB Host driver for first registered class + if(classNumber == 0) { sta = USBH_Init(&hUsbHostHS, USBH_UserProcess, HOST_HS); if(sta != USBH_OK) @@ -80,7 +94,7 @@ USBHostHandle::Result USBHostHandle::Impl::Init(USBHostHandle::Config config, US { return ConvertStatus(sta); } - if(firstTime) + if(classNumber == 0) { sta = USBH_Start(&hUsbHostHS); if(sta != USBH_OK) @@ -88,7 +102,7 @@ USBHostHandle::Result USBHostHandle::Impl::Init(USBHostHandle::Config config, US return ConvertStatus(sta); } } - config_[hUsbHostHS.ClassNumber] = config; + config_[classNumber] = config; return ConvertStatus(sta); } @@ -125,12 +139,10 @@ USBHostHandle::Result USBHostHandle::Deinit() return pimpl_->Deinit(); } -#if 0 bool USBHostHandle::GetReady() { return pimpl_->GetReady(); } -#endif USBHostHandle::Result USBHostHandle::Process() { @@ -147,20 +159,19 @@ bool USBHostHandle::IsActiveClass(USBH_ClassTypeDef* pClass) return pClass == hUsbHostHS.pActiveClass; } -#if 0 bool USBHostHandle::GetPresent() { auto state = hUsbHostHS.gState; return (state != HOST_IDLE && state != HOST_ABORT_STATE && state != HOST_DEV_DISCONNECTED); } -#endif // Shared USB IRQ Handlers are located in sys/System.cpp // This isn't super useful for our typical code structure static void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id) { + USBH_UsrLog("USBH_UserProcess %d", id); auto &conf = usbh_impl.GetConfig(phost->pActiveClass); switch(id) { diff --git a/src/hid/usb_host.h b/src/hid/usb_host.h index 89ae71418..465e3ed05 100644 --- a/src/hid/usb_host.h +++ b/src/hid/usb_host.h @@ -113,13 +113,17 @@ class USBHostHandle * and ready for communicaton * */ - //bool GetReady(); + bool GetReady(); /** Run after the first `Process` call to detect if * a device is present * */ - //bool GetPresent(); + bool GetPresent(); + + /** Returns name of the connected devices if there is one + */ + const char* GetProductName(); USBHostHandle() : pimpl_(nullptr) {} USBHostHandle(const USBHostHandle& other) = default; diff --git a/src/hid/usb_midi.cpp b/src/hid/usb_midi.cpp index b10a8e56b..1c054867c 100644 --- a/src/hid/usb_midi.cpp +++ b/src/hid/usb_midi.cpp @@ -40,9 +40,6 @@ class MidiUsbTransport::Impl UsbHandle usb_handle_; Config config_; - // When transport is configured for USB host - USBHostHandle usbh_handle_; - static constexpr size_t kBufferSize = 1024; bool rx_active_; // This corresponds to 256 midi messages @@ -104,19 +101,17 @@ void MidiUsbTransport::Impl::Init(Config config) */ // static_assert(1u == sizeof(MidiUsbTransport::Impl::usb_handle_), "UsbHandle is not static"); + config_ = config; + if(config_.periph == Config::HOST) { - // Assume that a USB midi host device was detected but check anyhow - if(usbh_handle_.IsActiveClass(USBH_MIDI_CLASS)) - { - USBH_MIDI_SetReceiveCallback(pUSB_Host, HostReceiveCallback, nullptr); - } + rx_active_ = false; + USBH_MIDI_SetReceiveCallback(pUSB_Host, HostReceiveCallback, nullptr); } else { // This tells the USB middleware to send out MIDI descriptors instead of CDC usbd_mode = USBD_MODE_MIDI; - config_ = config; UsbHandle::UsbPeriph periph = UsbHandle::FS_INTERNAL; if(config_.periph == Config::EXTERNAL) diff --git a/src/usbh/usbh_conf.h b/src/usbh/usbh_conf.h index 2abacb1d6..5ed25bc12 100644 --- a/src/usbh/usbh_conf.h +++ b/src/usbh/usbh_conf.h @@ -85,7 +85,7 @@ extern "C" #define USBH_MAX_DATA_BUFFER 512U /*---------- -----------*/ -#define USBH_DEBUG_LEVEL 0U +#define USBH_DEBUG_LEVEL 3U /*---------- -----------*/ #define USBH_USE_OS 0U @@ -127,11 +127,12 @@ extern "C" /* DEBUG macros */ #if(USBH_DEBUG_LEVEL > 0U) +extern void USBH_LogPrint(const char* format, ...); #define USBH_UsrLog(...) \ do \ { \ - printf(__VA_ARGS__); \ - printf("\n"); \ + USBH_LogPrint(__VA_ARGS__); \ + USBH_LogPrint("\n"); \ } while(0) #else #define USBH_UsrLog(...) \ @@ -145,9 +146,9 @@ extern "C" #define USBH_ErrLog(...) \ do \ { \ - printf("ERROR: "); \ - printf(__VA_ARGS__); \ - printf("\n"); \ + USBH_LogPrint("ERROR: "); \ + USBH_LogPrint(__VA_ARGS__); \ + USBH_LogPrint("\n"); \ } while(0) #else #define USBH_ErrLog(...) \ @@ -160,9 +161,9 @@ extern "C" #define USBH_DbgLog(...) \ do \ { \ - printf("DEBUG : "); \ - printf(__VA_ARGS__); \ - printf("\n"); \ + USBH_LogPrint("DEBUG : "); \ + USBH_LogPrint(__VA_ARGS__); \ + USBH_LogPrint("\n"); \ } while(0) #else #define USBH_DbgLog(...) \ From fe529fcd3e89dcf7a73427de6e3369ffb7db2666 Mon Sep 17 00:00:00 2001 From: Greg Burns Date: Thu, 15 Feb 2024 11:58:18 -0800 Subject: [PATCH 04/16] Works with some devices Signed-off-by: Greg Burns --- .../Class/MIDI/Src/usbh_midi.c | 70 ++++++---- .../Core/Src/usbh_core.c | 1 + .../Core/Src/usbh_pipes.c | 4 + examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp | 132 +++++++++--------- src/hid/usb_host.cpp | 84 +++++------ src/hid/usb_host.h | 9 +- src/hid/usb_midi.cpp | 5 +- src/usbh/usbh_conf.h | 2 +- 8 files changed, 170 insertions(+), 137 deletions(-) diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c index 964319356..88efec3ee 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c @@ -45,13 +45,20 @@ USBH_ClassTypeDef USBH_midi = { */ static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost) { + USBH_UsrLog(__FUNCTION__); USBH_StatusTypeDef status; MIDI_HandleTypeDef *MIDI_Handle; + + // Single static instance of midi handle + phost->pActiveClass->pData = &static_midi; + MIDI_Handle = (MIDI_HandleTypeDef*)phost->pActiveClass->pData; + USBH_memset(MIDI_Handle, 0, sizeof(MIDI_HandleTypeDef)); + uint8_t interface = USBH_FindInterface(phost, phost->pActiveClass->ClassCode, USB_MIDI_STREAMING_SUBCLASS, 0xFFU); if ((interface == 0xFFU) || (interface >= USBH_MAX_NUM_INTERFACES)) { - USBH_DbgLog("Cannot Find the interface for %s class.", phost->pActiveClass->Name); + USBH_DbgLog("Cannot find interface for %s class.", phost->pActiveClass->Name); return USBH_FAIL; } @@ -60,18 +67,14 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost) return USBH_FAIL; } - // Single static instance of midi handle - phost->pActiveClass->pData = &static_midi; - MIDI_Handle = (MIDI_HandleTypeDef*)phost->pActiveClass->pData; - - /* Initialize midi handler */ - USBH_memset(MIDI_Handle, 0, sizeof(MIDI_HandleTypeDef)); - /* Find the endpoints */ for (int ep = 0; ep <= 1; ++ep) { if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].bEndpointAddress & EP_IN) { MIDI_Handle->InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].bEndpointAddress; MIDI_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].wMaxPacketSize; + if (MIDI_Handle->InEpSize > USBH_MIDI_RX_BUF_SIZE) { + MIDI_Handle->InEpSize = USBH_MIDI_RX_BUF_SIZE; + } } else { MIDI_Handle->OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].bEndpointAddress; MIDI_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].wMaxPacketSize; @@ -80,21 +83,21 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost) MIDI_Handle->state = MIDI_INIT; MIDI_Handle->error = MIDI_OK; - MIDI_Handle->InPipe = USBH_AllocPipe(phost, MIDI_Handle->InEp); - /* Open input pipe */ + /* Allocate and open input pipe */ + MIDI_Handle->InPipe = USBH_AllocPipe(phost, MIDI_Handle->InEp); USBH_OpenPipe(phost, MIDI_Handle->InPipe, MIDI_Handle->InEp, phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, MIDI_Handle->InEpSize); - USBH_LL_SetToggle(phost, MIDI_Handle->InPipe, 0U); - - /* Open input pipe */ + /* Allocate and open output pipe */ + MIDI_Handle->OutPipe = USBH_AllocPipe(phost, MIDI_Handle->OutEp); USBH_OpenPipe(phost, MIDI_Handle->OutPipe, MIDI_Handle->OutEp, phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, MIDI_Handle->OutEpSize); - USBH_LL_SetToggle(phost, MIDI_Handle->OutPipe, 0U); + //USBH_LL_SetToggle(phost, MIDI_Handle->InPipe, 0U); + //USBH_LL_SetToggle(phost, MIDI_Handle->OutPipe, 0U); return USBH_OK; } @@ -107,14 +110,22 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost) */ static USBH_StatusTypeDef USBH_MIDI_InterfaceDeInit(USBH_HandleTypeDef *phost) { + USBH_UsrLog(__FUNCTION__); MIDI_HandleTypeDef *MIDI_Handle = (MIDI_HandleTypeDef *) phost->pActiveClass->pData; - if (MIDI_Handle->InPipe) { - USBH_ClosePipe(phost, MIDI_Handle->InPipe); - USBH_FreePipe(phost, MIDI_Handle->InPipe); - MIDI_Handle->InPipe = 0U; /* Reset the Channel as Free */ - } - if (phost->pActiveClass->pData) { + if (MIDI_Handle) { + if (MIDI_Handle->InPipe) { + USBH_ClosePipe(phost, MIDI_Handle->InPipe); + USBH_FreePipe(phost, MIDI_Handle->InPipe); + MIDI_Handle->InPipe = 0U; /* Reset the Channel as Free */ + } + if (MIDI_Handle->OutPipe) { + USBH_ClosePipe(phost, MIDI_Handle->OutPipe); + USBH_FreePipe(phost, MIDI_Handle->OutPipe); + MIDI_Handle->InPipe = 0U; /* Reset the Channel as Free */ + } phost->pActiveClass->pData = 0U; + MIDI_Handle->state = MIDI_IDLE; + MIDI_Handle->error = MIDI_OK; } return USBH_OK; } @@ -146,17 +157,20 @@ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) switch (hMidi->state) { case MIDI_INIT: - USBH_UsrLog("MIDI state INIT"); hMidi->state = MIDI_IDLE; phost->pUser(phost, HOST_USER_CLASS_ACTIVE); break; case MIDI_IDLE: - USBH_UsrLog("MIDI state IDLE"); - USBH_BulkReceiveData(phost, hMidi->rxBuffer, USBH_MIDI_RX_BUF_SIZE, hMidi->InPipe); - hMidi->state = MIDI_RX; + error = USBH_BulkReceiveData(phost, hMidi->rxBuffer, USBH_MIDI_RX_BUF_SIZE, hMidi->InPipe); + if (error == USBH_OK) { + hMidi->state = MIDI_RX; + } else { + USBH_UsrLog("BulkReceiveData->%d", error); + hMidi->state = MIDI_FAIL; + error = USBH_FAIL; + } break; case MIDI_RX: - //USBH_UsrLog("MIDI state RX"); rxStatus = USBH_LL_GetURBState(phost, hMidi->InPipe); if (rxStatus == USBH_URB_DONE) { size_t sz = USBH_LL_GetLastXferSize(phost, hMidi->InPipe); @@ -170,10 +184,11 @@ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) } break; case MIDI_FAIL: - USBH_UsrLog("MIDI state FAIL"); - error = USBH_ClrFeature(phost, 0); + error = USBH_ClrFeature(phost, 0x00U); if (error == USBH_OK) { hMidi->state = MIDI_IDLE; + } else { + USBH_UsrLog("MIDI_FAIL Could not clear"); } break; } @@ -195,6 +210,7 @@ static USBH_StatusTypeDef USBH_MIDI_SOFProcess(USBH_HandleTypeDef *phost) void USBH_MIDI_SetReceiveCallback(USBH_HandleTypeDef *phost, USBH_MIDI_RxCallback cb, void* pUser) { + USBH_UsrLog(__FUNCTION__); MIDI_HandleTypeDef *hMidi = (MIDI_HandleTypeDef*)phost->pActiveClass->pData; hMidi->callback = cb; hMidi->pUser = pUser; diff --git a/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c b/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c index 76874c4f2..1d7533f85 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c +++ b/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c @@ -186,6 +186,7 @@ USBH_StatusTypeDef USBH_DeInit(USBH_HandleTypeDef *phost) phost->device.is_ReEnumerated = 0U; phost->device.RstCnt = 0U; phost->device.EnumCnt = 0U; + phost->ClassNumber = 0U; if (phost->pData != NULL) { diff --git a/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_pipes.c b/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_pipes.c index 60fe08b90..87c5388b2 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_pipes.c +++ b/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_pipes.c @@ -124,6 +124,10 @@ uint8_t USBH_AllocPipe(USBH_HandleTypeDef *phost, uint8_t ep_addr) { phost->Pipes[pipe & 0xFU] = 0x8000U | ep_addr; } + else + { + USBH_ErrLog("Alloc error: no free pipe"); + } return (uint8_t)pipe; } diff --git a/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp b/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp index f8b64674f..d3d9fd683 100644 --- a/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp +++ b/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp @@ -37,35 +37,35 @@ void GetMidiTypeAsString(MidiEvent& msg, char* str) DaisySeed hw; MidiUsbHandler midi; USBHostHandle usbHost; -bool deviceActive = false; /** FIFO to hold messages as we're ready to print them */ FIFO event_log; -void USBH_MIDI_Connect(void* data) +void USBH_Connect(void* data) { - hw.PrintLine("MIDI device connected"); + hw.PrintLine("device connected"); } -void USBH_MIDI_Disconnect(void* data) +void USBH_Disconnect(void* data) { - hw.PrintLine("MIDI device disconnected"); - deviceActive = false; + hw.PrintLine("device disconnected"); } -void USBH_MIDI_ClassActive(void* data) +void USBH_ClassActive(void* data) { - hw.PrintLine("MIDI device class active"); - MidiUsbHandler::Config midi_config; - midi_config.transport_config.periph = MidiUsbTransport::Config::Periph::HOST; - midi.Init(midi_config); - midi.StartReceive(); - deviceActive = true; + if(usbHost.IsActiveClass(USBH_MIDI_CLASS)) + { + hw.PrintLine("MIDI device class active"); + MidiUsbHandler::Config midi_config; + midi_config.transport_config.periph = MidiUsbTransport::Config::Periph::HOST; + midi.Init(midi_config); + midi.StartReceive(); + } } -void USBH_MIDI_Error(void* data) +void USBH_Error(void* data) { - hw.PrintLine("MIDI device error"); + hw.PrintLine("USB device error"); } int main(void) @@ -79,11 +79,13 @@ int main(void) /** Configure USB host */ USBHostHandle::Config usbhConfig; - usbhConfig.connect_callback = USBH_MIDI_Connect, - usbhConfig.disconnect_callback = USBH_MIDI_Disconnect, - usbhConfig.class_active_callback = USBH_MIDI_ClassActive, - usbhConfig.error_callback = USBH_MIDI_Error, - usbHost.Init(usbhConfig, USBH_MIDI_CLASS); + usbhConfig.connect_callback = USBH_Connect, + usbhConfig.disconnect_callback = USBH_Disconnect, + usbhConfig.class_active_callback = USBH_ClassActive, + usbhConfig.error_callback = USBH_Error, + usbHost.Init(usbhConfig); + + usbHost.RegisterClass(USBH_MIDI_CLASS); uint32_t now = System::GetNow(); uint32_t log_time = System::GetNow(); @@ -106,57 +108,57 @@ int main(void) /** Run USB host process */ usbHost.Process(); - if (!deviceActive) - continue; - - /** Process MIDI in the background */ - midi.Listen(); - - /** Loop through any MIDI Events */ - while(midi.HasEvents()) + if(usbHost.IsActiveClass(USBH_MIDI_CLASS)) { - MidiEvent msg = midi.PopEvent(); + /** Process MIDI in the background */ + midi.Listen(); - /** Handle messages as they come in - * See DaisyExamples for some examples of this - */ - switch(msg.type) + /** Loop through any MIDI Events */ + while(midi.HasEvents()) { - case NoteOn: - // Do something on Note On events - { - uint8_t bytes[3] = {0x90, 0x00, 0x00}; - bytes[1] = msg.data[0]; - bytes[2] = msg.data[1]; - midi.SendMessage(bytes, 3); - } - break; - default: break; + MidiEvent msg = midi.PopEvent(); + + /** Handle messages as they come in + * See DaisyExamples for some examples of this + */ + switch(msg.type) + { + case NoteOn: + // Do something on Note On events + { + uint8_t bytes[3] = {0x90, 0x00, 0x00}; + bytes[1] = msg.data[0]; + bytes[2] = msg.data[1]; + midi.SendMessage(bytes, 3); + } + break; + default: break; + } + + /** Regardless of message, let's add the message data to our queue to output */ + event_log.PushBack(msg); } - /** Regardless of message, let's add the message data to our queue to output */ - event_log.PushBack(msg); - } - - /** Now separately, every 5ms we'll print the top message in our queue if there is one */ - if(now - log_time > 5) - { - log_time = now; - if(!event_log.IsEmpty()) + /** Now separately, every 5ms we'll print the top message in our queue if there is one */ + if(now - log_time > 5) { - auto msg = event_log.PopFront(); - char outstr[128]; - char type_str[16]; - GetMidiTypeAsString(msg, type_str); - sprintf(outstr, - "time:\t%ld\ttype: %s\tChannel: %d\tData MSB: " - "%d\tData LSB: %d\n", - now, - type_str, - msg.channel, - msg.data[0], - msg.data[1]); - hw.PrintLine(outstr); + log_time = now; + if(!event_log.IsEmpty()) + { + auto msg = event_log.PopFront(); + char outstr[128]; + char type_str[16]; + GetMidiTypeAsString(msg, type_str); + sprintf(outstr, + "time:\t%ld\ttype: %s\tChannel: %d\tData MSB: " + "%d\tData LSB: %d\n", + now, + type_str, + msg.channel, + msg.data[0], + msg.data[1]); + hw.PrintLine(outstr); + } } } } diff --git a/src/hid/usb_host.cpp b/src/hid/usb_host.cpp index 6d13f13be..f3949203a 100644 --- a/src/hid/usb_host.cpp +++ b/src/hid/usb_host.cpp @@ -1,4 +1,5 @@ +#include #include "usb_host.h" #include "daisy_core.h" #include "usbh_core.h" @@ -31,23 +32,18 @@ class USBHostHandle::Impl } ~Impl() {} - Result Init(Config config, USBH_ClassTypeDef* pClass); + Result RegisterClass(USBH_ClassTypeDef* pClass); + Result Init(USBHostHandle::Config& config); Result Deinit(); Result Process(); Result ReEnumerate(); bool GetReady(); - inline Config& GetConfig(USBH_ClassTypeDef* pClass) { - for (uint32_t i = 0; i < hUsbHostHS.ClassNumber; ++i) { - if(hUsbHostHS.pClass[i] == pClass) - return config_[i]; - } - return config_[0]; - } + inline Config& GetConfig() { return config_; } private: - Config config_[USBH_MAX_NUM_SUPPORTED_CLASS]; + Config config_; /** @brief Maps ST Middleware USBH_StatusTypeDef to USBHostHandle::Result codes */ Result ConvertStatus(USBH_StatusTypeDef sta) @@ -74,35 +70,23 @@ static USBHostHandle::Impl usbh_impl; static void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id); -USBHostHandle::Result USBHostHandle::Impl::Init(USBHostHandle::Config config, USBH_ClassTypeDef* pClass) +USBHostHandle::Result USBHostHandle::Impl::RegisterClass(USBH_ClassTypeDef* pClass) { - USBH_UsrLog("USBHostHandle:Init %d", hUsbHostHS.ClassNumber); + return ConvertStatus(USBH_RegisterClass(&hUsbHostHS, pClass)); +} + +USBHostHandle::Result USBHostHandle::Impl::Init(USBHostHandle::Config& config) +{ + /* Copy in configuration */ + config_ = config; + /* Init host Library, add supported class and start the library. */ USBH_StatusTypeDef sta; - int classNumber = hUsbHostHS.ClassNumber; - // Initialize USB Host driver for first registered class - if(classNumber == 0) - { - sta = USBH_Init(&hUsbHostHS, USBH_UserProcess, HOST_HS); - if(sta != USBH_OK) - { - return ConvertStatus(sta); - } - } - sta = USBH_RegisterClass(&hUsbHostHS, pClass); - if(sta != USBH_OK) - { - return ConvertStatus(sta); - } - if(classNumber == 0) - { + + sta = USBH_Init(&hUsbHostHS, USBH_UserProcess, HOST_HS); + if(sta == USBH_OK) sta = USBH_Start(&hUsbHostHS); - if(sta != USBH_OK) - { - return ConvertStatus(sta); - } - } - config_[classNumber] = config; + return ConvertStatus(sta); } @@ -115,7 +99,22 @@ USBHostHandle::Result USBHostHandle::Impl::Deinit() USBHostHandle::Result USBHostHandle::Impl::Process() { - return ConvertStatus(USBH_Process(&hUsbHostHS)); + USBHostHandle::Result result; + + // The USBH state machine seems to get wedged in the + // abort state, re-initialize to try and clear it. + if(hUsbHostHS.gState == HOST_ABORT_STATE) + { + uint32_t numClasses = hUsbHostHS.ClassNumber; + Deinit(); + result = Init(config_); + // Restore registered class count + hUsbHostHS.ClassNumber = numClasses; + } + else + result = ConvertStatus(USBH_Process(&hUsbHostHS)); + + return result; } USBHostHandle::Result USBHostHandle::Impl::ReEnumerate() @@ -128,10 +127,16 @@ bool USBHostHandle::Impl::GetReady() return Appli_state == APPLICATION_READY; } -USBHostHandle::Result USBHostHandle::Init(Config config, USBH_ClassTypeDef* pClass) +USBHostHandle::Result USBHostHandle::RegisterClass(USBH_ClassTypeDef* pClass) +{ + pimpl_ = &usbh_impl; + return pimpl_->RegisterClass(pClass); +} + +USBHostHandle::Result USBHostHandle::Init(Config& config) { pimpl_ = &usbh_impl; - return pimpl_->Init(config, pClass); + return pimpl_->Init(config); } USBHostHandle::Result USBHostHandle::Deinit() @@ -166,13 +171,12 @@ bool USBHostHandle::GetPresent() && state != HOST_DEV_DISCONNECTED); } -// Shared USB IRQ Handlers are located in sys/System.cpp +// Shared USB IRQ Handlers are located in sys/System.cpps // This isn't super useful for our typical code structure static void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id) { - USBH_UsrLog("USBH_UserProcess %d", id); - auto &conf = usbh_impl.GetConfig(phost->pActiveClass); + auto &conf = usbh_impl.GetConfig(); switch(id) { case HOST_USER_SELECT_CONFIGURATION: diff --git a/src/hid/usb_host.h b/src/hid/usb_host.h index 465e3ed05..ef060b964 100644 --- a/src/hid/usb_host.h +++ b/src/hid/usb_host.h @@ -40,7 +40,7 @@ class USBHostHandle FAIL, NOT_SUPPORTED, UNRECOVERED_ERROR, - ERROR_SPEED_UNKNOWN, + ERROR_SPEED_UNKNOWN }; /** @brief User defineable callback for USB Connection */ @@ -85,11 +85,16 @@ class USBHostHandle void* userdata; }; + /** + * Register a USB class + */ + Result RegisterClass(USBH_ClassTypeDef* pClass); + /** Initializes the USB drivers and starts timeout. * * \param config Configuration struct for initialization */ - Result Init(Config config, USBH_ClassTypeDef* usbClass); + Result Init(USBHostHandle::Config& config); /** Deinitializes USB host-related peripherals * diff --git a/src/hid/usb_midi.cpp b/src/hid/usb_midi.cpp index 1c054867c..cb44a6cd1 100644 --- a/src/hid/usb_midi.cpp +++ b/src/hid/usb_midi.cpp @@ -19,6 +19,7 @@ class MidiUsbTransport::Impl void StartRx(MidiRxParseCallback callback, void* context) { + FlushRx(); rx_active_ = true; parse_callback_ = callback; parse_context_ = context; @@ -102,10 +103,11 @@ void MidiUsbTransport::Impl::Init(Config config) // static_assert(1u == sizeof(MidiUsbTransport::Impl::usb_handle_), "UsbHandle is not static"); config_ = config; + rx_active_ = false; if(config_.periph == Config::HOST) { - rx_active_ = false; + System::Delay(10); USBH_MIDI_SetReceiveCallback(pUSB_Host, HostReceiveCallback, nullptr); } else @@ -119,7 +121,6 @@ void MidiUsbTransport::Impl::Init(Config config) usb_handle_.Init(periph); - rx_active_ = false; System::Delay(10); usb_handle_.SetReceiveCallback(ReceiveCallback, periph); } diff --git a/src/usbh/usbh_conf.h b/src/usbh/usbh_conf.h index 5ed25bc12..f12b03d4d 100644 --- a/src/usbh/usbh_conf.h +++ b/src/usbh/usbh_conf.h @@ -85,7 +85,7 @@ extern "C" #define USBH_MAX_DATA_BUFFER 512U /*---------- -----------*/ -#define USBH_DEBUG_LEVEL 3U +#define USBH_DEBUG_LEVEL 0U /*---------- -----------*/ #define USBH_USE_OS 0U From c57b29eeed7026c71b786ea45d8b601286cf03c9 Mon Sep 17 00:00:00 2001 From: Greg Burns Date: Fri, 16 Feb 2024 11:45:53 -0800 Subject: [PATCH 05/16] Setting wrong state on MIDI_Deinit Signed-off-by: Greg Burns --- .../Class/MIDI/Inc/usbh_midi.h | 3 +- .../Class/MIDI/Src/usbh_midi.c | 49 +++++++++++-------- examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp | 9 +++- src/hid/usb_host.cpp | 26 +++++----- 4 files changed, 50 insertions(+), 37 deletions(-) diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h index ae54f16a1..f6e6c0cc8 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h @@ -31,8 +31,8 @@ extern "C" { typedef enum { MIDI_INIT = 0, - MIDI_IDLE, MIDI_RX, + MIDI_RX_POLL, MIDI_FAIL } MIDI_StateTypeDef; @@ -54,6 +54,7 @@ typedef struct _MIDI_Process { uint8_t OutPipe; uint8_t OutEp; uint16_t OutEpSize; + uint8_t ep_addr; MIDI_StateTypeDef state; MIDI_ErrorTypeDef error; USBH_MIDI_RxCallback callback; diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c index 88efec3ee..f959a887a 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c @@ -62,42 +62,43 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost) return USBH_FAIL; } +#if 1 status = USBH_SelectInterface(phost, interface); if (status != USBH_OK) { return USBH_FAIL; } +#endif /* Find the endpoints */ - for (int ep = 0; ep <= 1; ++ep) { + for (int ep = 0; ep < phost->device.CfgDesc.Itf_Desc[interface].bNumEndpoints; ++ep) { if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].bEndpointAddress & EP_IN) { MIDI_Handle->InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].bEndpointAddress; MIDI_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].wMaxPacketSize; if (MIDI_Handle->InEpSize > USBH_MIDI_RX_BUF_SIZE) { MIDI_Handle->InEpSize = USBH_MIDI_RX_BUF_SIZE; } + /* Allocate and open input pipe */ + MIDI_Handle->InPipe = USBH_AllocPipe(phost, MIDI_Handle->InEp); + USBH_OpenPipe(phost, MIDI_Handle->InPipe, MIDI_Handle->InEp, + phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, + MIDI_Handle->InEpSize); + (void)USBH_LL_SetToggle(phost, MIDI_Handle->InPipe, 0U); } else { MIDI_Handle->OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].bEndpointAddress; MIDI_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].wMaxPacketSize; + /* Allocate and open output pipe */ + MIDI_Handle->OutPipe = USBH_AllocPipe(phost, MIDI_Handle->OutEp); + USBH_OpenPipe(phost, MIDI_Handle->OutPipe, MIDI_Handle->OutEp, + phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, + MIDI_Handle->OutEpSize); + (void)USBH_LL_SetToggle(phost, MIDI_Handle->OutPipe, 0U); } } + MIDI_Handle->ep_addr = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress; MIDI_Handle->state = MIDI_INIT; MIDI_Handle->error = MIDI_OK; - /* Allocate and open input pipe */ - MIDI_Handle->InPipe = USBH_AllocPipe(phost, MIDI_Handle->InEp); - USBH_OpenPipe(phost, MIDI_Handle->InPipe, MIDI_Handle->InEp, - phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, - MIDI_Handle->InEpSize); - - /* Allocate and open output pipe */ - MIDI_Handle->OutPipe = USBH_AllocPipe(phost, MIDI_Handle->OutEp); - USBH_OpenPipe(phost, MIDI_Handle->OutPipe, MIDI_Handle->OutEp, - phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, - MIDI_Handle->OutEpSize); - - //USBH_LL_SetToggle(phost, MIDI_Handle->InPipe, 0U); - //USBH_LL_SetToggle(phost, MIDI_Handle->OutPipe, 0U); return USBH_OK; } @@ -124,7 +125,7 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceDeInit(USBH_HandleTypeDef *phost) MIDI_Handle->InPipe = 0U; /* Reset the Channel as Free */ } phost->pActiveClass->pData = 0U; - MIDI_Handle->state = MIDI_IDLE; + MIDI_Handle->state = MIDI_INIT; MIDI_Handle->error = MIDI_OK; } return USBH_OK; @@ -151,6 +152,9 @@ static USBH_StatusTypeDef USBH_MIDI_ClassRequest(USBH_HandleTypeDef *phost) */ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) { + if (!phost->pActiveClass || !phost->pActiveClass->pData) + return USBH_FAIL; + MIDI_HandleTypeDef *hMidi = (MIDI_HandleTypeDef*)phost->pActiveClass->pData; USBH_StatusTypeDef error = USBH_OK; USBH_URBStateTypeDef rxStatus; @@ -161,20 +165,23 @@ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) phost->pUser(phost, HOST_USER_CLASS_ACTIVE); break; case MIDI_IDLE: + hMidi->state = MIDI_RX; + break; + case MIDI_RX: error = USBH_BulkReceiveData(phost, hMidi->rxBuffer, USBH_MIDI_RX_BUF_SIZE, hMidi->InPipe); if (error == USBH_OK) { - hMidi->state = MIDI_RX; + hMidi->state = MIDI_RX_POLL; } else { USBH_UsrLog("BulkReceiveData->%d", error); hMidi->state = MIDI_FAIL; error = USBH_FAIL; } break; - case MIDI_RX: + case MIDI_RX_POLL: rxStatus = USBH_LL_GetURBState(phost, hMidi->InPipe); if (rxStatus == USBH_URB_DONE) { size_t sz = USBH_LL_GetLastXferSize(phost, hMidi->InPipe); - hMidi->state = MIDI_IDLE; + hMidi->state = MIDI_RX; if (hMidi->callback) { hMidi->callback(hMidi->rxBuffer, sz, hMidi->pUser); } @@ -184,7 +191,7 @@ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) } break; case MIDI_FAIL: - error = USBH_ClrFeature(phost, 0x00U); + error = USBH_ClrFeature(phost, hMidi->ep_addr); if (error == USBH_OK) { hMidi->state = MIDI_IDLE; } else { @@ -228,7 +235,7 @@ MIDI_ErrorTypeDef USBH_MIDI_Transmit(USBH_HandleTypeDef *phost, uint8_t* data, s { if(txStatus == USBH_URB_ERROR || txStatus == USBH_URB_STALL) { - USBH_ClrFeature(phost, hMidi->OutPipe); + USBH_ClrFeature(phost, hMidi->ep_addr); return MIDI_ERROR; } if(numUrbs == 0) diff --git a/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp b/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp index d3d9fd683..9edaf33ee 100644 --- a/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp +++ b/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp @@ -59,6 +59,8 @@ void USBH_ClassActive(void* data) MidiUsbHandler::Config midi_config; midi_config.transport_config.periph = MidiUsbTransport::Config::Periph::HOST; midi.Init(midi_config); + uint8_t reset = 0xFF; + midi.SendMessage(&reset, sizeof(reset)); midi.StartReceive(); } } @@ -73,7 +75,7 @@ int main(void) /** Initialize our hardware */ hw.Init(); - hw.StartLog(true); + hw.StartLog(); hw.PrintLine("MIDI USB Host start"); @@ -103,7 +105,10 @@ int main(void) { hw.SetLed(ledState); ledState = !ledState; - blink_time = now + 200; + if (usbHost.GetPresent()) + blink_time = now + 400; + else + blink_time = now + 80; } /** Run USB host process */ usbHost.Process(); diff --git a/src/hid/usb_host.cpp b/src/hid/usb_host.cpp index f3949203a..3654bd849 100644 --- a/src/hid/usb_host.cpp +++ b/src/hid/usb_host.cpp @@ -35,6 +35,7 @@ class USBHostHandle::Impl Result RegisterClass(USBH_ClassTypeDef* pClass); Result Init(USBHostHandle::Config& config); Result Deinit(); + Result Reinit(); Result Process(); Result ReEnumerate(); @@ -90,6 +91,16 @@ USBHostHandle::Result USBHostHandle::Impl::Init(USBHostHandle::Config& config) return ConvertStatus(sta); } +USBHostHandle::Result USBHostHandle::Impl::Reinit() +{ + uint32_t numClasses = hUsbHostHS.ClassNumber; + Deinit(); + USBHostHandle::Result result = Init(config_); + // Restore registered class count + hUsbHostHS.ClassNumber = numClasses; + return result; +} + USBHostHandle::Result USBHostHandle::Impl::Deinit() { USBH_Stop(&hUsbHostHS); @@ -99,22 +110,12 @@ USBHostHandle::Result USBHostHandle::Impl::Deinit() USBHostHandle::Result USBHostHandle::Impl::Process() { - USBHostHandle::Result result; - // The USBH state machine seems to get wedged in the // abort state, re-initialize to try and clear it. if(hUsbHostHS.gState == HOST_ABORT_STATE) - { - uint32_t numClasses = hUsbHostHS.ClassNumber; - Deinit(); - result = Init(config_); - // Restore registered class count - hUsbHostHS.ClassNumber = numClasses; - } + return Reinit(); else - result = ConvertStatus(USBH_Process(&hUsbHostHS)); - - return result; + return ConvertStatus(USBH_Process(&hUsbHostHS)); } USBHostHandle::Result USBHostHandle::Impl::ReEnumerate() @@ -129,7 +130,6 @@ bool USBHostHandle::Impl::GetReady() USBHostHandle::Result USBHostHandle::RegisterClass(USBH_ClassTypeDef* pClass) { - pimpl_ = &usbh_impl; return pimpl_->RegisterClass(pClass); } From c5e579146ffec928f6dd9fa947707668c74545bc Mon Sep 17 00:00:00 2001 From: Greg Burns Date: Fri, 16 Feb 2024 11:45:53 -0800 Subject: [PATCH 06/16] Setting wrong state on MIDI_Deinit Signed-off-by: Greg Burns --- .../Class/MIDI/Inc/usbh_midi.h | 3 +- .../Class/MIDI/Src/usbh_midi.c | 49 +++++++++++-------- examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp | 9 +++- src/hid/usb_host.cpp | 26 +++++----- 4 files changed, 50 insertions(+), 37 deletions(-) diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h index ae54f16a1..f6e6c0cc8 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h @@ -31,8 +31,8 @@ extern "C" { typedef enum { MIDI_INIT = 0, - MIDI_IDLE, MIDI_RX, + MIDI_RX_POLL, MIDI_FAIL } MIDI_StateTypeDef; @@ -54,6 +54,7 @@ typedef struct _MIDI_Process { uint8_t OutPipe; uint8_t OutEp; uint16_t OutEpSize; + uint8_t ep_addr; MIDI_StateTypeDef state; MIDI_ErrorTypeDef error; USBH_MIDI_RxCallback callback; diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c index 88efec3ee..f959a887a 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c @@ -62,42 +62,43 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost) return USBH_FAIL; } +#if 1 status = USBH_SelectInterface(phost, interface); if (status != USBH_OK) { return USBH_FAIL; } +#endif /* Find the endpoints */ - for (int ep = 0; ep <= 1; ++ep) { + for (int ep = 0; ep < phost->device.CfgDesc.Itf_Desc[interface].bNumEndpoints; ++ep) { if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].bEndpointAddress & EP_IN) { MIDI_Handle->InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].bEndpointAddress; MIDI_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].wMaxPacketSize; if (MIDI_Handle->InEpSize > USBH_MIDI_RX_BUF_SIZE) { MIDI_Handle->InEpSize = USBH_MIDI_RX_BUF_SIZE; } + /* Allocate and open input pipe */ + MIDI_Handle->InPipe = USBH_AllocPipe(phost, MIDI_Handle->InEp); + USBH_OpenPipe(phost, MIDI_Handle->InPipe, MIDI_Handle->InEp, + phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, + MIDI_Handle->InEpSize); + (void)USBH_LL_SetToggle(phost, MIDI_Handle->InPipe, 0U); } else { MIDI_Handle->OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].bEndpointAddress; MIDI_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].wMaxPacketSize; + /* Allocate and open output pipe */ + MIDI_Handle->OutPipe = USBH_AllocPipe(phost, MIDI_Handle->OutEp); + USBH_OpenPipe(phost, MIDI_Handle->OutPipe, MIDI_Handle->OutEp, + phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, + MIDI_Handle->OutEpSize); + (void)USBH_LL_SetToggle(phost, MIDI_Handle->OutPipe, 0U); } } + MIDI_Handle->ep_addr = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress; MIDI_Handle->state = MIDI_INIT; MIDI_Handle->error = MIDI_OK; - /* Allocate and open input pipe */ - MIDI_Handle->InPipe = USBH_AllocPipe(phost, MIDI_Handle->InEp); - USBH_OpenPipe(phost, MIDI_Handle->InPipe, MIDI_Handle->InEp, - phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, - MIDI_Handle->InEpSize); - - /* Allocate and open output pipe */ - MIDI_Handle->OutPipe = USBH_AllocPipe(phost, MIDI_Handle->OutEp); - USBH_OpenPipe(phost, MIDI_Handle->OutPipe, MIDI_Handle->OutEp, - phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, - MIDI_Handle->OutEpSize); - - //USBH_LL_SetToggle(phost, MIDI_Handle->InPipe, 0U); - //USBH_LL_SetToggle(phost, MIDI_Handle->OutPipe, 0U); return USBH_OK; } @@ -124,7 +125,7 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceDeInit(USBH_HandleTypeDef *phost) MIDI_Handle->InPipe = 0U; /* Reset the Channel as Free */ } phost->pActiveClass->pData = 0U; - MIDI_Handle->state = MIDI_IDLE; + MIDI_Handle->state = MIDI_INIT; MIDI_Handle->error = MIDI_OK; } return USBH_OK; @@ -151,6 +152,9 @@ static USBH_StatusTypeDef USBH_MIDI_ClassRequest(USBH_HandleTypeDef *phost) */ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) { + if (!phost->pActiveClass || !phost->pActiveClass->pData) + return USBH_FAIL; + MIDI_HandleTypeDef *hMidi = (MIDI_HandleTypeDef*)phost->pActiveClass->pData; USBH_StatusTypeDef error = USBH_OK; USBH_URBStateTypeDef rxStatus; @@ -161,20 +165,23 @@ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) phost->pUser(phost, HOST_USER_CLASS_ACTIVE); break; case MIDI_IDLE: + hMidi->state = MIDI_RX; + break; + case MIDI_RX: error = USBH_BulkReceiveData(phost, hMidi->rxBuffer, USBH_MIDI_RX_BUF_SIZE, hMidi->InPipe); if (error == USBH_OK) { - hMidi->state = MIDI_RX; + hMidi->state = MIDI_RX_POLL; } else { USBH_UsrLog("BulkReceiveData->%d", error); hMidi->state = MIDI_FAIL; error = USBH_FAIL; } break; - case MIDI_RX: + case MIDI_RX_POLL: rxStatus = USBH_LL_GetURBState(phost, hMidi->InPipe); if (rxStatus == USBH_URB_DONE) { size_t sz = USBH_LL_GetLastXferSize(phost, hMidi->InPipe); - hMidi->state = MIDI_IDLE; + hMidi->state = MIDI_RX; if (hMidi->callback) { hMidi->callback(hMidi->rxBuffer, sz, hMidi->pUser); } @@ -184,7 +191,7 @@ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) } break; case MIDI_FAIL: - error = USBH_ClrFeature(phost, 0x00U); + error = USBH_ClrFeature(phost, hMidi->ep_addr); if (error == USBH_OK) { hMidi->state = MIDI_IDLE; } else { @@ -228,7 +235,7 @@ MIDI_ErrorTypeDef USBH_MIDI_Transmit(USBH_HandleTypeDef *phost, uint8_t* data, s { if(txStatus == USBH_URB_ERROR || txStatus == USBH_URB_STALL) { - USBH_ClrFeature(phost, hMidi->OutPipe); + USBH_ClrFeature(phost, hMidi->ep_addr); return MIDI_ERROR; } if(numUrbs == 0) diff --git a/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp b/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp index d3d9fd683..9edaf33ee 100644 --- a/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp +++ b/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp @@ -59,6 +59,8 @@ void USBH_ClassActive(void* data) MidiUsbHandler::Config midi_config; midi_config.transport_config.periph = MidiUsbTransport::Config::Periph::HOST; midi.Init(midi_config); + uint8_t reset = 0xFF; + midi.SendMessage(&reset, sizeof(reset)); midi.StartReceive(); } } @@ -73,7 +75,7 @@ int main(void) /** Initialize our hardware */ hw.Init(); - hw.StartLog(true); + hw.StartLog(); hw.PrintLine("MIDI USB Host start"); @@ -103,7 +105,10 @@ int main(void) { hw.SetLed(ledState); ledState = !ledState; - blink_time = now + 200; + if (usbHost.GetPresent()) + blink_time = now + 400; + else + blink_time = now + 80; } /** Run USB host process */ usbHost.Process(); diff --git a/src/hid/usb_host.cpp b/src/hid/usb_host.cpp index f3949203a..3654bd849 100644 --- a/src/hid/usb_host.cpp +++ b/src/hid/usb_host.cpp @@ -35,6 +35,7 @@ class USBHostHandle::Impl Result RegisterClass(USBH_ClassTypeDef* pClass); Result Init(USBHostHandle::Config& config); Result Deinit(); + Result Reinit(); Result Process(); Result ReEnumerate(); @@ -90,6 +91,16 @@ USBHostHandle::Result USBHostHandle::Impl::Init(USBHostHandle::Config& config) return ConvertStatus(sta); } +USBHostHandle::Result USBHostHandle::Impl::Reinit() +{ + uint32_t numClasses = hUsbHostHS.ClassNumber; + Deinit(); + USBHostHandle::Result result = Init(config_); + // Restore registered class count + hUsbHostHS.ClassNumber = numClasses; + return result; +} + USBHostHandle::Result USBHostHandle::Impl::Deinit() { USBH_Stop(&hUsbHostHS); @@ -99,22 +110,12 @@ USBHostHandle::Result USBHostHandle::Impl::Deinit() USBHostHandle::Result USBHostHandle::Impl::Process() { - USBHostHandle::Result result; - // The USBH state machine seems to get wedged in the // abort state, re-initialize to try and clear it. if(hUsbHostHS.gState == HOST_ABORT_STATE) - { - uint32_t numClasses = hUsbHostHS.ClassNumber; - Deinit(); - result = Init(config_); - // Restore registered class count - hUsbHostHS.ClassNumber = numClasses; - } + return Reinit(); else - result = ConvertStatus(USBH_Process(&hUsbHostHS)); - - return result; + return ConvertStatus(USBH_Process(&hUsbHostHS)); } USBHostHandle::Result USBHostHandle::Impl::ReEnumerate() @@ -129,7 +130,6 @@ bool USBHostHandle::Impl::GetReady() USBHostHandle::Result USBHostHandle::RegisterClass(USBH_ClassTypeDef* pClass) { - pimpl_ = &usbh_impl; return pimpl_->RegisterClass(pClass); } From 59611871f6a09ec23fc98c7b9eae80768acf1128 Mon Sep 17 00:00:00 2001 From: Greg Burns Date: Sat, 17 Feb 2024 15:05:54 -0800 Subject: [PATCH 07/16] Endpoint size is only 10 bits Signed-off-by: Greg Burns --- .../Class/MIDI/Inc/usbh_midi.h | 1 + .../Class/MIDI/Src/usbh_midi.c | 13 +++++-------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h index f6e6c0cc8..b0faae614 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h @@ -31,6 +31,7 @@ extern "C" { typedef enum { MIDI_INIT = 0, + MIDI_IDLE, MIDI_RX, MIDI_RX_POLL, MIDI_FAIL diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c index f959a887a..57c343714 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c @@ -73,7 +73,7 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost) for (int ep = 0; ep < phost->device.CfgDesc.Itf_Desc[interface].bNumEndpoints; ++ep) { if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].bEndpointAddress & EP_IN) { MIDI_Handle->InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].bEndpointAddress; - MIDI_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].wMaxPacketSize; + MIDI_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].wMaxPacketSize & 0x03FFU; if (MIDI_Handle->InEpSize > USBH_MIDI_RX_BUF_SIZE) { MIDI_Handle->InEpSize = USBH_MIDI_RX_BUF_SIZE; } @@ -85,7 +85,7 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost) (void)USBH_LL_SetToggle(phost, MIDI_Handle->InPipe, 0U); } else { MIDI_Handle->OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].bEndpointAddress; - MIDI_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].wMaxPacketSize; + MIDI_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].wMaxPacketSize & 0x03FFU; /* Allocate and open output pipe */ MIDI_Handle->OutPipe = USBH_AllocPipe(phost, MIDI_Handle->OutEp); USBH_OpenPipe(phost, MIDI_Handle->OutPipe, MIDI_Handle->OutEp, @@ -141,6 +141,7 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceDeInit(USBH_HandleTypeDef *phost) static USBH_StatusTypeDef USBH_MIDI_ClassRequest(USBH_HandleTypeDef *phost) { phost->pUser(phost, HOST_CLASS_REQUEST); + USBH_UsrLog("Speed=%d", USBH_LL_GetSpeed(phost)); return USBH_OK; } @@ -168,7 +169,7 @@ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) hMidi->state = MIDI_RX; break; case MIDI_RX: - error = USBH_BulkReceiveData(phost, hMidi->rxBuffer, USBH_MIDI_RX_BUF_SIZE, hMidi->InPipe); + error = USBH_BulkReceiveData(phost, hMidi->rxBuffer, hMidi->InEpSize, hMidi->InPipe); if (error == USBH_OK) { hMidi->state = MIDI_RX_POLL; } else { @@ -192,11 +193,7 @@ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) break; case MIDI_FAIL: error = USBH_ClrFeature(phost, hMidi->ep_addr); - if (error == USBH_OK) { - hMidi->state = MIDI_IDLE; - } else { - USBH_UsrLog("MIDI_FAIL Could not clear"); - } + hMidi->state = MIDI_IDLE; break; } return error; From f7e88efa136ccd01dd73d49c501d58de088b3896 Mon Sep 17 00:00:00 2001 From: Greg Burns Date: Sun, 18 Feb 2024 14:14:38 -0800 Subject: [PATCH 08/16] ClrFeature is not appropriate Signed-off-by: Greg Burns --- .../ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c | 7 +------ examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp | 4 +--- src/hid/midi.h | 1 + src/usbh/usbh_conf.h | 2 +- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c index 57c343714..0660a6df5 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c @@ -61,13 +61,10 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost) USBH_DbgLog("Cannot find interface for %s class.", phost->pActiveClass->Name); return USBH_FAIL; } - -#if 1 status = USBH_SelectInterface(phost, interface); if (status != USBH_OK) { return USBH_FAIL; } -#endif /* Find the endpoints */ for (int ep = 0; ep < phost->device.CfgDesc.Itf_Desc[interface].bNumEndpoints; ++ep) { @@ -99,7 +96,6 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost) MIDI_Handle->state = MIDI_INIT; MIDI_Handle->error = MIDI_OK; - return USBH_OK; } @@ -192,7 +188,7 @@ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) } break; case MIDI_FAIL: - error = USBH_ClrFeature(phost, hMidi->ep_addr); + //error = USBH_ClrFeature(phost, hMidi->ep_addr); hMidi->state = MIDI_IDLE; break; } @@ -232,7 +228,6 @@ MIDI_ErrorTypeDef USBH_MIDI_Transmit(USBH_HandleTypeDef *phost, uint8_t* data, s { if(txStatus == USBH_URB_ERROR || txStatus == USBH_URB_STALL) { - USBH_ClrFeature(phost, hMidi->ep_addr); return MIDI_ERROR; } if(numUrbs == 0) diff --git a/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp b/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp index 9edaf33ee..60d5e5cad 100644 --- a/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp +++ b/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp @@ -59,8 +59,6 @@ void USBH_ClassActive(void* data) MidiUsbHandler::Config midi_config; midi_config.transport_config.periph = MidiUsbTransport::Config::Periph::HOST; midi.Init(midi_config); - uint8_t reset = 0xFF; - midi.SendMessage(&reset, sizeof(reset)); midi.StartReceive(); } } @@ -113,7 +111,7 @@ int main(void) /** Run USB host process */ usbHost.Process(); - if(usbHost.IsActiveClass(USBH_MIDI_CLASS)) + if(usbHost.IsActiveClass(USBH_MIDI_CLASS) && midi.RxActive()) { /** Process MIDI in the background */ midi.Listen(); diff --git a/src/hid/midi.h b/src/hid/midi.h index 0ff823736..b212b3b3a 100644 --- a/src/hid/midi.h +++ b/src/hid/midi.h @@ -196,6 +196,7 @@ class MidiHandler */ bool HasEvents() const { return event_q_.GetNumElements() > 0; } + bool RxActive() { return transport_.RxActive(); } /** Pops the oldest unhandled MidiEvent from the internal queue \return The event to be handled diff --git a/src/usbh/usbh_conf.h b/src/usbh/usbh_conf.h index f12b03d4d..5ed25bc12 100644 --- a/src/usbh/usbh_conf.h +++ b/src/usbh/usbh_conf.h @@ -85,7 +85,7 @@ extern "C" #define USBH_MAX_DATA_BUFFER 512U /*---------- -----------*/ -#define USBH_DEBUG_LEVEL 0U +#define USBH_DEBUG_LEVEL 3U /*---------- -----------*/ #define USBH_USE_OS 0U From 77f54ec90f1c1ad7895eb2bdcd50af5f8a6394b0 Mon Sep 17 00:00:00 2001 From: Greg Burns Date: Sun, 18 Feb 2024 14:34:43 -0800 Subject: [PATCH 09/16] Remove commented out function call Signed-off-by: Greg Burns --- Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c index 0660a6df5..24ae09778 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c @@ -188,7 +188,6 @@ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) } break; case MIDI_FAIL: - //error = USBH_ClrFeature(phost, hMidi->ep_addr); hMidi->state = MIDI_IDLE; break; } From 121610875e098b3e6e3cdc06920c777b18ee5e1b Mon Sep 17 00:00:00 2001 From: Greg Burns Date: Tue, 20 Feb 2024 12:46:22 -0800 Subject: [PATCH 10/16] Remove trailing spaces Signed-off-by: Greg Burns --- examples/MIDI_UART_Input/MIDI_UART_Input.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/MIDI_UART_Input/MIDI_UART_Input.cpp b/examples/MIDI_UART_Input/MIDI_UART_Input.cpp index 8df73077d..53b6acd7f 100644 --- a/examples/MIDI_UART_Input/MIDI_UART_Input.cpp +++ b/examples/MIDI_UART_Input/MIDI_UART_Input.cpp @@ -1,10 +1,10 @@ /** Example of setting reading MIDI Input via UART - * - * + * + * * This can be used with any 5-pin DIN or TRS connector that has been wired up * to one of the UART Rx pins on Daisy. * This will use D14 as the UART 1 Rx pin - * + * * This example will also log incoming messages to the serial port for general MIDI troubleshooting */ #include "daisy_seed.h" @@ -14,7 +14,7 @@ using namespace daisy; /** Fills string with string representation of MidiEvent::Type * str needs to be at least 16 bytes long to store the data - * TODO: Move this into MIDI lib or something + * TODO: Move this into MIDI lib or something */ void GetMidiTypeAsString(MidiEvent& msg, char* str) { @@ -69,7 +69,7 @@ int main(void) { MidiEvent msg = midi.PopEvent(); - /** Handle messages as they come in + /** Handle messages as they come in * See DaisyExamples for some examples of this */ switch(msg.type) @@ -112,4 +112,4 @@ int main(void) } } } -} \ No newline at end of file +} From 89d393eacff6fc7380ebb1940ea06739759cb668 Mon Sep 17 00:00:00 2001 From: Greg Burns Date: Wed, 21 Feb 2024 11:04:51 -0800 Subject: [PATCH 11/16] Fix formatting Signed-off-by: Greg Burns --- src/dev/mcp23x17.h | 136 +++++++++++++++++++++---------------------- src/hid/usb_host.cpp | 78 ++++++++++++------------- src/hid/usb_midi.cpp | 14 +++-- src/hid/usb_midi.h | 1 - src/usbh/usbh_conf.h | 20 +++---- 5 files changed, 122 insertions(+), 127 deletions(-) diff --git a/src/dev/mcp23x17.h b/src/dev/mcp23x17.h index 135ada61d..e9f902da5 100644 --- a/src/dev/mcp23x17.h +++ b/src/dev/mcp23x17.h @@ -3,8 +3,6 @@ #include "per/gpio.h" #include "per/i2c.h" -#undef SetBit - namespace daisy { // Adapted from https://github.com/blemasle/arduino-mcp23017 @@ -168,13 +166,13 @@ class Mcp23X17 { transport.Init(config.transport_config); - //BANK = 0 : sequential register addresses - //MIRROR = 0 : use configureInterrupt - //SEQOP = 1 : sequential operation disabled, address pointer does not increment - //DISSLW = 0 : slew rate enabled - //HAEN = 0 : hardware address pin is always enabled on 23017 - //ODR = 0 : open drain output - //INTPOL = 0 : interrupt active low + //BANK = 0 : sequential register addresses + //MIRROR = 0 : use configureInterrupt + //SEQOP = 1 : sequential operation disabled, address pointer does not increment + //DISSLW = 0 : slew rate enabled + //HAEN = 0 : hardware address pin is always enabled on 23017 + //ODR = 0 : open drain output + //INTPOL = 0 : interrupt active low transport.WriteReg(MCPRegister::IOCON, 0b00100000); //enable all pull up resistors (will be effective for input pins only) @@ -182,14 +180,14 @@ class Mcp23X17 }; /** - * Controls the pins direction on a whole port at once. - * - * directions: 0 - output, 1 - input - * pullups: 0 - disabled, 1 - enabled - * inverted: 0 - false/normal, 1 - true/inverted - * - * See "3.5.1 I/O Direction register". - */ + * Controls the pins direction on a whole port at once. + * + * directions: 0 - output, 1 - input + * pullups: 0 - disabled, 1 - enabled + * inverted: 0 - false/normal, 1 - true/inverted + * + * See "3.5.1 I/O Direction register". + */ void PortMode(MCPPort port, uint8_t directions, uint8_t pullups = 0xFF, @@ -201,14 +199,14 @@ class Mcp23X17 } /** - * Controls a single pin direction. - * Pin 0-7 for port A, 8-15 fo port B. - * - * 1 = Pin is configured as an input. - * 0 = Pin is configured as an output. - * - * See "3.5.1 I/O Direction register". - */ + * Controls a single pin direction. + * Pin 0-7 for port A, 8-15 fo port B. + * + * 1 = Pin is configured as an input. + * 0 = Pin is configured as an output. + * + * See "3.5.1 I/O Direction register". + */ void PinMode(uint8_t pin, MCPMode mode, bool inverted) { MCPRegister iodirreg = MCPRegister::IODIR_A; @@ -243,14 +241,14 @@ class Mcp23X17 } /** - * Writes a single pin state. - * Pin 0-7 for port A, 8-15 for port B. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". - */ + * Writes a single pin state. + * Pin 0-7 for port A, 8-15 for port B. + * + * 1 = Logic-high + * 0 = Logic-low + * + * See "3.5.10 Port register". + */ void WritePin(uint8_t pin, uint8_t state) { MCPRegister gpioreg = MCPRegister::GPIO_A; @@ -275,14 +273,14 @@ class Mcp23X17 } /** - * Reads a single pin state. - * Pin 0-7 for port A, 8-15 for port B. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". - */ + * Reads a single pin state. + * Pin 0-7 for port A, 8-15 for port B. + * + * 1 = Logic-high + * 0 = Logic-low + * + * See "3.5.10 Port register". + */ uint8_t ReadPin(uint8_t pin) { MCPRegister gpioreg = MCPRegister::GPIO_A; @@ -303,39 +301,39 @@ class Mcp23X17 } /** - * Writes pins state to a whole port. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". - */ + * Writes pins state to a whole port. + * + * 1 = Logic-high + * 0 = Logic-low + * + * See "3.5.10 Port register". + */ void WritePort(MCPPort port, uint8_t value) { transport.WriteReg(MCPRegister::GPIO_A + port, value); } /** - * Reads pins state for a whole port. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". - */ + * Reads pins state for a whole port. + * + * 1 = Logic-high + * 0 = Logic-low + * + * See "3.5.10 Port register". + */ uint8_t ReadPort(MCPPort port) { return transport.ReadReg(MCPRegister::GPIO_A + port); } /** - * Writes pins state to both ports. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". - */ + * Writes pins state to both ports. + * + * 1 = Logic-high + * 0 = Logic-low + * + * See "3.5.10 Port register". + */ void Write(uint16_t value) { transport.WriteReg( @@ -343,13 +341,13 @@ class Mcp23X17 } /** - * Reads pins state for both ports. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". - */ + * Reads pins state for both ports. + * + * 1 = Logic-high + * 0 = Logic-low + * + * See "3.5.10 Port register". + */ uint16_t Read() { uint8_t a = ReadPort(MCPPort::A); diff --git a/src/hid/usb_host.cpp b/src/hid/usb_host.cpp index 3654bd849..d4a31426b 100644 --- a/src/hid/usb_host.cpp +++ b/src/hid/usb_host.cpp @@ -26,52 +26,51 @@ ApplicationTypeDef Appli_state = APPLICATION_IDLE; class USBHostHandle::Impl { - public: - Impl() { - memset(&hUsbHostHS, 0, sizeof(hUsbHostHS)); - } - ~Impl() {} + public: + Impl() { memset(&hUsbHostHS, 0, sizeof(hUsbHostHS)); } + ~Impl() {} - Result RegisterClass(USBH_ClassTypeDef* pClass); - Result Init(USBHostHandle::Config& config); - Result Deinit(); - Result Reinit(); - Result Process(); - Result ReEnumerate(); + Result RegisterClass(USBH_ClassTypeDef* pClass); + Result Init(USBHostHandle::Config& config); + Result Deinit(); + Result Reinit(); + Result Process(); + Result ReEnumerate(); - bool GetReady(); + bool GetReady(); - inline Config& GetConfig() { return config_; } + inline Config& GetConfig() { return config_; } - private: - Config config_; + private: + Config config_; - /** @brief Maps ST Middleware USBH_StatusTypeDef to USBHostHandle::Result codes */ - Result ConvertStatus(USBH_StatusTypeDef sta) + /** @brief Maps ST Middleware USBH_StatusTypeDef to USBHostHandle::Result codes */ + Result ConvertStatus(USBH_StatusTypeDef sta) + { + if(sta != USBH_OK) { - if(sta != USBH_OK) - { - return Result::FAIL; - } - switch(sta) - { - case USBH_OK: return Result::OK; - case USBH_BUSY: return Result::BUSY; - case USBH_NOT_SUPPORTED: return Result::NOT_SUPPORTED; - case USBH_UNRECOVERED_ERROR: return Result::UNRECOVERED_ERROR; - case USBH_ERROR_SPEED_UNKNOWN: return Result::ERROR_SPEED_UNKNOWN; - case USBH_FAIL: - default: return Result::FAIL; - } + return Result::FAIL; } + switch(sta) + { + case USBH_OK: return Result::OK; + case USBH_BUSY: return Result::BUSY; + case USBH_NOT_SUPPORTED: return Result::NOT_SUPPORTED; + case USBH_UNRECOVERED_ERROR: return Result::UNRECOVERED_ERROR; + case USBH_ERROR_SPEED_UNKNOWN: return Result::ERROR_SPEED_UNKNOWN; + case USBH_FAIL: + default: return Result::FAIL; + } + } }; // Global handle static USBHostHandle::Impl usbh_impl; -static void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id); +static void USBH_UserProcess(USBH_HandleTypeDef* phost, uint8_t id); -USBHostHandle::Result USBHostHandle::Impl::RegisterClass(USBH_ClassTypeDef* pClass) +USBHostHandle::Result +USBHostHandle::Impl::RegisterClass(USBH_ClassTypeDef* pClass) { return ConvertStatus(USBH_RegisterClass(&hUsbHostHS, pClass)); } @@ -174,13 +173,12 @@ bool USBHostHandle::GetPresent() // Shared USB IRQ Handlers are located in sys/System.cpps // This isn't super useful for our typical code structure -static void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id) +static void USBH_UserProcess(USBH_HandleTypeDef* phost, uint8_t id) { - auto &conf = usbh_impl.GetConfig(); + auto& conf = usbh_impl.GetConfig(); switch(id) { - case HOST_USER_SELECT_CONFIGURATION: - break; + case HOST_USER_SELECT_CONFIGURATION: break; case HOST_USER_CLASS_ACTIVE: Appli_state = APPLICATION_READY; if(conf.class_active_callback) @@ -189,8 +187,7 @@ static void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id) cb(conf.userdata); } break; - case HOST_USER_CLASS_SELECTED: - break; + case HOST_USER_CLASS_SELECTED: break; case HOST_USER_CONNECTION: Appli_state = APPLICATION_START; if(conf.connect_callback) @@ -214,7 +211,6 @@ static void USBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id) cb(conf.userdata); } break; - default: - break; + default: break; } } diff --git a/src/hid/usb_midi.cpp b/src/hid/usb_midi.cpp index cb44a6cd1..539d0ff56 100644 --- a/src/hid/usb_midi.cpp +++ b/src/hid/usb_midi.cpp @@ -4,7 +4,8 @@ #include "hid/usb_midi.h" #include -extern "C" { +extern "C" +{ extern USBH_HandleTypeDef hUsbHostHS; } @@ -102,7 +103,7 @@ void MidiUsbTransport::Impl::Init(Config config) */ // static_assert(1u == sizeof(MidiUsbTransport::Impl::usb_handle_), "UsbHandle is not static"); - config_ = config; + config_ = config; rx_active_ = false; if(config_.periph == Config::HOST) @@ -128,8 +129,8 @@ void MidiUsbTransport::Impl::Init(Config config) void MidiUsbTransport::Impl::Tx(uint8_t* buffer, size_t size) { - int attempt_count = config_.tx_retry_count; - bool should_retry; + int attempt_count = config_.tx_retry_count; + bool should_retry; MidiToUsb(buffer, size); do @@ -137,7 +138,7 @@ void MidiUsbTransport::Impl::Tx(uint8_t* buffer, size_t size) if(config_.periph == Config::HOST) { MIDI_ErrorTypeDef result; - result = USBH_MIDI_Transmit(pUSB_Host, tx_buffer_, tx_ptr_); + result = USBH_MIDI_Transmit(pUSB_Host, tx_buffer_, tx_ptr_); should_retry = (result == MIDI_BUSY) && attempt_count--; } else @@ -147,7 +148,8 @@ void MidiUsbTransport::Impl::Tx(uint8_t* buffer, size_t size) result = usb_handle_.TransmitExternal(tx_buffer_, tx_ptr_); else result = usb_handle_.TransmitInternal(tx_buffer_, tx_ptr_); - should_retry = (result == UsbHandle::Result::ERR) && attempt_count--; + should_retry + = (result == UsbHandle::Result::ERR) && attempt_count--; } diff --git a/src/hid/usb_midi.h b/src/hid/usb_midi.h index c264b3b64..900d5afcd 100644 --- a/src/hid/usb_midi.h +++ b/src/hid/usb_midi.h @@ -3,7 +3,6 @@ #define __DSY_MIDIUSBTRANSPORT_H__ #include "hid/usb.h" -#include "hid/usb_host.h" #include "sys/system.h" #include "util/ringbuffer.h" diff --git a/src/usbh/usbh_conf.h b/src/usbh/usbh_conf.h index 5ed25bc12..e2c4151ac 100644 --- a/src/usbh/usbh_conf.h +++ b/src/usbh/usbh_conf.h @@ -127,10 +127,10 @@ extern "C" /* DEBUG macros */ #if(USBH_DEBUG_LEVEL > 0U) -extern void USBH_LogPrint(const char* format, ...); -#define USBH_UsrLog(...) \ - do \ - { \ + extern void USBH_LogPrint(const char* format, ...); +#define USBH_UsrLog(...) \ + do \ + { \ USBH_LogPrint(__VA_ARGS__); \ USBH_LogPrint("\n"); \ } while(0) @@ -143,9 +143,9 @@ extern void USBH_LogPrint(const char* format, ...); #if(USBH_DEBUG_LEVEL > 1U) -#define USBH_ErrLog(...) \ - do \ - { \ +#define USBH_ErrLog(...) \ + do \ + { \ USBH_LogPrint("ERROR: "); \ USBH_LogPrint(__VA_ARGS__); \ USBH_LogPrint("\n"); \ @@ -158,9 +158,9 @@ extern void USBH_LogPrint(const char* format, ...); #endif #if(USBH_DEBUG_LEVEL > 2U) -#define USBH_DbgLog(...) \ - do \ - { \ +#define USBH_DbgLog(...) \ + do \ + { \ USBH_LogPrint("DEBUG : "); \ USBH_LogPrint(__VA_ARGS__); \ USBH_LogPrint("\n"); \ From d7a4dd91607e51721f11746902048519b54711a0 Mon Sep 17 00:00:00 2001 From: Greg Burns Date: Wed, 21 Feb 2024 11:08:55 -0800 Subject: [PATCH 12/16] Restore change Signed-off-by: Greg Burns --- src/dev/mcp23x17.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dev/mcp23x17.h b/src/dev/mcp23x17.h index e9f902da5..f4229fb66 100644 --- a/src/dev/mcp23x17.h +++ b/src/dev/mcp23x17.h @@ -3,6 +3,9 @@ #include "per/gpio.h" #include "per/i2c.h" +// This get defined in a public (ST) header file +#undef SetBit + namespace daisy { // Adapted from https://github.com/blemasle/arduino-mcp23017 From e547128e5ce40c39f4183962171a6043c7bc8ffa Mon Sep 17 00:00:00 2001 From: Greg Burns Date: Wed, 21 Feb 2024 11:14:24 -0800 Subject: [PATCH 13/16] Add missing include path for cmake Signed-off-by: Greg Burns --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 22b854cc1..4027cc39f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -208,6 +208,7 @@ target_include_directories(${TARGET} PUBLIC Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc Middlewares/ST/STM32_USB_Host_Library/Core/Inc Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Inc + Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc Middlewares/Third_Party/FatFs/src src src/sys From 81cdee41f0f9a9e37809c6f55af7d0439d63b754 Mon Sep 17 00:00:00 2001 From: Greg Burns Date: Wed, 21 Feb 2024 13:41:10 -0800 Subject: [PATCH 14/16] Remove unused field and disable debug output Signed-off-by: Greg Burns --- .../ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h | 1 - .../ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c | 3 ++- src/usbh/usbh_conf.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h index b0faae614..a76a8162e 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h @@ -55,7 +55,6 @@ typedef struct _MIDI_Process { uint8_t OutPipe; uint8_t OutEp; uint16_t OutEpSize; - uint8_t ep_addr; MIDI_StateTypeDef state; MIDI_ErrorTypeDef error; USBH_MIDI_RxCallback callback; diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c index 24ae09778..698150995 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c @@ -80,6 +80,7 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost) phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, MIDI_Handle->InEpSize); (void)USBH_LL_SetToggle(phost, MIDI_Handle->InPipe, 0U); + USBH_UsrLog("InEP[%d] %02x size=%u", ep, MIDI_Handle->InEp, MIDI_Handle->InEpSize); } else { MIDI_Handle->OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].bEndpointAddress; MIDI_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[ep].wMaxPacketSize & 0x03FFU; @@ -89,10 +90,10 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost) phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, MIDI_Handle->OutEpSize); (void)USBH_LL_SetToggle(phost, MIDI_Handle->OutPipe, 0U); + USBH_UsrLog("OutEP[%d] %02x size=%u", ep, MIDI_Handle->OutEp, MIDI_Handle->OutEpSize); } } - MIDI_Handle->ep_addr = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress; MIDI_Handle->state = MIDI_INIT; MIDI_Handle->error = MIDI_OK; diff --git a/src/usbh/usbh_conf.h b/src/usbh/usbh_conf.h index e2c4151ac..ab71b4387 100644 --- a/src/usbh/usbh_conf.h +++ b/src/usbh/usbh_conf.h @@ -85,7 +85,7 @@ extern "C" #define USBH_MAX_DATA_BUFFER 512U /*---------- -----------*/ -#define USBH_DEBUG_LEVEL 3U +#define USBH_DEBUG_LEVEL 0U /*---------- -----------*/ #define USBH_USE_OS 0U From a2aca084ccae4bebe602b8b32f4e2568688b1e2a Mon Sep 17 00:00:00 2001 From: Greg Burns Date: Mon, 26 Feb 2024 13:21:04 -0800 Subject: [PATCH 15/16] Improve error handling and turn off dma DMA is currently very unreliable, it doesn't work at all with the Arturia Beatstep Pro. Turning it off for now to allow further testing. Signed-off-by: Greg Burns --- .../Class/MIDI/Inc/usbh_midi.h | 3 +- .../Class/MIDI/Src/usbh_midi.c | 33 +++++++++++-------- src/usbh/usbh_conf.c | 4 ++- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h index a76a8162e..22d7d0d10 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h @@ -34,7 +34,8 @@ typedef enum { MIDI_IDLE, MIDI_RX, MIDI_RX_POLL, - MIDI_FAIL + MIDI_RX_ERROR, + MIDI_FATAL_ERROR } MIDI_StateTypeDef; typedef enum { diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c index 698150995..8e5629169 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c @@ -138,7 +138,6 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceDeInit(USBH_HandleTypeDef *phost) static USBH_StatusTypeDef USBH_MIDI_ClassRequest(USBH_HandleTypeDef *phost) { phost->pUser(phost, HOST_CLASS_REQUEST); - USBH_UsrLog("Speed=%d", USBH_LL_GetSpeed(phost)); return USBH_OK; } @@ -166,31 +165,36 @@ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) hMidi->state = MIDI_RX; break; case MIDI_RX: - error = USBH_BulkReceiveData(phost, hMidi->rxBuffer, hMidi->InEpSize, hMidi->InPipe); - if (error == USBH_OK) { - hMidi->state = MIDI_RX_POLL; - } else { - USBH_UsrLog("BulkReceiveData->%d", error); - hMidi->state = MIDI_FAIL; - error = USBH_FAIL; - } + // Always returns USBH_OK, call USBH_LL_GetURBState() for status + USBH_BulkReceiveData(phost, hMidi->rxBuffer, hMidi->InEpSize, hMidi->InPipe); + hMidi->state = MIDI_RX_POLL; break; case MIDI_RX_POLL: rxStatus = USBH_LL_GetURBState(phost, hMidi->InPipe); - if (rxStatus == USBH_URB_DONE) { + if (rxStatus == USBH_URB_NOTREADY || rxStatus == USBH_URB_IDLE) { + hMidi->state = MIDI_RX_POLL; + } else if (rxStatus == USBH_URB_DONE) { size_t sz = USBH_LL_GetLastXferSize(phost, hMidi->InPipe); hMidi->state = MIDI_RX; if (hMidi->callback) { hMidi->callback(hMidi->rxBuffer, sz, hMidi->pUser); } - } else if (rxStatus == USBH_URB_ERROR || rxStatus == USBH_URB_STALL) { - hMidi->state = MIDI_FAIL; + } else { + hMidi->state = MIDI_RX_ERROR; error = USBH_FAIL; } break; - case MIDI_FAIL: - hMidi->state = MIDI_IDLE; + case MIDI_RX_ERROR: + error = USBH_ClrFeature(phost, hMidi->InEp); + if (error == USBH_FAIL) { + USBH_MIDI_InterfaceDeInit(phost); + hMidi->state = MIDI_FATAL_ERROR; + } else { + hMidi->state = MIDI_IDLE; + } break; + case MIDI_FATAL_ERROR: + return USBH_FAIL; } return error; } @@ -228,6 +232,7 @@ MIDI_ErrorTypeDef USBH_MIDI_Transmit(USBH_HandleTypeDef *phost, uint8_t* data, s { if(txStatus == USBH_URB_ERROR || txStatus == USBH_URB_STALL) { + USBH_ClrFeature(phost, hMidi->OutEp); return MIDI_ERROR; } if(numUrbs == 0) diff --git a/src/usbh/usbh_conf.c b/src/usbh/usbh_conf.c index a03a01eea..857217116 100644 --- a/src/usbh/usbh_conf.c +++ b/src/usbh/usbh_conf.c @@ -217,6 +217,8 @@ USBH_StatusTypeDef USBH_LL_Init(USBH_HandleTypeDef *phost) /* Init USB_IP */ if(phost->id == HOST_HS) { + memset(&hhcd_USB_OTG_HS, 0, sizeof(hhcd_USB_OTG_HS)); + /* Link the driver to the stack. */ hhcd_USB_OTG_HS.pData = phost; phost->pData = &hhcd_USB_OTG_HS; @@ -224,7 +226,7 @@ USBH_StatusTypeDef USBH_LL_Init(USBH_HandleTypeDef *phost) hhcd_USB_OTG_HS.Instance = USB_OTG_HS; hhcd_USB_OTG_HS.Init.Host_channels = 16; hhcd_USB_OTG_HS.Init.speed = HCD_SPEED_FULL; - hhcd_USB_OTG_HS.Init.dma_enable = ENABLE; + hhcd_USB_OTG_HS.Init.dma_enable = DISABLE; hhcd_USB_OTG_HS.Init.phy_itface = USB_OTG_EMBEDDED_PHY; hhcd_USB_OTG_HS.Init.Sof_enable = DISABLE; hhcd_USB_OTG_HS.Init.low_power_enable = DISABLE; From 811a64970e88eb74675513d5682765596430af34 Mon Sep 17 00:00:00 2001 From: Greg Burns Date: Tue, 5 Mar 2024 12:48:00 -0800 Subject: [PATCH 16/16] DMA now working Seems that the class startup was happening at the wrong point. It needs to happen when the lower stack calls the ClassRequest callback. This fix also eliminates the spurious Device Error callback. Signed-off-by: Greg Burns --- .../ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c | 3 +-- examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp | 2 +- src/usbh/usbh_conf.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c index 8e5629169..e678fc5ab 100644 --- a/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c +++ b/Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c @@ -137,7 +137,7 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceDeInit(USBH_HandleTypeDef *phost) */ static USBH_StatusTypeDef USBH_MIDI_ClassRequest(USBH_HandleTypeDef *phost) { - phost->pUser(phost, HOST_CLASS_REQUEST); + phost->pUser(phost, HOST_USER_CLASS_ACTIVE); return USBH_OK; } @@ -159,7 +159,6 @@ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost) switch (hMidi->state) { case MIDI_INIT: hMidi->state = MIDI_IDLE; - phost->pUser(phost, HOST_USER_CLASS_ACTIVE); break; case MIDI_IDLE: hMidi->state = MIDI_RX; diff --git a/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp b/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp index 60d5e5cad..a733a6c5c 100644 --- a/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp +++ b/examples/MIDI_USBH_Input/MIDI_USBH_Input.cpp @@ -73,7 +73,7 @@ int main(void) /** Initialize our hardware */ hw.Init(); - hw.StartLog(); + hw.StartLog(true); hw.PrintLine("MIDI USB Host start"); diff --git a/src/usbh/usbh_conf.c b/src/usbh/usbh_conf.c index 857217116..746909ea5 100644 --- a/src/usbh/usbh_conf.c +++ b/src/usbh/usbh_conf.c @@ -226,7 +226,7 @@ USBH_StatusTypeDef USBH_LL_Init(USBH_HandleTypeDef *phost) hhcd_USB_OTG_HS.Instance = USB_OTG_HS; hhcd_USB_OTG_HS.Init.Host_channels = 16; hhcd_USB_OTG_HS.Init.speed = HCD_SPEED_FULL; - hhcd_USB_OTG_HS.Init.dma_enable = DISABLE; + hhcd_USB_OTG_HS.Init.dma_enable = ENABLE; hhcd_USB_OTG_HS.Init.phy_itface = USB_OTG_EMBEDDED_PHY; hhcd_USB_OTG_HS.Init.Sof_enable = DISABLE; hhcd_USB_OTG_HS.Init.low_power_enable = DISABLE;