Skip to content

Commit

Permalink
Merge pull request #611 from GregBurns/midi_usbh
Browse files Browse the repository at this point in the history
MIDI USB Host support
  • Loading branch information
beserge authored Mar 7, 2024
2 parents fc4abb0 + 811a649 commit f7727ed
Show file tree
Hide file tree
Showing 18 changed files with 699 additions and 83 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ target_include_directories(${TARGET} PUBLIC
Middlewares/Patched/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
Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,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 \
Expand Down Expand Up @@ -297,7 +298,6 @@ C_DEFS = \
-DDATA_IN_D2_SRAM
# ^ added for easy startup access


C_INCLUDES = \
-I$(MODULE_DIR) \
-I$(MODULE_DIR)/sys \
Expand All @@ -311,6 +311,7 @@ C_INCLUDES = \
-IMiddlewares/Patched/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.
Expand Down
87 changes: 87 additions & 0 deletions Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Inc/usbh_midi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
******************************************************************************
* @file usbh_midi.h
* @author Greg Burns
* @author MCD Application Team
* @brief This file contains all the prototypes for the usbh_midi.c
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2015 STMicroelectronics.
* All rights reserved.</center></h2>
*
* 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_RX_POLL,
MIDI_RX_ERROR,
MIDI_FATAL_ERROR
} MIDI_StateTypeDef;

typedef enum {
MIDI_OK,
MIDI_BUSY,
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****/
251 changes: 251 additions & 0 deletions Middlewares/ST/STM32_USB_Host_Library/Class/MIDI/Src/usbh_midi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
/**
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2015 STMicroelectronics.
* All rights reserved.</center></h2>
*
* 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_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 interface for %s class.", phost->pActiveClass->Name);
return USBH_FAIL;
}
status = USBH_SelectInterface(phost, interface);
if (status != USBH_OK) {
return USBH_FAIL;
}

/* Find the endpoints */
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 & 0x03FFU;
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);
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;
/* 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);
USBH_UsrLog("OutEP[%d] %02x size=%u", ep, MIDI_Handle->OutEp, MIDI_Handle->OutEpSize);
}
}

MIDI_Handle->state = MIDI_INIT;
MIDI_Handle->error = MIDI_OK;

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)
{
USBH_UsrLog(__FUNCTION__);
MIDI_HandleTypeDef *MIDI_Handle = (MIDI_HandleTypeDef *) 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_INIT;
MIDI_Handle->error = MIDI_OK;
}
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)
{
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;

switch (hMidi->state) {
case MIDI_INIT:
hMidi->state = MIDI_IDLE;
break;
case MIDI_IDLE:
hMidi->state = MIDI_RX;
break;
case MIDI_RX:
// 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_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 {
hMidi->state = MIDI_RX_ERROR;
error = USBH_FAIL;
}
break;
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;
}

/**
* @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)
{
USBH_UsrLog(__FUNCTION__);
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;
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->OutEp);
return MIDI_ERROR;
}
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;
}

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
1 change: 1 addition & 0 deletions Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
4 changes: 4 additions & 0 deletions Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_pipes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions core/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit f7727ed

Please sign in to comment.