Skip to content

Commit eb239b8

Browse files
philandstuffdpgeorge
authored andcommitted
stmhal/usb: Add support to receive USB HID messages from host.
1 parent 03de5a1 commit eb239b8

7 files changed

Lines changed: 215 additions & 1 deletion

File tree

docs/library/pyb.USB_HID.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@ Constructors
2020
Methods
2121
-------
2222

23+
.. method:: USB_HID.recv(data, \*, timeout=5000)
24+
25+
Receive data on the bus:
26+
27+
- ``data`` can be an integer, which is the number of bytes to receive,
28+
or a mutable buffer, which will be filled with received bytes.
29+
- ``timeout`` is the timeout in milliseconds to wait for the receive.
30+
31+
Return value: if ``data`` is an integer then a new buffer of the bytes received,
32+
otherwise the number of bytes read into ``data`` is returned.
33+
2334
.. method:: USB_HID.send(data)
2435

2536
Send data over the USB HID interface:

stmhal/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ SRC_C = \
121121
usbd_conf.c \
122122
usbd_desc.c \
123123
usbd_cdc_interface.c \
124+
usbd_hid_interface.c \
124125
usbd_msc_storage.c \
125126
mphalport.c \
126127
irq.c \

stmhal/usb.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "usbd_cdc_msc_hid.h"
3333
#include "usbd_cdc_interface.h"
3434
#include "usbd_msc_storage.h"
35+
#include "usbd_hid_interface.h"
3536

3637
#include "py/objstr.h"
3738
#include "py/runtime.h"
@@ -123,6 +124,7 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_H
123124
USBD_MSC_RegisterStorage(&hUSBDDevice, (USBD_StorageTypeDef*)&USBD_FLASH_STORAGE_fops);
124125
break;
125126
}
127+
USBD_HID_RegisterInterface(&hUSBDDevice, (USBD_HID_ItfTypeDef*)&USBD_HID_fops);
126128
USBD_Start(&hUSBDDevice);
127129
}
128130
pyb_usb_flags |= PYB_USB_FLAG_DEV_ENABLED;
@@ -553,6 +555,43 @@ STATIC mp_obj_t pyb_usb_hid_make_new(const mp_obj_type_t *type, mp_uint_t n_args
553555
return (mp_obj_t)&pyb_usb_hid_obj;
554556
}
555557

558+
/// \method recv(data, *, timeout=5000)
559+
///
560+
/// Receive data on the bus:
561+
///
562+
/// - `data` can be an integer, which is the number of bytes to receive,
563+
/// or a mutable buffer, which will be filled with received bytes.
564+
/// - `timeout` is the timeout in milliseconds to wait for the receive.
565+
///
566+
/// Return value: if `data` is an integer then a new buffer of the bytes received,
567+
/// otherwise the number of bytes read into `data` is returned.
568+
STATIC mp_obj_t pyb_usb_hid_recv(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
569+
static const mp_arg_t allowed_args[] = {
570+
{ MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
571+
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
572+
};
573+
574+
// parse args
575+
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
576+
mp_arg_parse_all(n_args - 1, args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
577+
578+
// get the buffer to receive into
579+
vstr_t vstr;
580+
mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &vstr);
581+
582+
// receive the data
583+
int ret = USBD_HID_Rx((uint8_t*)vstr.buf, vstr.len, vals[1].u_int);
584+
585+
// return the received data
586+
if (o_ret != MP_OBJ_NULL) {
587+
return mp_obj_new_int(ret); // number of bytes read into given buffer
588+
} else {
589+
vstr.len = ret; // set actual number of bytes read
590+
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); // create a new buffer
591+
}
592+
}
593+
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_hid_recv_obj, 1, pyb_usb_hid_recv);
594+
556595
STATIC mp_obj_t pyb_usb_hid_send(mp_obj_t self_in, mp_obj_t report_in) {
557596
#ifdef USE_DEVICE_MODE
558597
mp_buffer_info_t bufinfo;
@@ -587,6 +626,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj, pyb_hid_send_report);
587626

588627
STATIC const mp_map_elem_t pyb_usb_hid_locals_dict_table[] = {
589628
{ MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&pyb_usb_hid_send_obj },
629+
{ MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&pyb_usb_hid_recv_obj },
590630
};
591631

592632
STATIC MP_DEFINE_CONST_DICT(pyb_usb_hid_locals_dict, pyb_usb_hid_locals_dict_table);

