stmhal/usb: Add support to receive USB HID messages from host.
This commit is contained in:
parent
03de5a13cf
commit
eb239b8398
@ -20,6 +20,17 @@ Constructors
|
||||
Methods
|
||||
-------
|
||||
|
||||
.. method:: USB_HID.recv(data, \*, timeout=5000)
|
||||
|
||||
Receive data on the bus:
|
||||
|
||||
- ``data`` can be an integer, which is the number of bytes to receive,
|
||||
or a mutable buffer, which will be filled with received bytes.
|
||||
- ``timeout`` is the timeout in milliseconds to wait for the receive.
|
||||
|
||||
Return value: if ``data`` is an integer then a new buffer of the bytes received,
|
||||
otherwise the number of bytes read into ``data`` is returned.
|
||||
|
||||
.. method:: USB_HID.send(data)
|
||||
|
||||
Send data over the USB HID interface:
|
||||
|
@ -121,6 +121,7 @@ SRC_C = \
|
||||
usbd_conf.c \
|
||||
usbd_desc.c \
|
||||
usbd_cdc_interface.c \
|
||||
usbd_hid_interface.c \
|
||||
usbd_msc_storage.c \
|
||||
mphalport.c \
|
||||
irq.c \
|
||||
|
40
stmhal/usb.c
40
stmhal/usb.c
@ -32,6 +32,7 @@
|
||||
#include "usbd_cdc_msc_hid.h"
|
||||
#include "usbd_cdc_interface.h"
|
||||
#include "usbd_msc_storage.h"
|
||||
#include "usbd_hid_interface.h"
|
||||
|
||||
#include "py/objstr.h"
|
||||
#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
|
||||
USBD_MSC_RegisterStorage(&hUSBDDevice, (USBD_StorageTypeDef*)&USBD_FLASH_STORAGE_fops);
|
||||
break;
|
||||
}
|
||||
USBD_HID_RegisterInterface(&hUSBDDevice, (USBD_HID_ItfTypeDef*)&USBD_HID_fops);
|
||||
USBD_Start(&hUSBDDevice);
|
||||
}
|
||||
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
|
||||
return (mp_obj_t)&pyb_usb_hid_obj;
|
||||
}
|
||||
|
||||
/// \method recv(data, *, timeout=5000)
|
||||
///
|
||||
/// Receive data on the bus:
|
||||
///
|
||||
/// - `data` can be an integer, which is the number of bytes to receive,
|
||||
/// or a mutable buffer, which will be filled with received bytes.
|
||||
/// - `timeout` is the timeout in milliseconds to wait for the receive.
|
||||
///
|
||||
/// Return value: if `data` is an integer then a new buffer of the bytes received,
|
||||
/// otherwise the number of bytes read into `data` is returned.
|
||||
STATIC mp_obj_t pyb_usb_hid_recv(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
||||
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
|
||||
};
|
||||
|
||||
// parse args
|
||||
mp_arg_val_t vals[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, vals);
|
||||
|
||||
// get the buffer to receive into
|
||||
vstr_t vstr;
|
||||
mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &vstr);
|
||||
|
||||
// receive the data
|
||||
int ret = USBD_HID_Rx((uint8_t*)vstr.buf, vstr.len, vals[1].u_int);
|
||||
|
||||
// return the received data
|
||||
if (o_ret != MP_OBJ_NULL) {
|
||||
return mp_obj_new_int(ret); // number of bytes read into given buffer
|
||||
} else {
|
||||
vstr.len = ret; // set actual number of bytes read
|
||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); // create a new buffer
|
||||
}
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usb_hid_recv_obj, 1, pyb_usb_hid_recv);
|
||||
|
||||
STATIC mp_obj_t pyb_usb_hid_send(mp_obj_t self_in, mp_obj_t report_in) {
|
||||
#ifdef USE_DEVICE_MODE
|
||||
mp_buffer_info_t bufinfo;
|
||||
@ -587,6 +626,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj, pyb_hid_send_report);
|
||||
|
||||
STATIC const mp_map_elem_t pyb_usb_hid_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&pyb_usb_hid_send_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&pyb_usb_hid_recv_obj },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(pyb_usb_hid_locals_dict, pyb_usb_hid_locals_dict_table);
|
||||
|
112
stmhal/usbd_hid_interface.c
Normal file
112
stmhal/usbd_hid_interface.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* Taken from ST Cube library and heavily modified. See below for original
|
||||
* copyright header.
|
||||
*/
|
||||
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file USB_Device/CDC_Standalone/Src/usbd_cdc_interface.c
|
||||
* @author MCD Application Team
|
||||
* @version V1.0.1
|
||||
* @date 26-February-2014
|
||||
* @brief Source file for USBD CDC interface
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
|
||||
*
|
||||
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.st.com/software_license_agreement_liberty_v2
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "usbd_cdc_msc_hid.h"
|
||||
#include "usbd_hid_interface.h"
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "irq.h"
|
||||
#include "usb.h"
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
|
||||
static __IO uint8_t dev_is_connected = 0; // indicates if we are connected
|
||||
|
||||
static uint8_t buffer[2][64]; // pair of buffers to read individual packets into
|
||||
static int8_t current_read_buffer = 0; // which buffer to read from
|
||||
static uint32_t last_read_len; // length of last read
|
||||
static int8_t current_write_buffer = 0; // which buffer to write to
|
||||
|
||||
static size_t rx_packet_size = 64; // expected size of packets to receive
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
static int8_t HID_Itf_Receive (uint8_t* pbuf, uint32_t Len);
|
||||
|
||||
const USBD_HID_ItfTypeDef USBD_HID_fops = {
|
||||
HID_Itf_Receive
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief HID_Itf_Receive
|
||||
* Data received over USB OUT endpoint is processed here.
|
||||
* @param Buf: Buffer of data received
|
||||
* @param Len: Number of data received (in bytes)
|
||||
* @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL
|
||||
* @note The buffer we are passed here is just UserRxBuffer, so we are
|
||||
* free to modify it.
|
||||
*/
|
||||
static int8_t HID_Itf_Receive(uint8_t* Buf, uint32_t Len) {
|
||||
current_write_buffer = !current_write_buffer;
|
||||
last_read_len = Len;
|
||||
// initiate next USB packet transfer, to append to existing data in buffer
|
||||
USBD_HID_SetRxBuffer(&hUSBDDevice, buffer[current_write_buffer]);
|
||||
USBD_HID_ReceivePacket(&hUSBDDevice);
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
// timout in milliseconds.
|
||||
// Returns number of bytes read from the device.
|
||||
int USBD_HID_Rx(uint8_t *buf, uint32_t len, uint32_t timeout) {
|
||||
// Wait until we have buffer to read
|
||||
uint32_t start = HAL_GetTick();
|
||||
while (current_read_buffer == current_write_buffer) {
|
||||
// Wraparound of tick is taken care of by 2's complement arithmetic.
|
||||
if (HAL_GetTick() - start >= timeout) {
|
||||
// timeout
|
||||
return 0;
|
||||
}
|
||||
if (query_irq() == IRQ_STATE_DISABLED) {
|
||||
// IRQs disabled so buffer will never be filled; return immediately
|
||||
return 0;
|
||||
}
|
||||
__WFI(); // enter sleep mode, waiting for interrupt
|
||||
}
|
||||
|
||||
// There is not enough space in buffer
|
||||
if (len < last_read_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copy bytes from device to user buffer
|
||||
memcpy(buf, buffer[current_read_buffer], last_read_len);
|
||||
current_read_buffer = !current_read_buffer;
|
||||
|
||||
// Success, return number of bytes read
|
||||
return last_read_len;
|
||||
}
|
9
stmhal/usbd_hid_interface.h
Normal file
9
stmhal/usbd_hid_interface.h
Normal file
@ -0,0 +1,9 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*/
|
||||
|
||||
#include "usbd_cdc_msc_hid.h"
|
||||
|
||||
extern const USBD_HID_ItfTypeDef USBD_HID_fops;
|
||||
|
||||
int USBD_HID_Rx(uint8_t *buf, uint32_t len, uint32_t timeout);
|
@ -6,9 +6,10 @@
|
||||
#include "usbd_msc_scsi.h"
|
||||
#include "usbd_ioreq.h"
|
||||
|
||||
// CDC and MSC packet sizes
|
||||
// CDC, MSC and HID packet sizes
|
||||
#define CDC_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size
|
||||
#define MSC_MEDIA_PACKET (2048) // was 8192; how low can it go whilst still working?
|
||||
#define HID_DATA_FS_MAX_PACKET_SIZE (64) // endpoint IN & OUT packet size
|
||||
|
||||
// Need to define here for BOT and SCSI layers
|
||||
#define MSC_IN_EP (0x81)
|
||||
@ -46,6 +47,10 @@ typedef struct {
|
||||
__IO uint32_t RxState;
|
||||
} USBD_CDC_HandleTypeDef;
|
||||
|
||||
typedef struct _USBD_HID_Itf {
|
||||
int8_t (* Receive)(uint8_t *, uint32_t);
|
||||
} USBD_HID_ItfTypeDef;
|
||||
|
||||
typedef struct _USBD_STORAGE {
|
||||
int8_t (* Init) (uint8_t lun);
|
||||
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);
|
||||
|
||||
uint8_t USBD_MSC_RegisterStorage(USBD_HandleTypeDef *pdev, USBD_StorageTypeDef *fops);
|
||||
|
||||
uint8_t USBD_HID_RegisterInterface(USBD_HandleTypeDef *pdev, USBD_HID_ItfTypeDef *fops);
|
||||
uint8_t USBD_HID_SetRxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff);
|
||||
uint8_t USBD_HID_ReceivePacket(USBD_HandleTypeDef *pdev);
|
||||
int USBD_HID_CanSendReport(USBD_HandleTypeDef *pdev);
|
||||
uint8_t USBD_HID_SendReport(USBD_HandleTypeDef *pdev, uint8_t *report, uint16_t len);
|
||||
|
||||
|
@ -81,6 +81,8 @@ typedef struct {
|
||||
uint32_t IdleState;
|
||||
uint32_t AltSetting;
|
||||
HID_StateTypeDef state;
|
||||
uint8_t *RxBuffer;
|
||||
uint32_t RxLength;
|
||||
} USBD_HID_HandleTypeDef;
|
||||
|
||||
static uint8_t usbd_mode;
|
||||
@ -94,6 +96,7 @@ static const uint8_t *hid_report_desc;
|
||||
|
||||
static USBD_CDC_ItfTypeDef *CDC_fops;
|
||||
static USBD_StorageTypeDef *MSC_fops;
|
||||
static USBD_HID_ItfTypeDef *HID_fops;
|
||||
|
||||
static USBD_CDC_HandleTypeDef CDC_ClassData;
|
||||
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)
|
||||
} else if ((usbd_mode & USBD_MODE_MSC) && epnum == (MSC_OUT_EP & 0x7f)) {
|
||||
MSC_BOT_DataOut(pdev, epnum);
|
||||
return USBD_OK;
|
||||
} else if ((usbd_mode & USBD_MODE_HID) && epnum == (hid_out_ep & 0x7f)) {
|
||||
HID_ClassData.RxLength = USBD_LL_GetRxDataSize(pdev, epnum);
|
||||
HID_fops->Receive(HID_ClassData.RxBuffer, HID_ClassData.RxLength);
|
||||
}
|
||||
|
||||
return USBD_OK;
|
||||
@ -1039,6 +1045,33 @@ uint8_t USBD_MSC_RegisterStorage(USBD_HandleTypeDef *pdev, USBD_StorageTypeDef *
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t USBD_HID_RegisterInterface(USBD_HandleTypeDef *pdev, USBD_HID_ItfTypeDef *fops) {
|
||||
if (fops == NULL) {
|
||||
return USBD_FAIL;
|
||||
} else {
|
||||
HID_fops = fops;
|
||||
return USBD_OK;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t USBD_HID_SetRxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff) {
|
||||
HID_ClassData.RxBuffer = pbuff;
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
// prepare OUT endpoint for reception
|
||||
uint8_t USBD_HID_ReceivePacket(USBD_HandleTypeDef *pdev) {
|
||||
// Suspend or Resume USB Out process
|
||||
if (pdev->dev_speed == USBD_SPEED_HIGH) {
|
||||
return USBD_FAIL;
|
||||
}
|
||||
|
||||
// Prepare Out endpoint to receive next packet
|
||||
USBD_LL_PrepareReceive(pdev, hid_out_ep, HID_ClassData.RxBuffer, HID_DATA_FS_MAX_PACKET_SIZE);
|
||||
|
||||
return USBD_OK;
|
||||
}
|
||||
|
||||
int USBD_HID_CanSendReport(USBD_HandleTypeDef *pdev) {
|
||||
return pdev->dev_state == USBD_STATE_CONFIGURED && HID_ClassData.state == HID_IDLE;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user