summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Shawcroft <scott@tannewt.org>2018-04-08 22:02:23 -0700
committerGitHub <noreply@github.com>2018-04-08 22:02:23 -0700
commit93e09e7ee55f7193cb7be6c1279d07aad4dc08b4 (patch)
tree5c3580b913c4aa81aca0101d984dc58d3f1987ca
parent9672f3891efb5419977b378938971f8cf9dde882 (diff)
parent1e87a785b925657c5ab8fe14e76509debca663a3 (diff)
Merge pull request #738 from dhalbert/3.0_hid
3.0 hid
-rw-r--r--main.c4
-rw-r--r--ports/atmel-samd/Makefile20
-rw-r--r--ports/atmel-samd/asf4_conf/samd21/hpl_usb_config.h68
-rw-r--r--ports/atmel-samd/asf4_conf/samd51/hpl_usb_config.h74
-rw-r--r--ports/atmel-samd/common-hal/usb_hid/Device.c93
-rw-r--r--ports/atmel-samd/common-hal/usb_hid/Device.h20
-rw-r--r--ports/atmel-samd/common-hal/usb_hid/__init__.c107
-rw-r--r--ports/atmel-samd/common-hal/usb_hid/__init__.h40
-rw-r--r--ports/atmel-samd/common-hal/usb_hid/types.h43
-rw-r--r--ports/atmel-samd/mpconfigport.h2
-rw-r--r--ports/atmel-samd/supervisor/port.c6
-rw-r--r--ports/atmel-samd/supervisor/serial.c5
-rw-r--r--ports/atmel-samd/tools/autogen_usb_descriptor.h36
-rw-r--r--ports/atmel-samd/tools/gen_usb_descriptor.py354
-rw-r--r--ports/atmel-samd/usb.c15
-rw-r--r--py/objtuple.h7
-rw-r--r--shared-bindings/usb_hid/Device.h2
-rw-r--r--shared-bindings/usb_hid/__init__.h4
m---------tools/usb_descriptor0
19 files changed, 548 insertions, 352 deletions
diff --git a/main.c b/main.c
index 8c981aee1..0ad050608 100644
--- a/main.c
+++ b/main.c
@@ -286,12 +286,12 @@ int __attribute__((used)) main(void) {
#endif
// Reset to remove any state that boot.py setup. It should only be used to
- // change internal state thats not in the heap.
+ // change internal state that's not in the heap.
reset_port();
reset_mp();
}
- // Start serial after giving boot.py a chance to tweak behavior.
+ // Start serial and HID after giving boot.py a chance to tweak behavior.
serial_init();
// Boot script is finished, so now go into REPL/main mode.
diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile
index 1bcf9c350..16f789c52 100644
--- a/ports/atmel-samd/Makefile
+++ b/ports/atmel-samd/Makefile
@@ -72,6 +72,7 @@ BASE_CFLAGS = \
-Wnested-externs \
-Wunreachable-code \
-Wcast-align \
+ -Wno-error=lto-type-mismatch \
-D__$(CHIP_VARIANT)__ \
-ffunction-sections \
-fdata-sections \
@@ -81,6 +82,7 @@ BASE_CFLAGS = \
-DCIRCUITPY_SAFE_RESTART_WORD=0xDEADBEEF \
--param max-inline-insns-single=500
+
# NDEBUG disables assert() statements. This reduces code size pretty dramatically, per tannewt.
ifeq ($(CHIP_FAMILY), samd21)
@@ -95,8 +97,8 @@ endif
ifeq ($(DEBUG), 1)
# Turn on Python modules useful for debugging (e.g. uheap, ustack).
CFLAGS += -ggdb
- CFLAGS += -flto
- ## CFLAGS += -fno-inline
+## CFLAGS += -flto
+ CFLAGS += -fno-inline -fno-ipa-sra
ifeq ($(CHIP_FAMILY), samd21)
CFLAGS += -DENABLE_MICRO_TRACE_BUFFER
endif
@@ -192,6 +194,7 @@ SRC_ASF := \
hpl/systick/hpl_systick.c \
hpl/usb/hpl_usb.c \
usb/class/cdc/device/cdcdf_acm.c \
+ usb/class/hid/device/hiddf_generic.c \
usb/class/msc/device/mscdf.c \
usb/device/usbdc.c \
usb/usb_protocol.c \
@@ -281,6 +284,8 @@ SRC_COMMON_HAL = \
pulseio/PulseIn.c \
pulseio/PulseOut.c \
pulseio/PWMOut.c \
+ usb_hid/__init__.c \
+ usb_hid/Device.c
# audiobusio/__init__.c \
audiobusio/PDMIn.c \
audioio/__init__.c \
@@ -289,8 +294,6 @@ SRC_COMMON_HAL = \
nvm/ByteArray.c \
touchio/__init__.c \
touchio/TouchIn.c \
- usb_hid/__init__.c \
- usb_hid/Device.c
ifeq ($(INTERNAL_LIBM),1)
SRC_LIBM = $(addprefix lib/,\
@@ -378,14 +381,19 @@ $(BUILD)/firmware.uf2: $(BUILD)/firmware.bin
$(ECHO) "Create $@"
python2 $(TOP)/tools/uf2/utils/uf2conv.py -b $(BOOTLOADER_SIZE) -c -o $@ $^
-$(BUILD)/autogen_usb_descriptor.c: tools/gen_usb_descriptor.py Makefile
+$(BUILD)/autogen_usb_descriptor.c $(BUILD)/genhdr/autogen_usb_descriptor.h: autogen_usb_descriptor.intermediate
+
+.INTERMEDIATE: autogen_usb_descriptor.intermediate
+
+autogen_usb_descriptor.intermediate: tools/gen_usb_descriptor.py Makefile
install -d $(BUILD)
python3 tools/gen_usb_descriptor.py \
--manufacturer $(USB_MANUFACTURER)\
--product $(USB_PRODUCT)\
--vid $(USB_VID)\
--pid $(USB_PID)\
- $@
+ --output_c_file $(BUILD)/autogen_usb_descriptor.c\
+ --output_h_file $(BUILD)/genhdr/autogen_usb_descriptor.h
deploy: $(BUILD)/firmware.bin
$(ECHO) "Writing $< to the board"
diff --git a/ports/atmel-samd/asf4_conf/samd21/hpl_usb_config.h b/ports/atmel-samd/asf4_conf/samd21/hpl_usb_config.h
index 2108077bc..d1bb42fe4 100644
--- a/ports/atmel-samd/asf4_conf/samd21/hpl_usb_config.h
+++ b/ports/atmel-samd/asf4_conf/samd21/hpl_usb_config.h
@@ -2,6 +2,62 @@
#ifndef HPL_USB_CONFIG_H
#define HPL_USB_CONFIG_H
+// CIRCUITPY:
+
+// Use 64-byte USB buffers for endpoint directions that are in use. They're set to 0 below otherwise.
+
+#include "genhdr/autogen_usb_descriptor.h"
+
+#if defined(USB_ENDPOINT_1_OUT_USED) && USB_ENDPOINT_1_OUT_USED
+#define CONF_USB_EP1_CACHE 64
+#endif
+#if defined(USB_ENDPOINT_1_IN_USED) && USB_ENDPOINT_1_IN_USED
+#define CONF_USB_EP1_I_CACHE 64
+#endif
+
+#if defined(USB_ENDPOINT_2_OUT_USED) && USB_ENDPOINT_2_OUT_USED
+#define CONF_USB_EP2_CACHE 64
+#endif
+#if defined(USB_ENDPOINT_2_IN_USED) && USB_ENDPOINT_2_IN_USED
+#define CONF_USB_EP2_I_CACHE 64
+#endif
+
+#if defined(USB_ENDPOINT_3_OUT_USED) && USB_ENDPOINT_3_OUT_USED
+#define CONF_USB_EP3_CACHE 64
+#endif
+#if defined(USB_ENDPOINT_3_IN_USED) && USB_ENDPOINT_3_IN_USED
+#define CONF_USB_EP3_I_CACHE 64
+#endif
+
+#if defined(USB_ENDPOINT_4_OUT_USED) && USB_ENDPOINT_4_OUT_USED
+#define CONF_USB_EP4_CACHE 64
+#endif
+#if defined(USB_ENDPOINT_4_IN_USED) && USB_ENDPOINT_4_IN_USED
+#define CONF_USB_EP4_I_CACHE 64
+#endif
+
+#if defined(USB_ENDPOINT_5_OUT_USED) && USB_ENDPOINT_5_OUT_USED
+#define CONF_USB_EP5_CACHE 64
+#endif
+#if defined(USB_ENDPOINT_5_IN_USED) && USB_ENDPOINT_5_IN_USED
+#define CONF_USB_EP5_I_CACHE 64
+#endif
+
+#if defined(USB_ENDPOINT_6_OUT_USED) && USB_ENDPOINT_6_OUT_USED
+#define CONF_USB_EP6_CACHE 64
+#endif
+#if defined(USB_ENDPOINT_6_IN_USED) && USB_ENDPOINT_6_IN_USED
+#define CONF_USB_EP6_I_CACHE 64
+#endif
+
+#if defined(USB_ENDPOINT_7_OUT_USED) && USB_ENDPOINT_7_OUT_USED
+#define CONF_USB_EP7_CACHE 64
+#endif
+#if defined(USB_ENDPOINT_7_IN_USED) && USB_ENDPOINT_7_IN_USED
+#define CONF_USB_EP7_I_CACHE 64
+#endif
+
+
// <<< Use Configuration Wizard in Context Menu >>>
#define CONF_USB_N_0 0
@@ -28,6 +84,8 @@
// <y> Max number of endpoints supported
// <i> Limits the number of endpoints (described by EP address) can be used in app.
+// NOTE(tannewt): This not only limits the number of endpoints but also the
+// addresses. In other words, even if you use endpoint 6 you need to set this to 11.
// <CONF_USB_N_1"> 1 (EP0 only)
// <CONF_USB_N_2"> 2 (EP0 + 1 endpoint)
// <CONF_USB_N_3"> 3 (EP0 + 2 endpoints)
@@ -100,7 +158,7 @@
// <1024=> Cached by 1024 bytes buffer (interrupt or isochronous EP)
// <id> usb_arch_ep1_cache
#ifndef CONF_USB_EP1_CACHE
-#define CONF_USB_EP1_CACHE 64
+#define CONF_USB_EP1_CACHE 0
#endif
// <o> Cache buffer size for EP1 IN
@@ -138,7 +196,7 @@
// <1024=> Cached by 1024 bytes buffer (interrupt or isochronous EP)
// <id> usb_arch_ep2_cache
#ifndef CONF_USB_EP2_CACHE
-#define CONF_USB_EP2_CACHE 64
+#define CONF_USB_EP2_CACHE 0
#endif
// <o> Cache buffer size for EP2 IN
@@ -156,7 +214,7 @@
// <1024=> Cached by 1024 bytes buffer (interrupt or isochronous EP)
// <id> usb_ep2_I_CACHE
#ifndef CONF_USB_EP2_I_CACHE
-#define CONF_USB_EP2_I_CACHE 64
+#define CONF_USB_EP2_I_CACHE 0
#endif
// </h>
@@ -194,7 +252,7 @@
// <1024=> Cached by 1024 bytes buffer (interrupt or isochronous EP)
// <id> usb_ep3_I_CACHE
#ifndef CONF_USB_EP3_I_CACHE
-#define CONF_USB_EP3_I_CACHE 64
+#define CONF_USB_EP3_I_CACHE 0
#endif
// </h>
@@ -214,7 +272,7 @@
// <1024=> Cached by 1024 bytes buffer (interrupt or isochronous EP)
// <id> usb_arch_ep4_cache
#ifndef CONF_USB_EP4_CACHE
-#define CONF_USB_EP4_CACHE 64
+#define CONF_USB_EP4_CACHE 0
#endif
// <o> Cache buffer size for EP4 IN
diff --git a/ports/atmel-samd/asf4_conf/samd51/hpl_usb_config.h b/ports/atmel-samd/asf4_conf/samd51/hpl_usb_config.h
index 92dfcaa9b..d1bb42fe4 100644
--- a/ports/atmel-samd/asf4_conf/samd51/hpl_usb_config.h
+++ b/ports/atmel-samd/asf4_conf/samd51/hpl_usb_config.h
@@ -2,6 +2,62 @@
#ifndef HPL_USB_CONFIG_H
#define HPL_USB_CONFIG_H
+// CIRCUITPY:
+
+// Use 64-byte USB buffers for endpoint directions that are in use. They're set to 0 below otherwise.
+
+#include "genhdr/autogen_usb_descriptor.h"
+
+#if defined(USB_ENDPOINT_1_OUT_USED) && USB_ENDPOINT_1_OUT_USED
+#define CONF_USB_EP1_CACHE 64
+#endif
+#if defined(USB_ENDPOINT_1_IN_USED) && USB_ENDPOINT_1_IN_USED
+#define CONF_USB_EP1_I_CACHE 64
+#endif
+
+#if defined(USB_ENDPOINT_2_OUT_USED) && USB_ENDPOINT_2_OUT_USED
+#define CONF_USB_EP2_CACHE 64
+#endif
+#if defined(USB_ENDPOINT_2_IN_USED) && USB_ENDPOINT_2_IN_USED
+#define CONF_USB_EP2_I_CACHE 64
+#endif
+
+#if defined(USB_ENDPOINT_3_OUT_USED) && USB_ENDPOINT_3_OUT_USED
+#define CONF_USB_EP3_CACHE 64
+#endif
+#if defined(USB_ENDPOINT_3_IN_USED) && USB_ENDPOINT_3_IN_USED
+#define CONF_USB_EP3_I_CACHE 64
+#endif
+
+#if defined(USB_ENDPOINT_4_OUT_USED) && USB_ENDPOINT_4_OUT_USED
+#define CONF_USB_EP4_CACHE 64
+#endif
+#if defined(USB_ENDPOINT_4_IN_USED) && USB_ENDPOINT_4_IN_USED
+#define CONF_USB_EP4_I_CACHE 64
+#endif
+
+#if defined(USB_ENDPOINT_5_OUT_USED) && USB_ENDPOINT_5_OUT_USED
+#define CONF_USB_EP5_CACHE 64
+#endif
+#if defined(USB_ENDPOINT_5_IN_USED) && USB_ENDPOINT_5_IN_USED
+#define CONF_USB_EP5_I_CACHE 64
+#endif
+
+#if defined(USB_ENDPOINT_6_OUT_USED) && USB_ENDPOINT_6_OUT_USED
+#define CONF_USB_EP6_CACHE 64
+#endif
+#if defined(USB_ENDPOINT_6_IN_USED) && USB_ENDPOINT_6_IN_USED
+#define CONF_USB_EP6_I_CACHE 64
+#endif
+
+#if defined(USB_ENDPOINT_7_OUT_USED) && USB_ENDPOINT_7_OUT_USED
+#define CONF_USB_EP7_CACHE 64
+#endif
+#if defined(USB_ENDPOINT_7_IN_USED) && USB_ENDPOINT_7_IN_USED
+#define CONF_USB_EP7_I_CACHE 64
+#endif
+
+
// <<< Use Configuration Wizard in Context Menu >>>
#define CONF_USB_N_0 0
@@ -102,7 +158,7 @@
// <1024=> Cached by 1024 bytes buffer (interrupt or isochronous EP)
// <id> usb_arch_ep1_cache
#ifndef CONF_USB_EP1_CACHE
-#define CONF_USB_EP1_CACHE 64
+#define CONF_USB_EP1_CACHE 0
#endif
// <o> Cache buffer size for EP1 IN
@@ -140,7 +196,7 @@
// <1024=> Cached by 1024 bytes buffer (interrupt or isochronous EP)
// <id> usb_arch_ep2_cache
#ifndef CONF_USB_EP2_CACHE
-#define CONF_USB_EP2_CACHE 64
+#define CONF_USB_EP2_CACHE 0
#endif
// <o> Cache buffer size for EP2 IN
@@ -158,7 +214,7 @@
// <1024=> Cached by 1024 bytes buffer (interrupt or isochronous EP)
// <id> usb_ep2_I_CACHE
#ifndef CONF_USB_EP2_I_CACHE
-#define CONF_USB_EP2_I_CACHE 64
+#define CONF_USB_EP2_I_CACHE 0
#endif
// </h>
@@ -178,7 +234,7 @@
// <1024=> Cached by 1024 bytes buffer (interrupt or isochronous EP)
// <id> usb_arch_ep3_cache
#ifndef CONF_USB_EP3_CACHE
-#define CONF_USB_EP3_CACHE 64
+#define CONF_USB_EP3_CACHE 0
#endif
// <o> Cache buffer size for EP3 IN
@@ -216,7 +272,7 @@
// <1024=> Cached by 1024 bytes buffer (interrupt or isochronous EP)
// <id> usb_arch_ep4_cache
#ifndef CONF_USB_EP4_CACHE
-#define CONF_USB_EP4_CACHE 64
+#define CONF_USB_EP4_CACHE 0
#endif
// <o> Cache buffer size for EP4 IN
@@ -254,7 +310,7 @@
// <1024=> Cached by 1024 bytes buffer (interrupt or isochronous EP)
// <id> usb_arch_ep5_cache
#ifndef CONF_USB_EP5_CACHE
-#define CONF_USB_EP5_CACHE 64
+#define CONF_USB_EP5_CACHE 0
#endif
// <o> Cache buffer size for EP5 IN
@@ -292,7 +348,7 @@
// <1024=> Cached by 1024 bytes buffer (interrupt or isochronous EP)
// <id> usb_arch_ep6_cache
#ifndef CONF_USB_EP6_CACHE
-#define CONF_USB_EP6_CACHE 64
+#define CONF_USB_EP6_CACHE 0
#endif
// <o> Cache buffer size for EP6 IN
@@ -310,7 +366,7 @@
// <1024=> Cached by 1024 bytes buffer (interrupt or isochronous EP)
// <id> usb_ep6_I_CACHE
#ifndef CONF_USB_EP6_I_CACHE
-#define CONF_USB_EP6_I_CACHE 64
+#define CONF_USB_EP6_I_CACHE 0
#endif
// </h>
@@ -330,7 +386,7 @@
// <1024=> Cached by 1024 bytes buffer (interrupt or isochronous EP)
// <id> usb_arch_ep7_cache
#ifndef CONF_USB_EP7_CACHE
-#define CONF_USB_EP7_CACHE 64
+#define CONF_USB_EP7_CACHE 0
#endif
// <o> Cache buffer size for EP7 IN
diff --git a/ports/atmel-samd/common-hal/usb_hid/Device.c b/ports/atmel-samd/common-hal/usb_hid/Device.c
index 443a67f8e..ae6985aa9 100644
--- a/ports/atmel-samd/common-hal/usb_hid/Device.c
+++ b/ports/atmel-samd/common-hal/usb_hid/Device.c
@@ -26,60 +26,59 @@
#include <string.h>
-#include "py/nlr.h"
-#include "common-hal/usb_hid/__init__.h"
+#include "common-hal/usb_hid/Device.h"
+
+#include "py/runtime.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/usb_hid/Device.h"
+#include "genhdr/autogen_usb_descriptor.h"
-static void report_sent(udd_ep_status_t status, iram_size_t nb_sent,
- udd_ep_id_t ep) {
- UNUSED(status);
- UNUSED(nb_sent);
- for (uint8_t i = 0; i < 2; i++) {
- if (ep == usb_hid_devices[i].endpoint) {
- usb_hid_devices[i].transaction_ongoing = false;
- return;
- }
- }
-}
+#include "tick.h"
-bool usb_hid_send_report(usb_hid_device_obj_t *self, uint8_t* report, uint8_t len) {
- if (!self->enabled) {
- return true;
- }
- // Wait for the previous transaction to finish. Shouldn't happen.
- uint32_t timeout = 0xffff;
+#include "usb/class/hid/device/hiddf_generic.h"
- while (self->transaction_ongoing && timeout > 0) {
- timeout--;
- }
+static uint32_t usb_hid_send_report(usb_hid_device_obj_t *self, uint8_t* report, uint8_t len) {
+
+ int32_t status;
+
+ // Don't get stuck if USB fails in some way; timeout after a while.
+ uint64_t end_ticks = ticks_ms + 2000;
- if (self->transaction_ongoing) {
- return false;
+ while (ticks_ms < end_ticks) {
+ status = usb_d_ep_get_status(self->endpoint, NULL);
+ if (status == USB_BUSY) {
+ continue;
+ }
+ if (status == USB_OK) {
+ break;
+ }
+ // Some error. Give up.
+ return status;
}
- memcpy(self->report_buffer, report, len);
+ // Copy the data only when endpoint is ready to send. The previous
+ // buffer load gets zero'd out when transaction completes, so if
+ // you copy before it's ready, only zeros will get sent.
+
+ // Prefix with a report id if one is supplied.
+ if (self->report_id > 0) {
+ self->report_buffer[0] = self->report_id;
+ memcpy(&(self->report_buffer[1]), report, len);
+ return hiddf_generic_write(self->report_buffer, len + 1);
+ } else {
+ memcpy(self->report_buffer, report, len);
+ return hiddf_generic_write(self->report_buffer, len);
+ }
- // Disable interrupts to make sure we save the ongoing state before the
- // report_sent interrupt.
- common_hal_mcu_disable_interrupts();
- bool ok = udd_ep_run(self->endpoint, false,
- self->report_buffer, self->report_length, report_sent);
- self->transaction_ongoing = ok;
- common_hal_mcu_enable_interrupts();
- return ok;
}
void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t* report, uint8_t len) {
if (len != self->report_length) {
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
- "Buffer incorrect size. Should be %d bytes.", self->report_length));
- }
- if (!self->enabled) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "USB Inactive"));
+ mp_raise_ValueError_varg("Buffer incorrect size. Should be %d bytes.", self->report_length);
}
- if (!usb_hid_send_report(self, report, len)) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "USB Busy"));
+ int32_t status = usb_hid_send_report(self, report, len);
+ if (status != ERR_NONE) {
+ mp_raise_msg(&mp_type_OSError, status == USB_BUSY ? "USB Busy" : "USB Error");
}
}
@@ -90,3 +89,17 @@ uint8_t common_hal_usb_hid_device_get_usage_page(usb_hid_device_obj_t *self) {
uint8_t common_hal_usb_hid_device_get_usage(usb_hid_device_obj_t *self) {
return self->usage;
}
+
+
+void usb_hid_init() {
+}
+
+void usb_hid_reset() {
+ // We don't actually reset. We just set a report that is empty to prevent
+ // long keypresses and such.
+ uint8_t report[USB_HID_MAX_REPORT_LENGTH] = {0};
+
+ for (size_t i = 0; i < USB_HID_NUM_DEVICES; i++) {
+ usb_hid_send_report(&usb_hid_devices[i], report, usb_hid_devices[i].report_length);
+ }
+}
diff --git a/ports/atmel-samd/common-hal/usb_hid/Device.h b/ports/atmel-samd/common-hal/usb_hid/Device.h
index 1b313f9ce..f85522d65 100644
--- a/ports/atmel-samd/common-hal/usb_hid/Device.h
+++ b/ports/atmel-samd/common-hal/usb_hid/Device.h
@@ -30,8 +30,24 @@
#include <stdint.h>
#include <stdbool.h>
-#include "common-hal/usb_hid/types.h"
+#include "py/obj.h"
-bool usb_hid_send_report(usb_hid_device_obj_t *self, uint8_t* report, uint8_t len);
+#include "genhdr/autogen_usb_descriptor.h"
+
+typedef struct {
+ mp_obj_base_t base;
+ uint8_t* report_buffer;
+ uint8_t endpoint;
+ uint8_t report_id; // If non-zero, prefix report with given id.
+ uint8_t report_length; // Length not including Report ID.
+ uint8_t usage_page;
+ uint8_t usage;
+
+} usb_hid_device_obj_t;
+
+usb_hid_device_obj_t usb_hid_devices[USB_HID_NUM_DEVICES];
+
+void usb_hid_init(void);
+void usb_hid_reset(void);
#endif // COMMON_HAL_USB_HID_DEVICE_H
diff --git a/ports/atmel-samd/common-hal/usb_hid/__init__.c b/ports/atmel-samd/common-hal/usb_hid/__init__.c
index 5fa704cf8..8cbccbb4c 100644
--- a/ports/atmel-samd/common-hal/usb_hid/__init__.c
+++ b/ports/atmel-samd/common-hal/usb_hid/__init__.c
@@ -28,90 +28,67 @@
#include "py/mphal.h"
#include "py/runtime.h"
-#include "common-hal/usb_hid/__init__.h"
#include "common-hal/usb_hid/Device.h"
-#include "common-hal/usb_hid/types.h"
-#include "shared-bindings/usb_hid/__init__.h"
#include "shared-bindings/usb_hid/Device.h"
-#define UDI_HID_MOUSE_REPORT_SIZE 4
-#define UDI_HID_KBD_REPORT_SIZE 8
+#include "genhdr/autogen_usb_descriptor.h"
-uint8_t mouse_report_buffer[UDI_HID_MOUSE_REPORT_SIZE];
-uint8_t kbd_report_buffer[UDI_HID_KBD_REPORT_SIZE];
+// Buffers are report size + 1 to include the Report ID prefix byte if needed.
+static uint8_t keyboard_report_buffer[USB_HID_REPORT_LENGTH_KEYBOARD + 1];
+static uint8_t mouse_report_buffer[USB_HID_REPORT_LENGTH_MOUSE + 1];
+static uint8_t consumer_report_buffer[USB_HID_REPORT_LENGTH_CONSUMER + 1];
+static uint8_t sys_control_report_buffer[USB_HID_REPORT_LENGTH_SYS_CONTROL + 1];
-usb_hid_device_obj_t usb_hid_devices[2] = {
+usb_hid_device_obj_t usb_hid_devices[USB_HID_NUM_DEVICES] = {
{
- .endpoint = UDI_HID_MOUSE_EP_IN,
- .report_length = UDI_HID_MOUSE_REPORT_SIZE,
+ .base = { .type = &usb_hid_device_type },
+ .report_buffer = keyboard_report_buffer,
+ .endpoint = USB_HID_ENDPOINT_IN,
+ .report_id = USB_HID_REPORT_ID_KEYBOARD,
+ .report_length = USB_HID_REPORT_LENGTH_KEYBOARD,
+ .usage_page = 0x01,
+ .usage = 0x06,
+ },
+ {
+ .base = { .type = &usb_hid_device_type },
.report_buffer = mouse_report_buffer,
+ .endpoint = USB_HID_ENDPOINT_IN,
+ .report_id = USB_HID_REPORT_ID_MOUSE,
+ .report_length = USB_HID_REPORT_LENGTH_MOUSE,
.usage_page = 0x01,
.usage = 0x02,
- .enabled = false,
- .transaction_ongoing = false
},
{
- .endpoint = UDI_HID_KBD_EP_IN,
- .report_length = UDI_HID_KBD_REPORT_SIZE,
- .report_buffer = kbd_report_buffer,
+ .base = { .type = &usb_hid_device_type },
+ .report_buffer = consumer_report_buffer,
+ .endpoint = USB_HID_ENDPOINT_IN,
+ .report_id = USB_HID_REPORT_ID_CONSUMER,
+ .report_length = USB_HID_REPORT_LENGTH_CONSUMER,
+ .usage_page = 0x0C,
+ .usage = 0x01,
+ },
+ {
+ .base = { .type = &usb_hid_device_type },
+ .report_buffer = sys_control_report_buffer,
+ .endpoint = USB_HID_ENDPOINT_IN,
+ .report_id = USB_HID_REPORT_ID_SYS_CONTROL,
+ .report_length = USB_HID_REPORT_LENGTH_SYS_CONTROL,
.usage_page = 0x01,
- .usage = 0x06,
- .enabled = false,
- .transaction_ongoing = false
- }
+ .usage = 0x80,
+ },
};
-// TODO(tannewt): Make this a mp_obj_tuple_t when it is dynamically allocated.
-// until then we hard code it to two entries so LTO is happy.
-mp_obj_tuple2_t common_hal_usb_hid_devices = {
+
+mp_obj_tuple_t common_hal_usb_hid_devices = {
.base = {
.type = &mp_type_tuple,
},
- .len = 2,
+ .len = USB_HID_NUM_DEVICES,
.items = {
(mp_obj_t) &usb_hid_devices[0],
- (mp_obj_t) &usb_hid_devices[1]
+ (mp_obj_t) &usb_hid_devices[1],
+ (mp_obj_t) &usb_hid_devices[2],
+ (mp_obj_t) &usb_hid_devices[3],
}
};
-
-void usb_hid_init() {
- usb_hid_devices[0].base.type = &usb_hid_device_type;
- usb_hid_devices[1].base.type = &usb_hid_device_type;
-}
-
-void usb_hid_reset() {
- // We don't actually reset. We just set a report that is empty to prevent
- // long keypresses and such.
- uint8_t report[8] = {0, 0, 0, 0, 0, 0, 0, 0};
-
- usb_hid_send_report(&usb_hid_devices[0], report, 4);
- usb_hid_send_report(&usb_hid_devices[1], report, 8);
-}
-
-bool mp_mouse_enable(void)
-{
- usb_hid_devices[0].enabled = true;
- return true;
-}
-
-void mp_mouse_disable(void)
-{
- usb_hid_devices[0].enabled = false;
-}
-
-bool mp_keyboard_enable(void)
-{
- usb_hid_devices[1].enabled = true;
- return true;
-}
-
-void mp_keyboard_disable(void)
-{
- usb_hid_devices[1].enabled = false;
-}
-
-void mp_keyboard_led(uint8_t leds)
-{
- UNUSED(leds);
-}
diff --git a/ports/atmel-samd/common-hal/usb_hid/__init__.h b/ports/atmel-samd/common-hal/usb_hid/__init__.h
deleted file mode 100644
index 21f629f13..000000000
--- a/ports/atmel-samd/common-hal/usb_hid/__init__.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
- *
- * 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.
- */
-
-#ifndef COMMON_HAL_USB_HID_H
-#define COMMON_HAL_USB_HID_H
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#include "common-hal/usb_hid/types.h"
-
-usb_hid_device_obj_t usb_hid_devices[2];
-
-void usb_hid_init(void);
-void usb_hid_reset(void);
-
-#endif // COMMON_HAL_USB_HID_H
diff --git a/ports/atmel-samd/common-hal/usb_hid/types.h b/ports/atmel-samd/common-hal/usb_hid/types.h
deleted file mode 100644
index c276ebd0d..000000000
--- a/ports/atmel-samd/common-hal/usb_hid/types.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
- *
- * 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.
- */
-
-#ifndef MICROPY_INCLUDED_COMMON_HAL_USB_HID_TYPES_H
-#define MICROPY_INCLUDED_COMMON_HAL_USB_HID_TYPES_H
-
-#include "py/obj.h"
-
-typedef struct {
- mp_obj_base_t base;
- udd_ep_id_t endpoint;
- volatile bool transaction_ongoing;
- volatile bool enabled;
- uint8_t report_length;
- uint8_t* report_buffer;
- uint8_t usage_page;
- uint8_t usage;
-} usb_hid_device_obj_t;
-
-#endif // MICROPY_INCLUDED_COMMON_HAL_USB_HID_TYPES_H
diff --git a/ports/atmel-samd/mpconfigport.h b/ports/atmel-samd/mpconfigport.h
index de8703943..c66f0d0b3 100644
--- a/ports/atmel-samd/mpconfigport.h
+++ b/ports/atmel-samd/mpconfigport.h
@@ -215,7 +215,6 @@ extern const struct _mp_obj_module_t usb_hid_module;
// Disabled for now.
// { MP_OBJ_NEW_QSTR(MP_QSTR_touchio), (mp_obj_t)&touchio_module },
// { MP_OBJ_NEW_QSTR(MP_QSTR__stage), (mp_obj_t)&stage_module },
-// { MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid),(mp_obj_t)&usb_hid_module },
#define MICROPY_PORT_BUILTIN_MODULES \
@@ -233,6 +232,7 @@ extern const struct _mp_obj_module_t usb_hid_module;
{ MP_OBJ_NEW_QSTR(MP_QSTR_supervisor), (mp_obj_t)&supervisor_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_math), (mp_obj_t)&math_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_module }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_usb_hid),(mp_obj_t)&usb_hid_module }, \
EXTRA_BUILTIN_MODULES
#define MICROPY_PORT_BUILTIN_DEBUG_MODULES \
diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c
index cb8ffac47..23d9bc909 100644
--- a/ports/atmel-samd/supervisor/port.c
+++ b/ports/atmel-samd/supervisor/port.c
@@ -49,6 +49,7 @@
#include "common-hal/pulseio/PulseIn.h"
#include "common-hal/pulseio/PulseOut.h"
#include "common-hal/pulseio/PWMOut.h"
+#include "common-hal/usb_hid/Device.h"
#include "shared_dma.h"
#include "tick.h"
@@ -229,9 +230,8 @@ void reset_port(void) {
// gpio_set_pin_function(PIN_PB15, GPIO_PIN_FUNCTION_M); // GCLK1, D6
// #endif
-//
-// usb_hid_reset();
-//
+ usb_hid_reset();
+
// #ifdef CALIBRATE_CRYSTALLESS
// // If we are on USB lets double check our fine calibration for the clock and
// // save the new value if its different enough.
diff --git a/ports/atmel-samd/supervisor/serial.c b/ports/atmel-samd/supervisor/serial.c
index 0410c7417..4917dfb5b 100644
--- a/ports/atmel-samd/supervisor/serial.c
+++ b/ports/atmel-samd/supervisor/serial.c
@@ -28,8 +28,10 @@
#include "supervisor/serial.h"
+#include "common-hal/usb_hid/Device.h"
+
#include "usb.h"
-#include "tools/autogen_usb_descriptor.h"
+#include "genhdr/autogen_usb_descriptor.h"
// Serial number as hex characters. This writes directly to the USB
// descriptor.
@@ -57,6 +59,7 @@ void load_serial_number(void) {
void serial_init(void) {
load_serial_number();
init_usb();
+ usb_hid_init();
}
bool serial_connected(void) {
diff --git a/ports/atmel-samd/tools/autogen_usb_descriptor.h b/ports/atmel-samd/tools/autogen_usb_descriptor.h
deleted file mode 100644
index d9260681c..000000000
--- a/ports/atmel-samd/tools/autogen_usb_descriptor.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * This file is part of the Micro Python project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
- *
- * 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.
- */
-
-#ifndef MICROPY_INCLUDED_ATMEL_SAMD_TOOLS_AUTOGEN_USB_DESCRIPTOR_H
-#define MICROPY_INCLUDED_ATMEL_SAMD_TOOLS_AUTOGEN_USB_DESCRIPTOR_H
-
-#include "usb/device/usbdc.h"
-
-struct usbd_descriptors descriptor_bounds;
-uint8_t* serial_number;
-uint8_t serial_number_length;
-
-#endif // MICROPY_INCLUDED_ATMEL_SAMD_TOOLS_AUTOGEN_USB_DESCRIPTOR_H
diff --git a/ports/atmel-samd/tools/gen_usb_descriptor.py b/ports/atmel-samd/tools/gen_usb_descriptor.py
index 545600523..4669110fb 100644
--- a/ports/atmel-samd/tools/gen_usb_descriptor.py
+++ b/ports/atmel-samd/tools/gen_usb_descriptor.py
@@ -6,7 +6,7 @@ import sys
# path hacking
sys.path.append("../../tools/usb_descriptor")
-from adafruit_usb_descriptor import cdc, standard, util
+from adafruit_usb_descriptor import cdc, hid, msc, standard, util
parser = argparse.ArgumentParser(description='Generate USB descriptors.')
parser.add_argument('--manufacturer', type=str,
@@ -19,131 +19,323 @@ parser.add_argument('--pid', type=lambda x: int(x, 16),
help='product id')
parser.add_argument('--serial_number_length', type=int, default=32,
help='length needed for the serial number in digits')
-parser.add_argument('output_file', type=argparse.FileType('w'))
+parser.add_argument('--output_c_file', type=argparse.FileType('w'), required=True)
+parser.add_argument('--output_h_file', type=argparse.FileType('w'), required=True)
args = parser.parse_args()
-langid = standard.StringDescriptor("\u0409")
-manufacturer = standard.StringDescriptor(args.manufacturer)
-product = standard.StringDescriptor(args.product)
-serial_number = standard.StringDescriptor("serial number. you should fill in a unique serial number here."[:args.serial_number_length])
-strings = [langid, manufacturer, product, serial_number]
+class StringIndex:
+ """Assign a monotonically increasing index to each unique string. Start with 0."""
+ string_to_index = {}
+ strings = []
-# vid = 0x239A
-# pid = 0x8021
+ @classmethod
+ def index(cls, string):
+ if string in cls.string_to_index:
+ return cls.string_to_index[string]
+ else:
+ idx = len(cls.strings)
+ cls.string_to_index[string] = idx
+ cls.strings.append(string)
+ return idx
+
+ @classmethod
+ def strings_in_order(cls):
+ return cls.strings
+
+
+
+# langid must be the 0th string descriptor
+LANGID_INDEX = StringIndex.index("\u0409")
+assert LANGID_INDEX == 0
+SERIAL_NUMBER_INDEX = StringIndex.index("S" * args.serial_number_length)
device = standard.DeviceDescriptor(
+ description="top",
idVendor=args.vid,
idProduct=args.pid,
- iManufacturer=strings.index(manufacturer),
- iProduct=strings.index(product),
- iSerialNumber=strings.index(serial_number))
+ iManufacturer=StringIndex.index(args.manufacturer),
+ iProduct=StringIndex.index(args.product),
+ iSerialNumber=SERIAL_NUMBER_INDEX)
-# Interface numbers are interface set local and endpoints are interface local
-# until core.join_interfaces renumbers them.
-cdc_interfaces = [
- standard.InterfaceDescriptor(
- bInterfaceClass=0x2, # Communications Device Class
- bInterfaceSubClass=0x02, # Abstract control model
- bInterfaceProtocol=0x01, # Common AT Commands
- subdescriptors=[
- # Working 2.x
- # radix: hexadecimal
- # 05 24 00 10 01 header
- # 05 24 01 03 01 call manage
- # 04 24 02 06 acm
- # 05 24 06 00 01 union
- cdc.Header(bcdCDC=0x0110),
- cdc.CallManagement(bmCapabilities=0x03, bDataInterface=0x01),
- cdc.AbstractControlManagement(bmCapabilities=0x02),
- cdc.Union(bMasterInterface=0x00,
- bSlaveInterface=[0x01]),
- standard.EndpointDescriptor(
- bEndpointAddress=0x0 | standard.EndpointDescriptor.DIRECTION_IN,
- bmAttributes=standard.EndpointDescriptor.TYPE_INTERRUPT,
- wMaxPacketSize=0x8,
- bInterval=10)
- ]
- ),
- standard.InterfaceDescriptor(
- bInterfaceClass=0x0a,
- subdescriptors=[
- standard.EndpointDescriptor(
- bEndpointAddress=0x0 | standard.EndpointDescriptor.DIRECTION_IN,
- bmAttributes=standard.EndpointDescriptor.TYPE_BULK),
- standard.EndpointDescriptor(
- bEndpointAddress=0x0 | standard.EndpointDescriptor.DIRECTION_OUT,
- bmAttributes=standard.EndpointDescriptor.TYPE_BULK)
- ]
- )
-]
+# Interface numbers are interface-set local and endpoints are interface local
+# until util.join_interfaces renumbers them.
+
+cdc_union = cdc.Union(
+ description="CDC comm",
+ bMasterInterface=0x00, # Adjust this after interfaces are renumbered.
+ bSlaveInterface_list=[0x01]) # Adjust this after interfaces are renumbered.
+
+cdc_call_management = cdc.CallManagement(
+ description="CDC comm",
+ bmCapabilities=0x01,
+ bDataInterface=0x01) # Adjust this after interfaces are renumbered.
+
+cdc_comm_interface = standard.InterfaceDescriptor(
+ description="CDC comm",
+ bInterfaceClass=cdc.CDC_CLASS_COMM, # Communications Device Class
+ bInterfaceSubClass=cdc.CDC_SUBCLASS_ACM, # Abstract control model
+ bInterfaceProtocol=cdc.CDC_PROTOCOL_NONE,
+ iInterface=StringIndex.index("CircuitPython CDC control"),
+ subdescriptors=[
+ cdc.Header(
+ description="CDC comm",
+ bcdCDC=0x0110),
+ cdc_call_management,
+ cdc.AbstractControlManagement(
+ description="CDC comm",
+ bmCapabilities=0x02),
+ cdc_union,
+ standard.EndpointDescriptor(
+ description="CDC comm in",
+ bEndpointAddress=0x0 | standard.EndpointDescriptor.DIRECTION_IN,
+ bmAttributes=standard.EndpointDescriptor.TYPE_INTERRUPT,
+ wMaxPacketSize=0x0040,
+ bInterval=0x10)
+ ])
+
+cdc_data_interface = standard.InterfaceDescriptor(
+ description="CDC data",
+ bInterfaceClass=cdc.CDC_CLASS_DATA,
+ iInterface=StringIndex.index("CircuitPython CDC data"),
+ subdescriptors=[
+ standard.EndpointDescriptor(
+ description="CDC data out",
+ bEndpointAddress=0x0 | standard.EndpointDescriptor.DIRECTION_OUT,
+ bmAttributes=standard.EndpointDescriptor.TYPE_BULK),
+ standard.EndpointDescriptor(
+ description="CDC data in",
+ bEndpointAddress=0x0 | standard.EndpointDescriptor.DIRECTION_IN,
+ bmAttributes=standard.EndpointDescriptor.TYPE_BULK),
+ ])
+
+cdc_interfaces = [cdc_comm_interface, cdc_data_interface]
msc_interfaces = [
standard.InterfaceDescriptor(
- bInterfaceClass=0x08,
- bInterfaceSubClass=0x06,
- bInterfaceProtocol=0x50,
+ description="MSC",
+ bInterfaceClass=msc.MSC_CLASS,
+ bInterfaceSubClass=msc.MSC_SUBCLASS_TRANSPARENT,
+ bInterfaceProtocol=msc.MSC_PROTOCOL_BULK,
+ iInterface=StringIndex.index("CircuitPython Mass Storage"),
subdescriptors=[
standard.EndpointDescriptor(
+ description="MSC in",
bEndpointAddress=0x0 | standard.EndpointDescriptor.DIRECTION_IN,
bmAttributes=standard.EndpointDescriptor.TYPE_BULK),
standard.EndpointDescriptor(
+ description="MSC out",
bEndpointAddress=0x1 | standard.EndpointDescriptor.DIRECTION_OUT,
bmAttributes=standard.EndpointDescriptor.TYPE_BULK)
]
)
]
-interfaces = util.join_interfaces(cdc_interfaces, msc_interfaces)
+hid_report_descriptor = hid.ReportDescriptor.MOUSE_KEYBOARD_CONSUMER_SYS_CONTROL_REPORT
+hid_report_ids = hid.ReportDescriptor.REPORT_IDS
+hid_report_lengths = hid.ReportDescriptor.REPORT_LENGTHS
+hid_max_report_length = max(hid_report_lengths.values())
+
+# ASF4 expects keyboard and generic devices to have both in and out endpoints,
+# and will fail (possibly silently) if both are not supplied.
+hid_endpoint_in_descriptor = standard.EndpointDescriptor(
+ description="HID in",
+ bEndpointAddress=0x0 | standard.EndpointDescriptor.DIRECTION_IN,
+ bmAttributes=standard.EndpointDescriptor.TYPE_INTERRUPT,
+ bInterval=0x02)
+
+hid_endpoint_out_descriptor = standard.EndpointDescriptor(
+ description="HID out",
+ bEndpointAddress=0x0 | standard.EndpointDescriptor.DIRECTION_OUT,
+ bmAttributes=standard.EndpointDescriptor.TYPE_INTERRUPT)
+
+hid_interfaces = [
+ standard.InterfaceDescriptor(
+ description="HID Multiple Devices",
+ bInterfaceClass=hid.HID_CLASS,
+ bInterfaceSubClass=hid.HID_SUBCLASS_NOBOOT,
+ bInterfaceProtocol=hid.HID_PROTOCOL_NONE,
+ iInterface=StringIndex.index("CircuitPython HID"),
+ subdescriptors=[
+ hid.HIDDescriptor(
+ description="HID",
+ wDescriptorLength=len(bytes(hid_report_descriptor))),
+ hid_endpoint_in_descriptor,
+ hid_endpoint_out_descriptor,
+ ]
+ ),
+ ]
+
+# This will renumber the endpoints to make them unique across descriptors,
+# and renumber the interfaces in order. But we still need to fix up certain
+# interface cross-references.
+interfaces = util.join_interfaces(cdc_interfaces, msc_interfaces, hid_interfaces)
+
+# Now adjust the CDC interface cross-references.
-cdc_function = standard.InterfaceAssociationDescriptor(
- bFirstInterface=interfaces.index(cdc_interfaces[0]),
+cdc_union.bMasterInterface = cdc_comm_interface.bInterfaceNumber
+cdc_union.bSlaveInterface_list = [cdc_data_interface.bInterfaceNumber]
+
+cdc_call_management.bDataInterface = cdc_data_interface.bInterfaceNumber
+
+cdc_iad = standard.InterfaceAssociationDescriptor(
+ description="CDC IAD",
+ bFirstInterface=cdc_comm_interface.bInterfaceNumber,
bInterfaceCount=len(cdc_interfaces),
bFunctionClass=0x2, # Communications Device Class
bFunctionSubClass=0x2, # Abstract control model
- bFunctionProtocol=0x1) # Common AT Commands
+ bFunctionProtocol=0x1)
configuration = standard.ConfigurationDescriptor(
+ description="Composite configuration",
wTotalLength=(standard.ConfigurationDescriptor.bLength +
- cdc_function.bLength +
+ cdc_iad.bLength +
sum([len(bytes(x)) for x in interfaces])),
bNumInterfaces=len(interfaces))
-descriptor_list = [device, configuration, cdc_function]
-descriptor_list.extend(interfaces)
-descriptor_list.extend(strings)
+descriptor_list = []
+descriptor_list.append(device)
+descriptor_list.append(configuration)
+descriptor_list.append(cdc_iad)
+descriptor_list.extend(cdc_interfaces)
+descriptor_list.extend(msc_interfaces)
+# Put the CDC IAD just before the CDC interfaces.
+# There appears to be a bug in the Windows composite USB driver that requests the
+# HID report descriptor with the wrong interface number if the HID interface is not given
+# first. However, it still fetches the descriptor anyway. We could reorder the interfaces but
+# the Windows 7 Adafruit_usbser.inf file thinks CDC is at Interface 0, so we'll leave it
+# there for backwards compatibility.
+descriptor_list.extend(hid_interfaces)
+
+string_descriptors = [standard.StringDescriptor(string) for string in StringIndex.strings_in_order()]
+serial_number_descriptor = string_descriptors[SERIAL_NUMBER_INDEX]
+descriptor_list.extend(string_descriptors)
+
+c_file = args.output_c_file
+h_file = args.output_h_file
+
+
+c_file.write("""\
+#include <stdint.h>
+
+#include "{H_FILE_NAME}"
+
+#include "usb/device/usbdc.h"
-output_file = args.output_file
+""".format(H_FILE_NAME=h_file.name))
-output_file.write("#include <stdint.h>\n\n")
-output_file.write("#include \"tools/autogen_usb_descriptor.h\"\n\n")
-output_file.write("uint8_t usb_descriptors[] = {\n")
+c_file.write("""\
+uint8_t usb_descriptors[] = {
+""")
+
+# Write out all the regular descriptors as one long array (that's how ASF4 does it).
descriptor_length = 0
serial_number_offset = None
for descriptor in descriptor_list:
- output_file.write("// " + str(descriptor) + "\n")
+ c_file.write("""\
+// {DESCRIPTION} : {CLASS}
+""".format(DESCRIPTION=descriptor.description,
+ CLASS=descriptor.__class__))
+
b = bytes(descriptor)
i = 0
- if descriptor == serial_number:
- # Add two for the length and descriptor type bytes.
+
+ if descriptor == serial_number_descriptor:
+ # Add two for bLength and bDescriptorType.
serial_number_offset = descriptor_length + 2
+
# This prints each subdescriptor on a separate line.
while i < len(b):
length = b[i]
for j in range(length):
- output_file.write("0x{:02x}, ".format(b[i + j]))
- output_file.write("\n")
+ c_file.write("0x{:02x}, ".format(b[i + j]))
+ c_file.write("\n")
i += length
descriptor_length += length
- output_file.write("\n")
-output_file.write("};\n\n")
-output_file.write("struct usbd_descriptors descriptor_bounds = " +
- "{usb_descriptors," +
- " usb_descriptors + sizeof(usb_descriptors)};\n")
-output_file.write("uint8_t* serial_number = usb_descriptors + " +
- str(serial_number_offset) + ";\n")
-output_file.write("uint8_t serial_number_length = " +
- str(args.serial_number_length) + ";\n")
-
-output_file.close()
+
+c_file.write("""\
+};
+""")
+
+# Now we values we need for the .h file.
+h_file.write("""\
+#ifndef MICROPY_INCLUDED_AUTOGEN_USB_DESCRIPTOR_H
+#define MICROPY_INCLUDED_AUTOGEN_USB_DESCRIPTOR_H
+
+#define SERIAL_NUMBER_OFFSET {SERIAL_NUMBER_OFFSET}
+#define SERIAL_NUMBER_LENGTH {SERIAL_NUMBER_LENGTH}
+uint8_t* serial_number;
+
+uint8_t hid_report_descriptor[{HID_REPORT_DESCRIPTOR_LENGTH}];
+#define USB_HID_ENDPOINT_IN {HID_ENDPOINT_IN_ADDRESS}
+#define USB_HID_ENDPOINT_OUT {HID_ENDPOINT_OUT_ADDRESS}
+
+"""
+.format(SERIAL_NUMBER_OFFSET=serial_number_offset,
+ SERIAL_NUMBER_LENGTH=args.serial_number_length,
+ HID_REPORT_DESCRIPTOR_LENGTH=len(bytes(hid_report_descriptor)),
+ HID_ENDPOINT_IN_ADDRESS=hex(hid_endpoint_in_descriptor.bEndpointAddress),
+ HID_ENDPOINT_OUT_ADDRESS=hex(hid_endpoint_out_descriptor.bEndpointAddress)))
+
+# Write out #define's that declare which endpoints are in use.
+# These provide information for declaring cache sizes and perhaps other things at compile time
+for interface in interfaces:
+ for subdescriptor in interface.subdescriptors:
+ if isinstance(subdescriptor, standard.EndpointDescriptor):
+ endpoint_num = subdescriptor.bEndpointAddress & standard.EndpointDescriptor.NUMBER_MASK
+ endpoint_in = ((subdescriptor.bEndpointAddress & standard.EndpointDescriptor.DIRECTION_MASK) ==
+ standard.EndpointDescriptor.DIRECTION_IN)
+ h_file.write("""\
+#define USB_ENDPOINT_{NUMBER}_{DIRECTION}_USED 1
+""".format(NUMBER=endpoint_num,
+ DIRECTION="IN" if endpoint_in else "OUT"))
+
+h_file.write("\n")
+
+# #define the report ID's used in the combined HID descriptor
+for name, id in hid_report_ids.items():
+ h_file.write("""\
+#define USB_HID_REPORT_ID_{NAME} {ID}
+""".format(NAME=name,
+ ID = id))
+
+h_file.write("\n")
+
+# #define the report sizes used in the combined HID descriptor
+for name, length in hid_report_lengths.items():
+ h_file.write("""\
+#define USB_HID_REPORT_LENGTH_{NAME} {LENGTH}
+""".format(NAME=name,
+ LENGTH=length))
+
+h_file.write("\n")
+
+h_file.write("""\
+#define USB_HID_NUM_DEVICES {NUM_DEVICES}
+#define USB_HID_MAX_REPORT_LENGTH {MAX_LENGTH}
+""".format(NUM_DEVICES=len(hid_report_lengths),
+ MAX_LENGTH=hid_max_report_length))
+
+
+
+# Write out the report descriptor and info
+c_file.write("""\
+uint8_t hid_report_descriptor[{HID_DESCRIPTOR_LENGTH}] = {{
+""".format(HID_DESCRIPTOR_LENGTH=len(bytes(hid_report_descriptor))))
+
+for b in bytes(hid_report_descriptor):
+ c_file.write("0x{:02x}, ".format(b))
+c_file.write("""
+};
+""")
+
+c_file.write("""\
+
+struct usbd_descriptors descriptor_bounds = {{usb_descriptors, usb_descriptors + sizeof(usb_descriptors)}};
+uint8_t* serial_number = usb_descriptors + {SERIAL_NUMBER_OFFSET};
+""".format(SERIAL_NUMBER_OFFSET=serial_number_offset))
+
+h_file.write("""\
+#endif // MICROPY_INCLUDED_AUTOGEN_USB_DESCRIPTOR_H
+""")
diff --git a/ports/atmel-samd/usb.c b/ports/atmel-samd/usb.c
index fd939e22d..7fff957c0 100644
--- a/ports/atmel-samd/usb.c
+++ b/ports/atmel-samd/usb.c
@@ -34,8 +34,6 @@
#include "hal/include/hal_gpio.h"
#include "usb/class/cdc/device/cdcdf_acm.h"
-// #include "hiddf_mouse.h"
-// #include "hiddf_keyboard.h"
#include "usb/class/hid/device/hiddf_generic.h"
#include "usb/class/composite/device/composite_desc.h"
#include "usb/class/msc/device/mscdf.h"
@@ -44,12 +42,14 @@
#include "hpl/gclk/hpl_gclk_base.h"
#include "lib/utils/interrupt_char.h"
-#include "tools/autogen_usb_descriptor.h"
+#include "genhdr/autogen_usb_descriptor.h"
#include "reset.h"
#include "usb_mass_storage.h"
#include "supervisor/shared/autoreload.h"
+extern struct usbd_descriptors descriptor_bounds;
+
// Store received characters on our own so that we can filter control characters
// and act immediately on CTRL-C for example.
@@ -199,14 +199,11 @@ void init_usb(void) {
usbdc_init(ctrl_buffer);
- /* usbdc_register_funcion inside */
+ /* usbdc_register_function inside */
cdcdf_acm_init();
pending_read = false;
mscdf_init(1);
- // hiddf_mouse_init();
- // hiddf_keyboard_init();
-
mscdf_register_callback(MSCDF_CB_INQUIRY_DISK, (FUNC_PTR)usb_msc_inquiry_info);
mscdf_register_callback(MSCDF_CB_GET_DISK_CAPACITY, (FUNC_PTR)usb_msc_get_capacity);
mscdf_register_callback(MSCDF_CB_START_READ_DISK, (FUNC_PTR)usb_msc_new_read);
@@ -216,9 +213,13 @@ void init_usb(void) {
mscdf_register_callback(MSCDF_CB_XFER_BLOCKS_DONE, (FUNC_PTR)usb_msc_xfer_done);
mscdf_register_callback(MSCDF_CB_IS_WRITABLE, (FUNC_PTR)usb_msc_disk_is_writable);
+ hiddf_generic_init(hid_report_descriptor, sizeof(hid_report_descriptor));
+
usbdc_start(&descriptor_bounds);
usbdc_attach();
+
+
}
static bool cdc_enabled(void) {
diff --git a/py/objtuple.h b/py/objtuple.h
index bcf0c9ed4..7f20ab7b6 100644
--- a/py/objtuple.h
+++ b/py/objtuple.h
@@ -34,13 +34,6 @@ typedef struct _mp_obj_tuple_t {
mp_obj_t items[];
} mp_obj_tuple_t;
-// TODO(tannewt): Remove this when we no longer hard code the usb hid tuple.
-typedef struct _mp_obj_tuple2_t {
- mp_obj_base_t base;
- size_t len;
- mp_obj_t items[2];
-} mp_obj_tuple2_t;
-
typedef struct _mp_rom_obj_tuple_t {
mp_obj_base_t base;
size_t len;
diff --git a/shared-bindings/usb_hid/Device.h b/shared-bindings/usb_hid/Device.h
index 33b9f1c99..2bc553c4a 100644
--- a/shared-bindings/usb_hid/Device.h
+++ b/shared-bindings/usb_hid/Device.h
@@ -27,7 +27,7 @@
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_USB_HID_DEVICE_H
#define MICROPY_INCLUDED_SHARED_BINDINGS_USB_HID_DEVICE_H
-#include "common-hal/usb_hid/types.h"
+#include "common-hal/usb_hid/Device.h"
const mp_obj_type_t usb_hid_device_type;
diff --git a/shared-bindings/usb_hid/__init__.h b/shared-bindings/usb_hid/__init__.h
index ff478d083..3d56fbfd0 100644
--- a/shared-bindings/usb_hid/__init__.h
+++ b/shared-bindings/usb_hid/__init__.h
@@ -30,8 +30,6 @@
#include <stdint.h>
#include <stdbool.h>
-// TODO(tannewt): Make this a mp_obj_tuple_t when it is dynamically allocated.
-// until then we hard code it to two entries so LTO is happy.
-extern mp_obj_tuple2_t common_hal_usb_hid_devices;
+extern mp_obj_tuple_t common_hal_usb_hid_devices;
#endif // SHARED_BINDINGS_USB_HID_H
diff --git a/tools/usb_descriptor b/tools/usb_descriptor
-Subproject a04341153b41b4728f9b42a77cbd51c49536228
+Subproject 0ccd1935d666bcffc3fd5941ba06bd9273d72e0