diff --git a/docs/library/pyb.USB_HID.rst b/docs/library/pyb.USB_HID.rst
index 65fb4014e0..7d17c3099f 100644
--- a/docs/library/pyb.USB_HID.rst
+++ b/docs/library/pyb.USB_HID.rst
@@ -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:
diff --git a/stmhal/Makefile b/stmhal/Makefile
index a135fbb5cb..477cb2631d 100644
--- a/stmhal/Makefile
+++ b/stmhal/Makefile
@@ -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 \
diff --git a/stmhal/usb.c b/stmhal/usb.c
index 4ef6bfa500..4eb67a8ca8 100644
--- a/stmhal/usb.c
+++ b/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);
diff --git a/stmhal/usbd_hid_interface.c b/stmhal/usbd_hid_interface.c
new file mode 100644
index 0000000000..10e03fa420
--- /dev/null
+++ b/stmhal/usbd_hid_interface.c
@@ -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
+ *
+ *
© COPYRIGHT(c) 2014 STMicroelectronics
+ *
+ * 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
+
+#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;
+}
diff --git a/stmhal/usbd_hid_interface.h b/stmhal/usbd_hid_interface.h
new file mode 100644
index 0000000000..9cdf32549d
--- /dev/null
+++ b/stmhal/usbd_hid_interface.h
@@ -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);
diff --git a/stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h b/stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h
index 248ce17f3e..76a7678929 100644
--- a/stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h
+++ b/stmhal/usbdev/class/inc/usbd_cdc_msc_hid.h
@@ -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);
diff --git a/stmhal/usbdev/class/src/usbd_cdc_msc_hid.c b/stmhal/usbdev/class/src/usbd_cdc_msc_hid.c
index a3c86140f5..3ac9029321 100644
--- a/stmhal/usbdev/class/src/usbd_cdc_msc_hid.c
+++ b/stmhal/usbdev/class/src/usbd_cdc_msc_hid.c
@@ -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;
}