Skip to content

Commit

Permalink
Initial commit for CM108 style HID endpoint PTT support
Browse files Browse the repository at this point in the history
  • Loading branch information
skuep committed Feb 23, 2023
1 parent ae24f73 commit 6e77ea2
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 30 deletions.
6 changes: 5 additions & 1 deletion stm32/aioc-fw/Inc/tusb_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
//------------- CLASS -------------//
#define CFG_TUD_AUDIO 1
#define CFG_TUD_CDC 1
#define CFG_TUD_HID 1

// CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE 128
Expand All @@ -105,6 +106,9 @@
// CDC Endpoint transfer buffer size, more is faster
#define CFG_TUD_CDC_EP_BUFSIZE 64

// HID buffer size
#define CFG_TUD_HID_EP_BUFSIZE 8

//--------------------------------------------------------------------
// AUDIO CLASS DRIVER CONFIGURATION
//--------------------------------------------------------------------
Expand All @@ -115,7 +119,7 @@
#define CFG_TUD_AUDIO_ENABLE_EP_OUT 1
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 1

#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_IO_DESC_LEN
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN AIOC_AUDIO_DESC_LEN
#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE 2
Expand Down
3 changes: 3 additions & 0 deletions stm32/aioc-fw/Src/main.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "stm32f3xx_hal.h"
#include "aioc.h"
#include "led.h"
#include "ptt.h"
#include "usb.h"
#include <assert.h>
#include <stdio.h>
Expand Down Expand Up @@ -91,6 +92,8 @@ int main(void)
LED_MODE(0, LED_MODE_SLOWPULSE2X);
LED_MODE(1, LED_MODE_SLOWPULSE2X);

PTT_Init();

USB_Init();

uint32_t i = 0;
Expand Down
10 changes: 8 additions & 2 deletions stm32/aioc-fw/Src/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "tusb.h"
#include "usb_serial.h"
#include "usb_audio.h"
#include "usb_hid.h"

// We have ISOCHRONOUS endpoints defined that share the same endpoint number, but have opposing directions.
// However with STM32 hardware, ISOCHRONOUS endpoints use both RX and TX structures of the same endpoint register in hardware
Expand All @@ -26,12 +27,16 @@ uint8_t tu_stm32_edpt_number_cb(uint8_t addr)
case EPNUM_AUDIO_FB:
return 0x03;

case EPNUM_HID_IN:
case EPNUM_HID_OUT:
return 0x04;

case EPNUM_CDC_0_OUT:
case EPNUM_CDC_0_IN:
return 0x04;
return 0x05;

case EPNUM_CDC_0_NOTIF:
return 0x05;
return 0x06;

default:
TU_BREAKPOINT();
Expand Down Expand Up @@ -127,6 +132,7 @@ void USB_Init(void)
// Init classes
USB_SerialInit();
USB_AudioInit();
USB_HIDInit();

// Start USB Stack
tud_init(BOARD_TUD_RHPORT);
Expand Down
81 changes: 67 additions & 14 deletions stm32/aioc-fw/Src/usb_descriptors.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,50 @@ uint8_t const* tud_descriptor_device_cb(void) {
return (uint8_t const*) &desc_device;
}

//--------------------------------------------------------------------+
// HID Report Descriptor
//--------------------------------------------------------------------+

uint8_t const desc_hid_report[] = {
/* CM108 emulation */
HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ),
HID_USAGE ( HID_USAGE_CONSUMER_CONTROL ),
HID_COLLECTION ( HID_COLLECTION_APPLICATION ),
/* Input */
HID_USAGE ( 0x00 ),
HID_LOGICAL_MIN ( 0x00 ),
HID_LOGICAL_MAX_N ( 0xff, 2 ),
HID_REPORT_SIZE ( 8 ),
HID_REPORT_COUNT( 4 ),
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),
/* Output */
HID_USAGE ( 0x00 ),
HID_LOGICAL_MIN ( 0x00 ),
HID_LOGICAL_MAX_N ( 0xff, 2 ),
HID_REPORT_SIZE ( 8 ),
HID_REPORT_COUNT( 4 ),
HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),
HID_COLLECTION_END
};