stmhal/usbd_hid_interface.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* Taken from ST Cube library and heavily modified. See below for original
5+
* copyright header.
6+
*/
7+
8+
/**
9+
******************************************************************************
10+
* @file USB_Device/CDC_Standalone/Src/usbd_cdc_interface.c
11+
* @author MCD Application Team
12+
* @version V1.0.1
13+
* @date 26-February-2014
14+
* @brief Source file for USBD CDC interface
15+
******************************************************************************
16+
* @attention
17+
*
18+
* <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
19+
*
20+
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
21+
* You may not use this file except in compliance with the License.
22+
* You may obtain a copy of the License at:
23+
*
24+
* http://www.st.com/software_license_agreement_liberty_v2
25+
*
26+
* Unless required by applicable law or agreed to in writing, software
27+
* distributed under the License is distributed on an "AS IS" BASIS,
28+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29+
* See the License for the specific language governing permissions and
30+
* limitations under the License.
31+
*
32+
******************************************************************************
33+
*/
34+
35+
/* Includes ------------------------------------------------------------------*/
36+
37+
#include <stdint.h>
38+
39+
#include "usbd_cdc_msc_hid.h"
40+
#include "usbd_hid_interface.h"
41+
42+
#include "py/obj.h"
43+
#include "irq.h"
44+
#include "usb.h"
45+
46+
/* Private variables ---------------------------------------------------------*/
47+
48+
static __IO uint8_t dev_is_connected = 0; // indicates if we are connected
49+
50+
static uint8_t buffer[2][64]; // pair of buffers to read individual packets into
51+
static int8_t current_read_buffer = 0; // which buffer to read from
52+
static uint32_t last_read_len; // length of last read
53+
static int8_t current_write_buffer = 0; // which buffer to write to
54+
55+
static size_t rx_packet_size = 64; // expected size of packets to receive
56+
57+
/* Private function prototypes -----------------------------------------------*/
58+
static int8_t HID_Itf_Receive (uint8_t* pbuf, uint32_t Len);
59+
60+
const USBD_HID_ItfTypeDef USBD_HID_fops = {
61+
HID_Itf_Receive
62+
};
63+
64+
/**
65+
* @brief HID_Itf_Receive
66+
* Data received over USB OUT endpoint is processed here.
67+
* @param Buf: Buffer of data received
68+
* @param Len: Number of data received (in bytes)
69+
* @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL
70+
* @note The buffer we are passed here is just UserRxBuffer, so we are
71+
* free to modify it.
72+
*/
73+
static int8_t HID_Itf_Receive(uint8_t* Buf, uint32_t Len) {
74+
current_write_buffer = !current_write_buffer;
75+
last_read_len = Len;
76+
// initiate next USB packet transfer, to append to existing data in buffer
77+
USBD_HID_SetRxBuffer(&hUSBDDevice, buffer[current_write_buffer]);
78+
USBD_HID_ReceivePacket(&hUSBDDevice);
79+
80+
return USBD_OK;
81+
}
82+
83+
// timout in milliseconds.
84+
// Returns number of bytes read from the device.
85+
int USBD_HID_Rx(uint8_t *buf, uint32_t len, uint32_t timeout) {
86+
// Wait until we have buffer to read
87+
uint32_t start = HAL_GetTick();
88+
while (current_read_buffer == current_write_buffer) {
89+
// Wraparound of tick is taken care of by 2's complement arithmetic.
90+
if (HAL_GetTick() - start >= timeout) {
91+
// timeout
92+
return 0;
93+
}
94+
if (query_irq() == IRQ_STATE_DISABLED) {
95+
// IRQs disabled so buffer will never be filled; return immediately
96+
return 0;
97+
}
98+
__WFI(); // enter sleep mode, waiting for interrupt
99+
}
100+
101+
// There is not enough space in buffer
102+
if (len < last_read_len) {
103+
return 0;
104+
}
105+
106+
// Copy bytes from device to user buffer
107+
memcpy(buf, buffer[current_read_buffer], last_read_len);
108+
current_read_buffer = !current_read_buffer;
109+
110+
// Success, return number of bytes read
111+
return last_read_len;
112+
}

stmhal/usbd_hid_interface.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*/
4+
5+
#include "usbd_cdc_msc_hid.h"
6+
7+
extern const USBD_HID_ItfTypeDef USBD_HID_fops;
8+
9+
int USBD_HID_Rx(uint8_t *buf, uint32_t len, uint32_t timeout);

stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
#include "usbd_msc_scsi.h"
77
#include "usbd_ioreq.h"
88

9-
// CDC and MSC packet sizes
9+
// CDC, MSC and HID packet sizes
1010
#define CDC_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size
1111
#define MSC_MEDIA_PACKET (2048) // was 8192; how low can it go whilst still working?
12+
#define HID_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size
1213

