Skip to content

Commit

Permalink
Added MidiHost class, major refactor.
Browse files Browse the repository at this point in the history
MidiHost owns and manages;
- USBH_Handle (usbhost/phost), and its state change callback
- MidiStreamingHandle
- USBH_ClassTypeDef (operations and pData ptr to MidiStreamingHandle)

It also sets up the OTG interrupt.
It provides wrappers for Midi Host functions (start/stop/rx/tx)

It's not 100% there yet, but close to supporting multiple MidiHosts (i.e. on different USB ports)
  • Loading branch information
danngreen committed Nov 13, 2022
1 parent e456684 commit f438c7e
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 113 deletions.
71 changes: 15 additions & 56 deletions examples/usb_midi_audio_host/main.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include "drivers/interrupt.hh"
#include "drivers/interrupt_control.hh"
#include "drivers/leds.hh"
#include "drivers/uart.hh"
#include "midi_host.hh"
#include "stm32mp1xx.h"
#include "system_clk.hh"
#include "usbh_core.h"
Expand All @@ -15,9 +14,6 @@
namespace Board = OSD32BRK;
// namespace Board = STM32MP1Disco;

// defined in usbh_conf.c
extern HCD_HandleTypeDef hhcd;

static void usbh_state_change_callback(USBH_HandleTypeDef *phost, uint8_t id);

void main()
Expand All @@ -31,29 +27,30 @@ void main()

SystemClocks::init();

USBH_HandleTypeDef usbhost;
MidiHost midi_host;

