diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c
index 2d1f6084fe..3308f07449 100644
--- a/ports/stm32/usb.c
+++ b/ports/stm32/usb.c
@@ -787,6 +787,11 @@ STATIC mp_obj_t pyb_usb_hid_recv(size_t n_args, const mp_obj_t *args, mp_map_t *
// receive the data
int ret = usbd_hid_rx(&self->usb_dev->usbd_hid_itf, vstr.len, (uint8_t*)vstr.buf, vals[1].u_int);
+ if (ret < 0) {
+ // error, just return 0/empty bytes
+ ret = 0;
+ }
+
// return the received data
if (o_ret != MP_OBJ_NULL) {
return mp_obj_new_int(ret); // number of bytes read into given buffer
diff --git a/ports/stm32/usbd_hid_interface.c b/ports/stm32/usbd_hid_interface.c
index 033d83ea64..386cf34d70 100644
--- a/ports/stm32/usbd_hid_interface.c
+++ b/ports/stm32/usbd_hid_interface.c
@@ -1,113 +1,70 @@
/*
* 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.
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
*/
-/**
- ******************************************************************************
- * @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_hid_interface.h"
-#include "py/obj.h"
-#include "irq.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
#include "usb.h"
#if MICROPY_HW_USB_HID
uint8_t *usbd_hid_init(usbd_hid_state_t *hid_in) {
usbd_hid_itf_t *hid = (usbd_hid_itf_t*)hid_in;
-
- hid->current_read_buffer = 0;
- hid->last_read_len = 0;
- hid->current_write_buffer = 0;
-
- // Return the buffer to place the first USB OUT packet
- return hid->buffer[hid->current_write_buffer];
+ hid->report_in_len = USBD_HID_REPORT_INVALID;
+ return &hid->report_in_buf[0]; // location to place first incoming report
}
-// Data received over USB OUT endpoint is processed here.
-// len: number of bytes received into the buffer we passed to USBD_HID_ReceivePacket
-// Returns USBD_OK if all operations are OK else USBD_FAIL
int8_t usbd_hid_receive(usbd_hid_state_t *hid_in, size_t len) {
+ // Incoming report: save the length but don't schedule next report until user reads this one
usbd_hid_itf_t *hid = (usbd_hid_itf_t*)hid_in;
-
- hid->current_write_buffer = !hid->current_write_buffer;
- hid->last_read_len = len;
- // initiate next USB packet transfer, to append to existing data in buffer
- USBD_HID_ReceivePacket(&hid->base, hid->buffer[hid->current_write_buffer]);
- // Set NAK to indicate we need to process read buffer
- USBD_HID_SetNAK(&hid->base);
+ hid->report_in_len = len;
return USBD_OK;
}
-// Returns number of ready rx buffers.
-int usbd_hid_rx_num(usbd_hid_itf_t *hid) {
- return hid->current_read_buffer != hid->current_write_buffer;
-}
-
-// timout in milliseconds.
-// Returns number of bytes read from the device.
-int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout) {
- // Wait until we have buffer to read
- uint32_t start = HAL_GetTick();
- while (hid->current_read_buffer == hid->current_write_buffer) {
- // Wraparound of tick is taken care of by 2's complement arithmetic.
- if (HAL_GetTick() - start >= timeout) {
- // timeout
- return 0;
+int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout_ms) {
+ // Wait for an incoming report
+ uint32_t t0 = mp_hal_ticks_ms();
+ while (hid->report_in_len == USBD_HID_REPORT_INVALID) {
+ if (mp_hal_ticks_ms() - t0 >= timeout_ms || query_irq() == IRQ_STATE_DISABLED) {
+ return -MP_ETIMEDOUT;
}
- 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
+ MICROPY_EVENT_POLL_HOOK
}
- // There is not enough space in buffer
- if (len < hid->last_read_len) {
- return 0;
- }
+ // Copy bytes from report to user buffer
+ int n = MIN(len, hid->report_in_len);
+ memcpy(buf, &hid->report_in_buf[0], n);
- // Copy bytes from device to user buffer
- int read_len = hid->last_read_len;
- memcpy(buf, hid->buffer[hid->current_read_buffer], read_len);
- hid->current_read_buffer = !hid->current_read_buffer;
+ // Schedule to receive next incoming report
+ hid->report_in_len = USBD_HID_REPORT_INVALID;
+ USBD_HID_ReceivePacket(&hid->base, &hid->report_in_buf[0]);
- // Clear NAK to indicate we are ready to read more data
- USBD_HID_ClearNAK(&hid->base);
-
- // Success, return number of bytes read
- return read_len;
+ // Return number of bytes read into user buffer
+ return n;
}
#endif // MICROPY_HW_USB_HID
diff --git a/ports/stm32/usbd_hid_interface.h b/ports/stm32/usbd_hid_interface.h
index 777fa93403..5d2c9ad870 100644
--- a/ports/stm32/usbd_hid_interface.h
+++ b/ports/stm32/usbd_hid_interface.h
@@ -4,18 +4,22 @@
#ifndef MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H
#define MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H
+#include
#include "usbd_cdc_msc_hid.h"
+#define USBD_HID_REPORT_INVALID ((size_t)-1)
+
typedef struct _usbd_hid_itf_t {
usbd_hid_state_t base; // state for the base HID layer
- uint8_t buffer[2][HID_DATA_FS_MAX_PACKET_SIZE]; // pair of buffers to read individual packets into
- int8_t current_read_buffer; // which buffer to read from
- uint32_t last_read_len; // length of last read
- int8_t current_write_buffer; // which buffer to write to
+ volatile size_t report_in_len;
+ uint8_t report_in_buf[HID_DATA_FS_MAX_PACKET_SIZE];
} usbd_hid_itf_t;
-int usbd_hid_rx_num(usbd_hid_itf_t *hid);
-int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout);
+static inline int usbd_hid_rx_num(usbd_hid_itf_t *hid) {
+ return hid->report_in_len != USBD_HID_REPORT_INVALID;
+}
+
+int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout_ms);
#endif // MICROPY_INCLUDED_STM32_USBD_HID_INTERFACE_H
diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c
index 32ce4ca875..e13a93ddbc 100644
--- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c
+++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c
@@ -1190,30 +1190,6 @@ uint8_t USBD_HID_SendReport(usbd_hid_state_t *hid, uint8_t *report, uint16_t len
return USBD_FAIL;
}
-uint8_t USBD_HID_SetNAK(usbd_hid_state_t *hid) {
- // get USBx object from pdev (needed for USBx_OUTEP macro below)
- PCD_HandleTypeDef *hpcd = hid->usbd->pdev->pData;
- USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
- #if defined(STM32H7)
- uint32_t USBx_BASE = (uint32_t)USBx;
- #endif
- // set NAK on HID OUT endpoint
- USBx_OUTEP(HID_OUT_EP_WITH_CDC)->DOEPCTL |= USB_OTG_DOEPCTL_SNAK;
- return USBD_OK;
-}
-
-uint8_t USBD_HID_ClearNAK(usbd_hid_state_t *hid) {
- // get USBx object from pdev (needed for USBx_OUTEP macro below)
- PCD_HandleTypeDef *hpcd = hid->usbd->pdev->pData;
- USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;
- #if defined(STM32H7)
- uint32_t USBx_BASE = (uint32_t)USBx;
- #endif
- // clear NAK on HID OUT endpoint
- USBx_OUTEP(HID_OUT_EP_WITH_CDC)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
- return USBD_OK;
-}
-
#endif
// CDC/MSC/HID interface class callback structure