1314
// Need to define here for BOT and SCSI layers
1415
#define MSC_IN_EP (0x81)
@@ -46,6 +47,10 @@ typedef struct {
4647
__IO uint32_t RxState;
4748
} USBD_CDC_HandleTypeDef;
4849

50+
typedef struct _USBD_HID_Itf {
51+
int8_t (* Receive)(uint8_t *, uint32_t);
52+
} USBD_HID_ItfTypeDef;
53+
4954
typedef struct _USBD_STORAGE {
5055
int8_t (* Init) (uint8_t lun);
5156
int8_t (* GetCapacity) (uint8_t lun, uint32_t *block_num, uint16_t *block_size);
@@ -105,6 +110,9 @@ uint8_t USBD_CDC_TransmitPacket (USBD_HandleTypeDef *pdev);
105110

106111
uint8_t USBD_MSC_RegisterStorage(USBD_HandleTypeDef *pdev, USBD_StorageTypeDef *fops);
107112

113+
uint8_t USBD_HID_RegisterInterface(USBD_HandleTypeDef *pdev, USBD_HID_ItfTypeDef *fops);
114+
uint8_t USBD_HID_SetRxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff);
115+
uint8_t USBD_HID_ReceivePacket(USBD_HandleTypeDef *pdev);
108116
int USBD_HID_CanSendReport(USBD_HandleTypeDef *pdev);
109117
uint8_t USBD_HID_SendReport(USBD_HandleTypeDef *pdev, uint8_t *report, uint16_t len);
110118

stmhal/usbdev/class/src/usbd_cdc_msc_hid.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ typedef struct {
8181
uint32_t IdleState;
8282
uint32_t AltSetting;
8383
HID_StateTypeDef state;
84+
uint8_t *RxBuffer;
85+
uint32_t RxLength;
8486
} USBD_HID_HandleTypeDef;
8587

8688
static uint8_t usbd_mode;
@@ -94,6 +96,7 @@ static const uint8_t *hid_report_desc;
9496

9597
static USBD_CDC_ItfTypeDef *CDC_fops;
9698
static USBD_StorageTypeDef *MSC_fops;
99+
static USBD_HID_ItfTypeDef *HID_fops;
97100

98101
static USBD_CDC_HandleTypeDef CDC_ClassData;
99102
static USBD_MSC_BOT_HandleTypeDef MSC_BOT_ClassData;
@@ -962,6 +965,9 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
962965
} else if ((usbd_mode & USBD_MODE_MSC) && epnum == (MSC_OUT_EP & 0x7f)) {
963966
MSC_BOT_DataOut(pdev, epnum);
964967
return USBD_OK;
968+
} else if ((usbd_mode & USBD_MODE_HID) && epnum == (hid_out_ep & 0x7f)) {
969+
HID_ClassData.RxLength = USBD_LL_GetRxDataSize(pdev, epnum);
970+
HID_fops->Receive(HID_ClassData.RxBuffer, HID_ClassData.RxLength);
965971
}
966972

967973
return USBD_OK;
@@ -1039,6 +1045,33 @@ uint8_t USBD_MSC_RegisterStorage(USBD_HandleTypeDef *pdev, USBD_StorageTypeDef *
10391045
}
10401046
}
10411047

1048+
uint8_t USBD_HID_RegisterInterface(USBD_HandleTypeDef *pdev, USBD_HID_ItfTypeDef *fops) {
1049+
if (fops == NULL) {
1050+
return USBD_FAIL;
1051+
} else {
1052+
HID_fops = fops;
1053+
return USBD_OK;
1054+
}
1055+
}
1056+
1057+
uint8_t USBD_HID_SetRxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff) {
1058+
HID_ClassData.RxBuffer = pbuff;
1059+
return USBD_OK;
1060+
}
1061+
1062+
// prepare OUT endpoint for reception
1063+
uint8_t USBD_HID_ReceivePacket(USBD_HandleTypeDef *pdev) {
1064+
// Suspend or Resume USB Out process
1065+
if (pdev->dev_speed == USBD_SPEED_HIGH) {
1066+
return USBD_FAIL;
1067+
}
1068+
1069+
// Prepare Out endpoint to receive next packet
1070+
USBD_LL_PrepareReceive(pdev, hid_out_ep, HID_ClassData.RxBuffer, HID_DATA_FS_MAX_PACKET_SIZE);
1071+
1072+
return USBD_OK;
1073+
}
1074+
10421075
int USBD_HID_CanSendReport(USBD_HandleTypeDef *pdev) {
10431076
return pdev->dev_state == USBD_STATE_CONFIGURED && HID_ClassData.state == HID_IDLE;
10441077
}

0 commit comments

Comments
 (0)