stmhal/usb: Add support to receive USB HID messages from host.

master
Philip Potter 2016-08-29 22:42:38 +01:00 committed by Damien George
parent 03de5a13cf
commit eb239b8398
7 changed files with 215 additions and 1 deletions

View File

@ -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:

View File

@ -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 \

View File

@ -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);

View 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>&copy; 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;
}

View 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);

View File

@ -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);

View File

@ -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;
}