// Invoked when received GET HID REPORT DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf)
{
(void) itf;
return desc_hid_report;
}

//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_IO_DESC_LEN)
#define CONFIG_TOTAL_LEN ( \
TUD_CONFIG_DESC_LEN + \
AIOC_AUDIO_DESC_LEN + \
AIOC_HID_DESC_LEN + \
AIOC_CDC_DESC_LEN \
)

uint8_t const desc_fs_configuration[] = {
// Config number, interface count, string index, total length, attribute, power in mA
Expand All @@ -68,26 +108,35 @@ uint8_t const desc_fs_configuration[] = {
/* _power_ma */ 100
),

TUD_CDC_DESCRIPTOR(
AIOC_AUDIO_DESCRIPTOR(
/* _itfnum */ ITF_NUM_AUDIO_CONTROL,
/* _stridx */ STR_IDX_AUDIOITF,
/* _nBytesPerSample */ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE,
/* _nBitsUsedPerSample */ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE*8,
/* _epin */ EPNUM_AUDIO_IN,
/* _epinsize */ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX,
/* _epout */ EPNUM_AUDIO_OUT,
/* _epoutsize */ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX,
/* _epfb */ EPNUM_AUDIO_FB
),
AIOC_HID_DESCRIPTOR(
/* _itfnum */ ITF_NUM_HID,
/* _stridx */ STR_IDX_HIDITF,
/* _boot_protocol */HID_ITF_PROTOCOL_NONE,
/*_report_desc_len*/sizeof(desc_hid_report),
/* _epin */ EPNUM_HID_IN,
/* _epsize */ CFG_TUD_HID_EP_BUFSIZE,
/* _ep_interval */ 0x20
),

AIOC_CDC_DESCRIPTOR(
/* _itfnum */ ITF_NUM_CDC_0,
/* _stridx */ STR_IDX_CDCITF,
/* _ep_notif */ EPNUM_CDC_0_NOTIF,
/* _ep_notif_size */ 8,
/* _epout */ EPNUM_CDC_0_OUT,
/* _epin */ EPNUM_CDC_0_IN,
/* _epsize */ CFG_TUD_CDC_EP_BUFSIZE
),

TUD_AUDIO_IO_DESCRIPTOR(
/*_itfnum*/ ITF_NUM_AUDIO_CONTROL,
/*_stridx*/ STR_IDX_AUDIOITF,
/*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE,
/*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE*8,
/*_epin*/ EPNUM_AUDIO_IN,
/*_epinsize*/ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX,
/*_epout*/ EPNUM_AUDIO_OUT,
/*_epoutsize*/ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX,
/*_epfb*/ EPNUM_AUDIO_FB
)
};

Expand Down Expand Up @@ -209,6 +258,10 @@ const uint16_t * tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
len = ascii_to_utf16(ptr, len, USB_STRING_AUDIOOUTCHAN);
break;

case STR_IDX_HIDITF:
len = ascii_to_utf16(ptr, len, USB_STRING_HIDITF);
break;

default:
TU_ASSERT(0, NULL);
break;
Expand Down
47 changes: 34 additions & 13 deletions stm32/aioc-fw/Src/usb_descriptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@

/* Interfaces */
enum USB_DESCRIPTORS_ITF {
ITF_NUM_CDC_0 = 0,
ITF_NUM_CDC_0_DATA,
ITF_NUM_AUDIO_CONTROL,
ITF_NUM_AUDIO_CONTROL = 0,
ITF_NUM_AUDIO_STREAMING_OUT,
ITF_NUM_AUDIO_STREAMING_IN,
ITF_NUM_HID, /* For CM108 compatibility make this interface #3 */
ITF_NUM_CDC_0,
ITF_NUM_CDC_0_DATA,
ITF_NUM_TOTAL
};

Expand All @@ -17,14 +18,15 @@ enum USB_STRING_IDX {
STR_IDX_MANUFACTURER,
STR_IDX_PRODUCT,
STR_IDX_SERIAL,
STR_IDX_CDCITF,
STR_IDX_AUDIOITF,
STR_IDX_AUDIOIN,
STR_IDX_AUDIOOUT,
STR_IDX_AUDIOINVOL,
STR_IDX_AUDIOOUTVOL,
STR_IDX_AUDIOINCHAN,
STR_IDX_AUDIOOUTCHAN,
STR_IDX_HIDITF,
STR_IDX_CDCITF
};

#define USB_VID 0x1209
Expand All @@ -33,22 +35,26 @@ enum USB_STRING_IDX {

#define USB_STRING_MANUFACTURER "AIOC"
#define USB_STRING_PRODUCT "All-In-One-Cable"
#define USB_STRING_CDCITF "AIOC CDC"
#define USB_STRING_AUDIOITF "AIOC Audio"
#define USB_STRING_AUDIOIN "AIOC Audio In"
#define USB_STRING_AUDIOOUT "AIOC Audio Out"
#define USB_STRING_AUDIOINVOL "AIOC Audio In Volume"
#define USB_STRING_AUDIOOUTVOL "AIOC Audio Out Volume"
#define USB_STRING_AUDIOINCHAN "AIOC Audio In Channel"
#define USB_STRING_AUDIOOUTCHAN "AIOC Audio Out Channel"
#define USB_STRING_CDCITF "AIOC CDC"
#define USB_STRING_HIDITF "AIOC HID"

/* Endpoints */
#define EPNUM_AUDIO_IN 0x81
#define EPNUM_AUDIO_OUT 0x02
#define EPNUM_AUDIO_FB 0x82
#define EPNUM_CDC_0_OUT 0x03
#define EPNUM_CDC_0_IN 0x83
#define EPNUM_CDC_0_NOTIF 0x84
#define EPNUM_HID_IN 0x83
#define EPNUM_HID_OUT 0x03
#define EPNUM_CDC_0_OUT 0x04
#define EPNUM_CDC_0_IN 0x84
#define EPNUM_CDC_0_NOTIF 0x85


/* Custom Audio Descriptor.
* Courtesy of https://github.com/hathach/tinyusb/issues/1249#issuecomment-1148727765 */
Expand All @@ -65,7 +71,7 @@ enum USB_STRING_IDX {
#define AUDIO_NUM_INCHANNELS 0x01
#define AUDIO_NUM_OUTCHANNELS 0x01

#define TUD_AUDIO_CTRL_TOTAL_LEN ( \
#define AIOC_AUDIO_CTRL_TOTAL_LEN ( \
TUD_AUDIO_DESC_CLK_SRC_LEN + \
TUD_AUDIO_DESC_INPUT_TERM_LEN + \
TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN + \
Expand All @@ -75,11 +81,11 @@ enum USB_STRING_IDX {
TUD_AUDIO_DESC_OUTPUT_TERM_LEN + \
TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN)

#define TUD_AUDIO_IO_DESC_LEN ( \
#define AIOC_AUDIO_DESC_LEN ( \
TUD_AUDIO_DESC_IAD_LEN + \
TUD_AUDIO_DESC_STD_AC_LEN + \
TUD_AUDIO_DESC_CS_AC_LEN + \
TUD_AUDIO_CTRL_TOTAL_LEN + \
AIOC_AUDIO_CTRL_TOTAL_LEN + \
/* Speaker Interface */ \
TUD_AUDIO_DESC_STD_AS_INT_LEN + \
TUD_AUDIO_DESC_STD_AS_INT_LEN + \
Expand All @@ -96,14 +102,14 @@ enum USB_STRING_IDX {
TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN + \
TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN)

#define TUD_AUDIO_IO_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epinsize, _epout, _epoutsize, _epfb) \
#define AIOC_AUDIO_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epinsize, _epout, _epoutsize, _epfb) \
/* Standard Interface Association Descriptor (IAD) */ \
TUD_AUDIO_DESC_IAD(_itfnum, AUDIO_NUM_INTERFACES, /*_stridx*/ 0x00), \
/* Audio Control Interface */ \
/* Standard AC Interface Descriptor(4.7.1) */ \
TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \
/* Class-Specific AC Interface Header Descriptor(4.7.2) */ \
TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, AUDIO_FUNC_CONVERTER, TUD_AUDIO_CTRL_TOTAL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \
TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, AUDIO_FUNC_CONVERTER, AIOC_AUDIO_CTRL_TOTAL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \
/* Clock Source Descriptor(4.7.2.1) */ \
TUD_AUDIO_DESC_CLK_SRC(AUDIO_CTRL_ID_SPK_CLOCK, AUDIO_CLOCK_SOURCE_ATT_INT_PRO_CLK, (AUDIO_CTRL_RW << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ AUDIO_CTRL_ID_SPK_INPUT_STREAM, /*_stridx*/ 0x00), \
/* Speaker Terminals */ \
Expand Down Expand Up @@ -147,4 +153,19 @@ enum USB_STRING_IDX {
/* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \
TUD_AUDIO_DESC_CS_AS_ISO_EP(AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, AUDIO_CTRL_NONE, AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, 0x0000)


#define AIOC_HID_DESC_LEN (9 + 9 + 7)

#define AIOC_HID_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epin, _epsize, _ep_interval) \
/* Interface */\
9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_HID, (uint8_t)((_boot_protocol) ? (uint8_t)HID_SUBCLASS_BOOT : 0), _boot_protocol, _stridx,\
/* HID descriptor */\
9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0100), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\
/* Endpoint In */\
7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval

#define AIOC_CDC_DESC_LEN TUD_CDC_DESC_LEN

#define AIOC_CDC_DESCRIPTOR TUD_CDC_DESCRIPTOR

#endif /* USB_DESCRIPTORS_H_ */
70 changes: 70 additions & 0 deletions stm32/aioc-fw/Src/usb_hid.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include "usb_hid.h"
#include "tusb.h"
#include "ptt.h"
#include "usb_descriptors.h"

#define USB_HID_INOUT_REPORT_LEN 4

static uint8_t gpioState = 0x00;

static void ControlPTT(uint8_t gpio)
{
/* PTT1 on GPIO 3, PTT2 on GPIO4 */
uint8_t pttMask = (gpio & 0x04 ? PTT_MASK_PTT1 : 0) |
(gpio & 0x08 ? PTT_MASK_PTT2 : 0);

PTT_Control(pttMask);
}

// Invoked when received GET_REPORT control request
// Application must fill buffer report's content and return its length.
// Return zero will cause the stack to STALL request
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
{
(void) itf;
(void) report_id;
(void) report_type;
(void) buffer;
(void) reqlen;

buffer[0] = 0x00;
buffer[1] = gpioState;
buffer[2] = 0x00;
buffer[3] = 0x00;

return USB_HID_INOUT_REPORT_LEN;
}

// Invoked when received SET_REPORT control request
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
{
(void) itf;
(void) report_id;

switch (report_type) {
case HID_REPORT_TYPE_OUTPUT:
TU_ASSERT(bufsize == USB_HID_INOUT_REPORT_LEN, /* */);

/* Output report, emulate CM108 behaviour */
if ((buffer[0] & 0xC0) == 0) {
gpioState = buffer[1];
ControlPTT(gpioState);
}
break;

case HID_REPORT_TYPE_FEATURE:
/* Custom extension for configuring the AIOC */
break;

default:
TU_BREAKPOINT();
break;
}
}


void USB_HIDInit(void)
{


}
6 changes: 6 additions & 0 deletions stm32/aioc-fw/Src/usb_hid.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef USB_HID_H_
#define USB_HID_H_

void USB_HIDInit(void);

#endif /* USB_HID_H_ */

0 comments on commit 6e77ea2

Please sign in to comment.