auto init_ok = USBH_Init(&usbhost, usbh_state_change_callback, 0);
if (init_ok != USBH_OK) {
printf("USB Host failed to initialize! Error code: %d\n", static_cast<uint32_t>(init_ok));
if (!midi_host.init()) {
printf("USB Host failed to initialize!\r\n");
}
InterruptControl::disable_irq(OTG_IRQn);
InterruptManager::registerISR(OTG_IRQn, [] { HAL_HCD_IRQHandler(&hhcd); });
InterruptControl::set_irq_priority(OTG_IRQn, 0, 0);
InterruptControl::enable_irq(OTG_IRQn);

USBH_RegisterClass(&usbhost, USBH_MIDI_CLASS);
auto start_ok = USBH_Start(&usbhost);
if (start_ok != USBH_OK) {
printf("USB Host failed to start! Error code: %d\n", static_cast<uint32_t>(start_ok));
midi_host.set_rx_callback([&](uint8_t *buf, uint32_t sz) {
printf("RX %d bytes: ", sz);
if (sz >= 4)
printf("0x%x 0x%x 0x%x 0x%x\n", buf[0], buf[1], buf[2], buf[3]);

midi_host.receive();
});

if (!midi_host.start()) {
printf("MIDI Host failed to start!\r\n");
}

// Blink green1 light at 1Hz
uint32_t last_tm = 0;
bool led_state = false;
while (1) {

USBH_Process(&usbhost);
midi_host.process();

uint32_t tm = HAL_GetTick();
if (tm > (last_tm + 500)) {
Expand All @@ -68,44 +65,6 @@ void main()
}
}

uint8_t rx_buffer[128];
void usbh_state_change_callback(USBH_HandleTypeDef *phost, uint8_t id)
{
switch (id) {
case HOST_USER_SELECT_CONFIGURATION:
printf("Select config\n");
break;

case HOST_USER_CONNECTION:
printf("Connected\n");
break;

case HOST_USER_CLASS_SELECTED:
printf("Class selected\n");
break;

case HOST_USER_CLASS_ACTIVE:
printf("Class active\n");
USBH_MIDI_Receive(phost, rx_buffer, 128);
break;

case HOST_USER_DISCONNECTION:
printf("Disconnected\n");
break;

case HOST_USER_UNRECOVERED_ERROR:
printf("Error\n");
break;
}
}

void USBH_MIDI_ReceiveCallback(USBH_HandleTypeDef *phost)
{
auto bytes_rx = USBH_MIDI_GetLastReceivedDataSize(phost);
printf("RX %d bytes: 0x%x 0x%x 0x%x 0x%x\n", bytes_rx, rx_buffer[0], rx_buffer[1], rx_buffer[2], rx_buffer[3]);
USBH_MIDI_Receive(phost, rx_buffer, 128);
}

// required for printf()
extern "C" int __io_putchar(int ch)
{
Expand Down
83 changes: 83 additions & 0 deletions examples/usb_midi_audio_host/midi_host.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#pragma once
#include "drivers/interrupt.hh"
#include "drivers/interrupt_control.hh"
#include "usbh_midi.hh"

class MidiHost {
public:
static inline uint8_t rx_buffer[128];

MidiStreamingHandle MSHandle;
USBH_HandleTypeDef usbhost;

USBH_ClassTypeDef midi_class_ops = {
"MIDI",
AudioClassCode,
USBH_MIDI_InterfaceInit,
USBH_MIDI_InterfaceDeInit,
USBH_MIDI_ClassRequest,
USBH_MIDI_Process,
USBH_MIDI_SOFProcess,
&MSHandle,
};

MidiHost() = default;

void set_rx_callback(MidiStreamRxCallbackType rx_callback) { MSHandle.rx_callback = rx_callback; }
void set_tx_callback(MidiStreamTxCallbackType tx_callback) { MSHandle.tx_callback = tx_callback; }

bool init()
{
auto status = USBH_Init(&usbhost, usbh_state_change_callback, 0);
if (status != USBH_OK)
return false;

// defined in usbh_conf.c
extern HCD_HandleTypeDef hhcd;
InterruptControl::disable_irq(OTG_IRQn);
InterruptManager::registerISR(OTG_IRQn, [] { HAL_HCD_IRQHandler(&hhcd); });
InterruptControl::set_irq_priority(OTG_IRQn, 0, 0);
InterruptControl::enable_irq(OTG_IRQn);

USBH_RegisterClass(&usbhost, &midi_class_ops);

return true;
}

bool start() { return USBH_Start(&usbhost) == USBH_OK; }
bool stop() { return USBH_Stop(&usbhost) == USBH_OK; }
void process() { USBH_Process(&usbhost); }
USBH_StatusTypeDef receive() { return USBH_MIDI_Receive(&usbhost, rx_buffer, 128); }
USBH_StatusTypeDef transmit(uint8_t *buff, uint32_t len) { return USBH_MIDI_Transmit(&usbhost, buff, len); }

static void usbh_state_change_callback(USBH_HandleTypeDef *phost, uint8_t id)
{
switch (id) {
case HOST_USER_SELECT_CONFIGURATION:
printf("Select config\n");
break;

case HOST_USER_CONNECTION:
printf("Connected\n");
break;

case HOST_USER_CLASS_SELECTED:
printf("Class selected\n");
break;

case HOST_USER_CLASS_ACTIVE:
printf("Class active\n");
// TODO: Move rx_buffer to class handle, to support multiple instances
USBH_MIDI_Receive(phost, rx_buffer, 128);
break;

case HOST_USER_DISCONNECTION:
printf("Disconnected\n");
break;

case HOST_USER_UNRECOVERED_ERROR:
printf("Error\n");
break;
}
}
};
72 changes: 19 additions & 53 deletions examples/usb_midi_audio_host/usbh_midi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,45 +38,21 @@

#include "usbh_midi.hh"

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_SOFProcess(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_MIDI_ClassRequest(USBH_HandleTypeDef *phost);

static void MIDI_ProcessTransmission(USBH_HandleTypeDef *phost);
static void MIDI_ProcessReception(USBH_HandleTypeDef *phost);

constexpr uint8_t AudioClassCode = 0x01;
constexpr uint8_t AudioControlSubclassCode = 0x01;
constexpr uint8_t MidiStreamingSubClass = 0x03;

constexpr uint8_t AnyProtocol = 0xFF;
constexpr uint8_t NoValidInterfaceFound = 0xFF;

USBH_ClassTypeDef MIDI_Class_Ops = {
"MIDI",
AudioClassCode,
USBH_MIDI_InterfaceInit,
USBH_MIDI_InterfaceDeInit,
USBH_MIDI_ClassRequest,
USBH_MIDI_Process,
USBH_MIDI_SOFProcess,
nullptr,
};

/**
* @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 USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef status;
uint8_t interface;

phost->pActiveClass->pData = new_usbh_handle<MidiStreamingHandle>();
// phost->pActiveClass->pData = new_usbh_handle<MidiStreamingHandle>();
if (phost->pActiveClass->pData == nullptr) {
USBH_DbgLog("Cannot allocate memory for CDC Handle");
return USBH_FAIL;
Expand Down Expand Up @@ -134,7 +110,7 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost)
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_MIDI_InterfaceDeInit(USBH_HandleTypeDef *phost)
USBH_StatusTypeDef USBH_MIDI_InterfaceDeInit(USBH_HandleTypeDef *phost)
{
USBHostHandle host{phost};
auto MSHandle = host.get_class_handle<MidiStreamingHandle>();
Expand All @@ -145,8 +121,8 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceDeInit(USBH_HandleTypeDef *phost)
host.close_and_free_pipe(MSHandle->DataItf.InEP);
host.close_and_free_pipe(MSHandle->DataItf.OutEP);

USBH_free(phost->pActiveClass->pData);
phost->pActiveClass->pData = nullptr;
// USBH_free(phost->pActiveClass->pData);
// phost->pActiveClass->pData = nullptr;

return USBH_OK;
}
Expand All @@ -158,7 +134,7 @@ static USBH_StatusTypeDef USBH_MIDI_InterfaceDeInit(USBH_HandleTypeDef *phost)
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_MIDI_ClassRequest(USBH_HandleTypeDef *phost)
USBH_StatusTypeDef USBH_MIDI_ClassRequest(USBH_HandleTypeDef *phost)
{
if (phost->pUser)
phost->pUser(phost, HOST_USER_CLASS_ACTIVE);
Expand All @@ -172,7 +148,7 @@ static USBH_StatusTypeDef USBH_MIDI_ClassRequest(USBH_HandleTypeDef *phost)
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost)
USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef status = USBH_BUSY;

Expand Down Expand Up @@ -209,7 +185,7 @@ static USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost)
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_MIDI_SOFProcess(USBH_HandleTypeDef *phost)
USBH_StatusTypeDef USBH_MIDI_SOFProcess(USBH_HandleTypeDef *phost)
{
UNUSED(phost);
return USBH_OK;
Expand Down Expand Up @@ -437,24 +413,14 @@ static void MIDI_ProcessReception(USBH_HandleTypeDef *phost)
}
}

/**
* @brief The function informs user that data have been received
* @param pdev: Selected device
* @retval None
*/
__weak void USBH_MIDI_TransmitCallback(USBH_HandleTypeDef *phost)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(phost);
}

/**
* @brief The function informs user that data have been sent
* @param pdev: Selected device
* @retval None
*/
__weak void USBH_MIDI_ReceiveCallback(USBH_HandleTypeDef *phost)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(phost);
}
// Not used, but kept here in to more easily add this driver to a C project
USBH_ClassTypeDef MIDI_Class_Ops = {
"MIDI",
AudioClassCode,
USBH_MIDI_InterfaceInit,
USBH_MIDI_InterfaceDeInit,
USBH_MIDI_ClassRequest,
USBH_MIDI_Process,
USBH_MIDI_SOFProcess,
nullptr,
};
17 changes: 13 additions & 4 deletions examples/usb_midi_audio_host/usbh_midi.hh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
#include "usbh_core.h"
#include "usbh_host.hh"

constexpr uint8_t AudioClassCode = 0x01;
constexpr uint8_t AudioControlSubclassCode = 0x01;
constexpr uint8_t MidiStreamingSubClass = 0x03;

constexpr uint8_t AnyProtocol = 0xFF;
constexpr uint8_t NoValidInterfaceFound = 0xFF;


struct MidiInterfaceHeaderDesc {
uint8_t bLength; // Size of this descriptor = 7
uint8_t bDescriptorType; // CS_INTERFACE (0x24)
Expand Down Expand Up @@ -113,12 +121,13 @@ struct MidiStreamingHandle {
extern USBH_ClassTypeDef MIDI_Class_Ops;
#define USBH_MIDI_CLASS &MIDI_Class_Ops

USBH_StatusTypeDef USBH_MIDI_InterfaceInit(USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_MIDI_InterfaceDeInit(USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_MIDI_Process(USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_MIDI_SOFProcess(USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_MIDI_ClassRequest(USBH_HandleTypeDef *phost);

USBH_StatusTypeDef USBH_MIDI_Transmit(USBH_HandleTypeDef *phost, uint8_t *pbuff, uint32_t length);
USBH_StatusTypeDef USBH_MIDI_Receive(USBH_HandleTypeDef *phost, uint8_t *pbuff, uint32_t length);
uint16_t USBH_MIDI_GetLastReceivedDataSize(USBH_HandleTypeDef *phost);
USBH_StatusTypeDef USBH_MIDI_Stop(USBH_HandleTypeDef *phost);
void USBH_MIDI_TransmitCallback(USBH_HandleTypeDef *phost);
void USBH_MIDI_ReceiveCallback(USBH_HandleTypeDef *phost);

#endif /* __USBH_CDC_H */

0 comments on commit f438c7e

Please sign in to comment.