diff --git a/README.md b/README.md index ab288cbec..919251243 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ TinyUSB is an open-source cross-platform USB Host/Device stack for embedded syst Support multiple device configurations by dynamically changing usb descriptors. Low power functions such as suspend, resume and remote wakeup. Following device classes are supported: - Communication Class (CDC) -- Human Interface Device (HID): Keyboard, Mouse, Gamepad etc ... +- Human Interface Device (HID): Generic (In & Out), Keyboard, Mouse, Gamepad etc ... - Mass Storage Class (MSC): with multiple LUNs - Musical Instrument Digital Interface (MIDI) @@ -78,5 +78,6 @@ TinyUSB is currently used by these other projects: * [Adafruit nRF52 Arduino](https://github.com/adafruit/Adafruit_nRF52_Arduino) * [Adafruit nRF52 Bootloader](https://github.com/adafruit/Adafruit_nRF52_Bootloader) * [CircuitPython](https://github.com/adafruit/circuitpython) +* [TinyUSB Arduino Library](https://github.com/adafruit/Adafruit_TinyUSB_Arduino) If your project also uses TinyUSB and want to share, feel free to create a pull request. diff --git a/docs/boards.md b/docs/boards.md index 9b218fa22..5da421bc3 100644 --- a/docs/boards.md +++ b/docs/boards.md @@ -11,6 +11,7 @@ This code base already had supported for a handful of following boards ### Nordic nRF5x +- [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062) - [nRF52840-DK (aka pca10056)](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK) ### NXP LPC diff --git a/examples/device/cdc_msc_hid/Makefile b/examples/device/cdc_msc_hid/Makefile index 69bffaace..4ff3371dc 100644 --- a/examples/device/cdc_msc_hid/Makefile +++ b/examples/device/cdc_msc_hid/Makefile @@ -1,185 +1,15 @@ include ../../../tools/top.mk +include ../../make.mk -# Select the board to build for. -ifeq ($(BOARD),) - $(info You must provide a BOARD parameter with 'BOARD=') - $(info Possible values are:) - $(info $(sort $(subst /.,,$(subst $(TOP)/hw/bsp/,,$(wildcard $(TOP)/hw/bsp/*/.))))) - $(error BOARD not defined) -else - ifeq ($(wildcard $(TOP)/hw/bsp/$(BOARD)/.),) - $(error Invalid BOARD specified) - endif -endif - -# Verbose mode (V=). 0: default, 1: print out CFLAG, LDFLAG 2: print all compile command -ifeq ("$(V)","2") - QUIET = -else - QUIET = @ -endif - -# If the build directory is not given, make it reflect the board name. -BUILD ?= build-$(BOARD) - -CROSS_COMPILE = arm-none-eabi- - -include $(TOP)/hw/bsp/$(BOARD)/board.mk - -CC = $(CROSS_COMPILE)gcc -CXX = $(CROSS_COMPILE)g++ -OBJCOPY = $(CROSS_COMPILE)objcopy -SIZE = $(CROSS_COMPILE)size -MKDIR = mkdir -SED = sed -CP = cp -RM = rm - -INC += -Isrc \ - -I$(TOP)/hw \ - -I$(TOP)/src - -CFLAGS += \ - -fsingle-precision-constant \ - -fno-strict-aliasing \ - -Wdouble-promotion \ - -Wno-endif-labels \ - -Wstrict-prototypes \ - -Werror-implicit-function-declaration \ - -Wfloat-equal \ - -Wundef \ - -Wshadow \ - -Wwrite-strings \ - -Wsign-compare \ - -Wmissing-format-attribute \ - -Wno-deprecated-declarations \ - -Wnested-externs \ - -Wunreachable-code \ - -Wno-error=lto-type-mismatch \ - -ffunction-sections \ - -fdata-sections - -# This causes lots of warning with nrf5x build due to nrfx code -# CFLAGS += -Wcast-align - -#Debugging/Optimization -ifeq ($(DEBUG), 1) - CFLAGS += -O0 -ggdb -else - CFLAGS += -flto -Os -endif - -CFLAGS += $(INC) -Wall -Werror -std=gnu11 -DBOARD_$(shell echo $(BOARD) | tr '[:lower:]' '[:upper:]') -LDFLAGS += $(CFLAGS) -fshort-enums -Wl,-T,$(TOP)/$(LD_FILE) -Wl,-Map=$@.map -Wl,-cref -Wl,-gc-sections -specs=nosys.specs -specs=nano.specs - -ifeq ("$(V)","1") -$(info CFLAGS $(CFLAGS)) -$(info ) -$(info LDFLAGS $(LDFLAGS)) -$(info ) -$(info ASFLAGS $(ASFLAGS)) -$(info ) -endif - -LIBS = -lgcc -lc -lm -lnosys +INC += \ + src \ + $(TOP)/hw \ +# Example source EXAMPLE_SOURCE += $(wildcard src/*.c) SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE)) -LIB_SOURCE += \ - hw/bsp/$(BOARD)/board_$(BOARD).c \ - src/common/tusb_fifo.c \ - src/device/usbd.c \ - src/device/usbd_control.c \ - src/class/msc/msc_device.c \ - src/class/cdc/cdc_device.c \ - src/class/hid/hid_device.c \ - src/tusb.c \ - src/portable/$(VENDOR)/$(CHIP_FAMILY)/dcd_$(CHIP_FAMILY).c +# Board source +SRC_C += hw/bsp/$(BOARD)/board_$(BOARD).c -SRC_C += $(LIB_SOURCE) - -# Assembly files can be name with upper case .S, convert it to .s -SRC_S := $(SRC_S:.S=.s) - -# Due to GCC LTO bug https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966 -# assembly file should be placed first in linking order -OBJ += $(addprefix $(BUILD)/obj/, $(SRC_S:.s=.o)) -OBJ += $(addprefix $(BUILD)/obj/, $(SRC_C:.c=.o)) - -# Set all as default goal -.DEFAULT_GOAL := all -all: $(BUILD)/$(BOARD)-firmware.bin size - -OBJ_DIRS = $(sort $(dir $(OBJ))) -$(OBJ): | $(OBJ_DIRS) -$(OBJ_DIRS): - @$(MKDIR) -p $@ - -$(BUILD)/$(BOARD)-firmware.elf: $(OBJ) - @echo LINK $@ - $(QUIET)$(CC) -o $@ $(LDFLAGS) $^ -Wl,--start-group $(LIBS) -Wl,--end-group - -$(BUILD)/$(BOARD)-firmware.bin: $(BUILD)/$(BOARD)-firmware.elf - @echo CREATE $@ - @$(OBJCOPY) -O binary -j .vectors -j .text -j .data $^ $@ - -$(BUILD)/$(BOARD)-firmware.hex: $(BUILD)/$(BOARD)-firmware.elf - @echo CREATE $@ - @$(OBJCOPY) -O ihex $^ $@ - -# We set vpath to point to the top of the tree so that the source files -# can be located. By following this scheme, it allows a single build rule -# to be used to compile all .c files. -vpath %.c . $(TOP) -$(BUILD)/obj/%.o: %.c - @echo CC $(notdir $@) - $(QUIET)$(CC) $(CFLAGS) -c -MD -o $@ $< - @# The following fixes the dependency file. - @# See http://make.paulandlesley.org/autodep.html for details. - @# Regex adjusted from the above to play better with Windows paths, etc. - @$(CP) $(@:.o=.d) $(@:.o=.P); \ - $(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \ - -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \ - $(RM) $(@:.o=.d) - -# ASM sources lower case .s -vpath %.s . $(TOP) -$(BUILD)/obj/%.o: %.s - @echo AS $(notdir $@) - $(QUIET)$(CC) -x assembler-with-cpp $(ASFLAGS) -c -o $@ $< - -# ASM sources upper case .S -vpath %.S . $(TOP) -$(BUILD)/obj/%.o: %.S - @echo AS $(notdir $@) - $(QUIET)$(CC) -x assembler-with-cpp $(ASFLAGS) -c -o $@ $< - -# Flash binary using Jlink, should be added into system path -ifeq ($(OS),Windows_NT) - JLINKEXE = JLink.exe -else - JLINKEXE = JLinkExe -endif - -# default jlink interface is swd -ifeq ($(JLINK_IF),) - JLINK_IF = swd -endif - -# Flash using jlink -flash-jlink: $(BUILD)/$(BOARD)-firmware.hex - @echo halt > $(BUILD)/$(BOARD).jlink - @echo loadfile $^ >> $(BUILD)/$(BOARD).jlink - @echo r >> $(BUILD)/$(BOARD).jlink - @echo go >> $(BUILD)/$(BOARD).jlink - @echo exit >> $(BUILD)/$(BOARD).jlink - $(JLINKEXE) -device $(JLINK_DEVICE) -if $(JLINK_IF) -speed auto -CommandFile $(BUILD)/$(BOARD).jlink - -size: $(BUILD)/$(BOARD)-firmware.elf - -@echo '' - @$(SIZE) $< - -@echo '' - -clean: - rm -rf build-$(BOARD) +include ../../rules.mk diff --git a/examples/device/cdc_msc_hid/src/main.c b/examples/device/cdc_msc_hid/src/main.c index fc2f2aad0..f743026c2 100644 --- a/examples/device/cdc_msc_hid/src/main.c +++ b/examples/device/cdc_msc_hid/src/main.c @@ -49,8 +49,8 @@ static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; void led_blinking_task(void); -extern void cdc_task(void); -extern void hid_task(void); +void cdc_task(void); +void hid_task(void); /*------------- MAIN -------------*/ int main(void) @@ -196,7 +196,9 @@ void hid_task(void) if ( btn ) { int8_t const delta = 5; - tud_hid_mouse_move(REPORT_ID_MOUSE, delta, delta); // right + down + + // no button, right + down, no scroll pan + tud_hid_mouse_report(REPORT_ID_MOUSE, 0x00, delta, delta, 0, 0); // delay a bit before attempt to send keyboard report board_delay(2); @@ -220,12 +222,15 @@ void hid_task(void) }else { // send empty key report if previously has key pressed - if (has_key) tud_hid_keyboard_key_release(REPORT_ID_KEYBOARD); + if (has_key) tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL); has_key = false; } } } +// Invoked when received GET_REPORT control request +// Application must fill buffer report's content and return its length. +// Return zero will cause the stack to STALL request uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) { // TODO not Implemented @@ -237,6 +242,8 @@ uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, return 0; } +// Invoked when received SET_REPORT control request or +// received data on OUT endpoint ( Report ID = 0, Type = 0 ) void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) { // TODO not Implemented diff --git a/examples/device/cdc_msc_hid/src/tusb_config.h b/examples/device/cdc_msc_hid/src/tusb_config.h index 400afb620..c1210152e 100644 --- a/examples/device/cdc_msc_hid/src/tusb_config.h +++ b/examples/device/cdc_msc_hid/src/tusb_config.h @@ -77,17 +77,13 @@ #define CFG_TUD_MIDI 0 #define CFG_TUD_CUSTOM_CLASS 0 -//-------------------------------------------------------------------- -// CDC -//-------------------------------------------------------------------- +//------------- CDC -------------// // FIFO size of CDC TX and RX #define CFG_TUD_CDC_RX_BUFSIZE 64 #define CFG_TUD_CDC_TX_BUFSIZE 64 -//-------------------------------------------------------------------- -// MSC -//-------------------------------------------------------------------- +//------------- MSC -------------// // Buffer size of Device Mass storage #define CFG_TUD_MSC_BUFSIZE 512 @@ -101,9 +97,10 @@ // Product revision string included in Inquiry response, max 4 bytes #define CFG_TUD_MSC_PRODUCT_REV "1.0" -//-------------------------------------------------------------------- -// HID -//-------------------------------------------------------------------- +//------------- HID -------------// + +// Should be sufficient to hold ID (if any) + Data +#define CFG_TUD_HID_BUFSIZE 16 #ifdef __cplusplus } diff --git a/examples/device/cdc_msc_hid/src/usb_descriptors.c b/examples/device/cdc_msc_hid/src/usb_descriptors.c index c3bcc6f2b..72d280c2f 100644 --- a/examples/device/cdc_msc_hid/src/usb_descriptors.c +++ b/examples/device/cdc_msc_hid/src/usb_descriptors.c @@ -76,8 +76,8 @@ enum uint8_t const desc_hid_report[] = { - HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(REPORT_ID_KEYBOARD), ), - HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(REPORT_ID_MOUSE), ) + TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(REPORT_ID_KEYBOARD), ), + TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(REPORT_ID_MOUSE), ) }; #endif @@ -117,19 +117,22 @@ enum uint8_t const desc_configuration[] = { - // Config: self-powered with remote wakeup support, max power up to 100 mA + // Inteface count, string index, total length, attribute, power in mA TUD_CONFIG_DESCRIPTOR(ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), #if CFG_TUD_CDC + // Interface number, string index, EP notification address and size, EP data address (out, in) and size. TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, 0x81, 8, 0x02, 0x82, 64), #endif #if CFG_TUD_MSC + // Interface number, string index, EP Out & EP In address, EP size TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC, 0x80 | EPNUM_MSC, 64), // highspeed 512 #endif #if CFG_TUD_HID - TUD_HID_DESCRIPTOR(ITF_NUM_HID, 6, HID_PROTOCOL_KEYBOARD, sizeof(desc_hid_report), 0x84, 16, 10) + // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval + TUD_HID_DESCRIPTOR(ITF_NUM_HID, 6, HID_PROTOCOL_NONE, sizeof(desc_hid_report), 0x84, 16, 10) #endif }; @@ -162,13 +165,13 @@ uint16_t const * const string_desc_arr [] = // tud_desc_set is required by tinyusb stack tud_desc_set_t tud_desc_set = { - .device = &desc_device, - .config = desc_configuration, + .device = &desc_device, + .config = desc_configuration, - .string_arr = (uint8_t const **) string_desc_arr, - .string_count = sizeof(string_desc_arr)/sizeof(string_desc_arr[0]), + .string_arr = (uint8_t const **) string_desc_arr, + .string_count = sizeof(string_desc_arr)/sizeof(string_desc_arr[0]), #if CFG_TUD_HID - .hid_report = desc_hid_report, + .hid_report = desc_hid_report, #endif }; diff --git a/examples/device/cdc_msc_hid_freertos/Makefile b/examples/device/cdc_msc_hid_freertos/Makefile new file mode 100644 index 000000000..3a39f4601 --- /dev/null +++ b/examples/device/cdc_msc_hid_freertos/Makefile @@ -0,0 +1,29 @@ +include ../../../tools/top.mk +include ../../make.mk + +INC += \ + src \ + $(TOP)/hw \ + $(TOP)/lib/FreeRTOS/Source/include \ + $(TOP)/lib/FreeRTOS/Source/portable/GCC/$(FREERTOS_PORT) + +# Example source +EXAMPLE_SOURCE += $(wildcard src/*.c) +SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE)) + +# Board source +SRC_C += hw/bsp/$(BOARD)/board_$(BOARD).c + +# FreeRTOS source +SRC_C += \ + lib/FreeRTOS/Source/list.c \ + lib/FreeRTOS/Source/queue.c \ + lib/FreeRTOS/Source/tasks.c \ + lib/FreeRTOS/Source/timers.c \ + lib/FreeRTOS/Source/portable/MemMang/heap_4.c \ + lib/FreeRTOS/Source/portable/GCC/$(FREERTOS_PORT)/port.c \ + +# FreeRTOS (lto + Os) linker issue +LDFLAGS += -Wl,--undefined=vTaskSwitchContext + +include ../../rules.mk diff --git a/examples/device/cdc_msc_hid_freertos/ses/nrf5x/nrf5x.emProject b/examples/device/cdc_msc_hid_freertos/ses/nrf5x/nrf5x.emProject index ee387958e..f01b26d23 100644 --- a/examples/device/cdc_msc_hid_freertos/ses/nrf5x/nrf5x.emProject +++ b/examples/device/cdc_msc_hid_freertos/ses/nrf5x/nrf5x.emProject @@ -141,7 +141,6 @@ - +#include +#include + +#include "bsp/board.h" +#include "tusb.h" + +/* This example demonstrate HID Generic raw Input & Output. + * It will receive data from Host (In endpoint) and echo back (Out endpoint). + * HID Report descriptor use vendor for usage page (using template TUD_HID_REPORT_DESC_GENERIC_INOUT) + * + * Run 'python3 hid_test.py' on your PC to send and receive data to this device. + * Python and `hid` package is required, for installation please follow + * https://pypi.org/project/hid/ + */ + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF PROTYPES +//--------------------------------------------------------------------+ + +/* Blink pattern + * - 250 ms : device not mounted + * - 1000 ms : device mounted + * - 2500 ms : device is suspended + */ +enum { + BLINK_NOT_MOUNTED = 250, + BLINK_MOUNTED = 1000, + BLINK_SUSPENDED = 2500, +}; + +static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; + +void led_blinking_task(void); + +/*------------- MAIN -------------*/ +int main(void) +{ + board_init(); + + tusb_init(); + + while (1) + { + // tinyusb device task + tud_task(); + + led_blinking_task(); + } + + return 0; +} + +//--------------------------------------------------------------------+ +// Device callbacks +//--------------------------------------------------------------------+ + +// Invoked when device is mounted +void tud_mount_cb(void) +{ + blink_interval_ms = BLINK_MOUNTED; +} + +// Invoked when device is unmounted +void tud_umount_cb(void) +{ + blink_interval_ms = BLINK_NOT_MOUNTED; +} + +// Invoked when usb bus is suspended +// remote_wakeup_en : if host allow us to perform remote wakeup +// Within 7ms, device must draw an average of current less than 2.5 mA from bus +void tud_suspend_cb(bool remote_wakeup_en) +{ + (void) remote_wakeup_en; + blink_interval_ms = BLINK_SUSPENDED; +} + +// Invoked when usb bus is resumed +void tud_resume_cb(void) +{ + blink_interval_ms = BLINK_MOUNTED; +} + +//--------------------------------------------------------------------+ +// USB HID +//--------------------------------------------------------------------+ + +// Invoked when received GET_REPORT control request +// Application must fill buffer report's content and return its length. +// Return zero will cause the stack to STALL request +uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) +{ + // TODO not Implemented + (void) report_id; + (void) report_type; + (void) buffer; + (void) reqlen; + + return 0; +} + +// Invoked when received SET_REPORT control request or +// received data on OUT endpoint ( Report ID = 0, Type = 0 ) +void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) +{ + // This example doesn't use multiple report and report ID + (void) report_id; + (void) report_type; + + // echo back anything we received from host + tud_hid_report(0, buffer, bufsize); +} + +//--------------------------------------------------------------------+ +// BLINKING TASK +//--------------------------------------------------------------------+ +void led_blinking_task(void) +{ + static uint32_t start_ms = 0; + static bool led_state = false; + + // Blink every 1000 ms + if ( board_millis() < start_ms + blink_interval_ms) return; // not enough time + start_ms += blink_interval_ms; + + board_led_write(led_state); + led_state = 1 - led_state; // toggle +} diff --git a/examples/device/hid_generic_inout/src/tusb_config.h b/examples/device/hid_generic_inout/src/tusb_config.h new file mode 100644 index 000000000..baf418d94 --- /dev/null +++ b/examples/device/hid_generic_inout/src/tusb_config.h @@ -0,0 +1,88 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2018, hathach (tinyusb.org) + * + * 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 _TUSB_CONFIG_H_ +#define _TUSB_CONFIG_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//-------------------------------------------------------------------- +// COMMON CONFIGURATION +//-------------------------------------------------------------------- + +// defined by compiler flags for flexibility +#ifndef CFG_TUSB_MCU + #error CFG_TUSB_MCU must be defined +#endif + +#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX +#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED) +#else +#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE +#endif + +#define CFG_TUSB_OS OPT_OS_NONE +#define CFG_TUSB_DEBUG 2 + +/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. + * Tinyusb use follows macros to declare transferring memory so that they can be put + * into those specific section. + * e.g + * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) + * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) + */ +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif + +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN ATTR_ALIGNED(4) +#endif + +//-------------------------------------------------------------------- +// DEVICE CONFIGURATION +//-------------------------------------------------------------------- + +#define CFG_TUD_ENDOINT0_SIZE 64 + +//------------- CLASS -------------// +#define CFG_TUD_CDC 0 +#define CFG_TUD_MSC 0 +#define CFG_TUD_HID 1 +#define CFG_TUD_MIDI 0 +#define CFG_TUD_CUSTOM_CLASS 0 + +//------------- HID -------------// + +// Should be sufficient to hold ID (if any) + Data +#define CFG_TUD_HID_BUFSIZE 64 + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CONFIG_H_ */ diff --git a/examples/device/hid_generic_inout/src/usb_descriptors.c b/examples/device/hid_generic_inout/src/usb_descriptors.c new file mode 100644 index 000000000..231eb4fa6 --- /dev/null +++ b/examples/device/hid_generic_inout/src/usb_descriptors.c @@ -0,0 +1,117 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2018, hathach (tinyusb.org) + * + * 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. + * + */ + +#include "tusb.h" + +/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. + * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. + * + * Auto ProductID layout's Bitmap: + * [MSB] HID | MSC | CDC [LSB] + */ +#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) ) +#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) ) + +//------------- Device Descriptors -------------// +tusb_desc_device_t const desc_device = +{ + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize0 = CFG_TUD_ENDOINT0_SIZE, + + .idVendor = 0xCafe, + .idProduct = USB_PID, + .bcdDevice = 0x0100, + + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + + .bNumConfigurations = 0x01 +}; + +//------------- HID Report Descriptor -------------// +uint8_t const desc_hid_report[] = +{ + TUD_HID_REPORT_DESC_GENERIC_INOUT(CFG_TUD_HID_BUFSIZE) +}; + +//------------- Configuration Descriptor -------------// +enum +{ + ITF_NUM_HID, + ITF_NUM_TOTAL +}; + +enum +{ + CONFIG_TOTAL_LEN = TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN +}; + +// Use Endpoint 2 instead of 1 due to NXP MCU +// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number +// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ... +#define EPNUM_HID 0x01 + +uint8_t const desc_configuration[] = +{ + // Inteface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + + // Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval + TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID, 0, HID_PROTOCOL_NONE, sizeof(desc_hid_report), 0x80 | EPNUM_HID, EPNUM_HID, 16, 10) +}; + +//------------- String Descriptors -------------// +// array of pointer to string descriptors +uint16_t const * const string_desc_arr [] = +{ + // 0: is supported language = English + TUD_DESC_STRCONV(0x0409), + + // 1: Manufacturer + TUD_DESC_STRCONV('t', 'i', 'n', 'y', 'u', 's', 'b', '.', 'o', 'r', 'g'), + + // 2: Product + TUD_DESC_STRCONV('t', 'i', 'n', 'y', 'u', 's', 'b', ' ', 'd', 'e', 'v', 'i', 'c', 'e'), + + // 3: Serials, should use chip ID + TUD_DESC_STRCONV('1', '2', '3', '4', '5', '6'), +}; + +// tud_desc_set is required by tinyusb stack +tud_desc_set_t tud_desc_set = +{ + .device = &desc_device, + .config = desc_configuration, + + .string_arr = (uint8_t const **) string_desc_arr, + .string_count = sizeof(string_desc_arr)/sizeof(string_desc_arr[0]), + .hid_report = desc_hid_report, +}; diff --git a/examples/device/msc_dual_lun/Makefile b/examples/device/msc_dual_lun/Makefile index 1a9f9d135..59eeacf4d 100644 --- a/examples/device/msc_dual_lun/Makefile +++ b/examples/device/msc_dual_lun/Makefile @@ -1,186 +1,15 @@ include ../../../tools/top.mk +include ../../make.mk -# Select the board to build for. -ifeq ($(BOARD),) - $(info You must provide a BOARD parameter with 'BOARD=') - $(info Possible values are:) - $(info $(sort $(subst /.,,$(subst $(TOP)/hw/bsp/,,$(wildcard $(TOP)/hw/bsp/*/.))))) - $(error BOARD not defined) -else - ifeq ($(wildcard $(TOP)/hw/bsp/$(BOARD)/.),) - $(error Invalid BOARD specified) - endif -endif - -# Verbose mode (V=). 0: default, 1: print out CFLAG, LDFLAG 2: print all compile command -ifeq ("$(V)","2") - QUIET = -else - QUIET = @ -endif - -# If the build directory is not given, make it reflect the board name. -BUILD ?= build-$(BOARD) - -CROSS_COMPILE = arm-none-eabi- - -include $(TOP)/hw/bsp/$(BOARD)/board.mk - -CC = $(CROSS_COMPILE)gcc -CXX = $(CROSS_COMPILE)g++ -OBJCOPY = $(CROSS_COMPILE)objcopy -SIZE = $(CROSS_COMPILE)size -MKDIR = mkdir -SED = sed -CP = cp -RM = rm - -INC += -Isrc \ - -I$(TOP)/hw \ - -I$(TOP)/src - -CFLAGS += \ - -fsingle-precision-constant \ - -fno-strict-aliasing \ - -Wdouble-promotion \ - -Wno-endif-labels \ - -Wstrict-prototypes \ - -Werror-implicit-function-declaration \ - -Wfloat-equal \ - -Wundef \ - -Wshadow \ - -Wwrite-strings \ - -Wsign-compare \ - -Wmissing-format-attribute \ - -Wno-deprecated-declarations \ - -Wnested-externs \ - -Wunreachable-code \ - -Wno-error=lto-type-mismatch \ - -ffunction-sections \ - -fdata-sections - -# This causes lots of warning with nrf5x build due to nrfx code -# CFLAGS += -Wcast-align - -#Debugging/Optimization -ifeq ($(DEBUG), 1) - CFLAGS += -O0 -ggdb -else - CFLAGS += -flto -Os -endif - -CFLAGS += $(INC) -Wall -Werror -std=gnu11 -DBOARD_$(shell echo $(BOARD) | tr '[:lower:]' '[:upper:]') -LDFLAGS += $(CFLAGS) -fshort-enums -Wl,-T,$(TOP)/$(LD_FILE) -Wl,-Map=$@.map -Wl,-cref -Wl,-gc-sections -specs=nosys.specs -specs=nano.specs - -ifeq ("$(V)","1") -$(info CFLAGS $(CFLAGS)) -$(info ) -$(info LDFLAGS $(LDFLAGS)) -$(info ) -$(info ASFLAGS $(ASFLAGS)) -$(info ) -endif - -LIBS = -lgcc -lc -lm -lnosys +INC += \ + src \ + $(TOP)/hw \ +# Example source EXAMPLE_SOURCE += $(wildcard src/*.c) - SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE)) -LIB_SOURCE += \ - hw/bsp/$(BOARD)/board_$(BOARD).c \ - src/common/tusb_fifo.c \ - src/device/usbd.c \ - src/device/usbd_control.c \ - src/class/msc/msc_device.c \ - src/class/cdc/cdc_device.c \ - src/class/hid/hid_device.c \ - src/tusb.c \ - src/portable/$(VENDOR)/$(CHIP_FAMILY)/dcd_$(CHIP_FAMILY).c +# Board source +SRC_C += hw/bsp/$(BOARD)/board_$(BOARD).c -SRC_C += $(LIB_SOURCE) - -# Assembly files can be name with upper case .S, convert it to .s -SRC_S := $(SRC_S:.S=.s) - -# Due to GCC LTO bug https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966 -# assembly file should be placed first in linking order -OBJ += $(addprefix $(BUILD)/obj/, $(SRC_S:.s=.o)) -OBJ += $(addprefix $(BUILD)/obj/, $(SRC_C:.c=.o)) - -# Set all as default goal -.DEFAULT_GOAL := all -all: $(BUILD)/$(BOARD)-firmware.bin size - -OBJ_DIRS = $(sort $(dir $(OBJ))) -$(OBJ): | $(OBJ_DIRS) -$(OBJ_DIRS): - @$(MKDIR) -p $@ - -$(BUILD)/$(BOARD)-firmware.elf: $(OBJ) - @echo LINK $@ - $(QUIET)$(CC) -o $@ $(LDFLAGS) $^ -Wl,--start-group $(LIBS) -Wl,--end-group - -$(BUILD)/$(BOARD)-firmware.bin: $(BUILD)/$(BOARD)-firmware.elf - @echo CREATE $@ - @$(OBJCOPY) -O binary -j .vectors -j .text -j .data $^ $@ - -$(BUILD)/$(BOARD)-firmware.hex: $(BUILD)/$(BOARD)-firmware.elf - @echo CREATE $@ - @$(OBJCOPY) -O ihex $^ $@ - -# We set vpath to point to the top of the tree so that the source files -# can be located. By following this scheme, it allows a single build rule -# to be used to compile all .c files. -vpath %.c . $(TOP) -$(BUILD)/obj/%.o: %.c - @echo CC $(notdir $@) - $(QUIET)$(CC) $(CFLAGS) -c -MD -o $@ $< - @# The following fixes the dependency file. - @# See http://make.paulandlesley.org/autodep.html for details. - @# Regex adjusted from the above to play better with Windows paths, etc. - @$(CP) $(@:.o=.d) $(@:.o=.P); \ - $(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \ - -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \ - $(RM) $(@:.o=.d) - -# ASM sources lower case .s -vpath %.s . $(TOP) -$(BUILD)/obj/%.o: %.s - @echo AS $(notdir $@) - $(QUIET)$(CC) -x assembler-with-cpp $(ASFLAGS) -c -o $@ $< - -# ASM sources upper case .S -vpath %.S . $(TOP) -$(BUILD)/obj/%.o: %.S - @echo AS $(notdir $@) - $(QUIET)$(CC) -x assembler-with-cpp $(ASFLAGS) -c -o $@ $< - -# Flash binary using Jlink, should be added into system path -ifeq ($(OS),Windows_NT) - JLINKEXE = JLink.exe -else - JLINKEXE = JLinkExe -endif - -# default jlink interface is swd -ifeq ($(JLINK_IF),) - JLINK_IF = swd -endif - -# Flash using jlink -flash-jlink: $(BUILD)/$(BOARD)-firmware.hex - @echo halt > $(BUILD)/$(BOARD).jlink - @echo loadfile $^ >> $(BUILD)/$(BOARD).jlink - @echo r >> $(BUILD)/$(BOARD).jlink - @echo go >> $(BUILD)/$(BOARD).jlink - @echo exit >> $(BUILD)/$(BOARD).jlink - $(JLINKEXE) -device $(JLINK_DEVICE) -if $(JLINK_IF) -speed auto -CommandFile $(BUILD)/$(BOARD).jlink - -size: $(BUILD)/$(BOARD)-firmware.elf - -@echo '' - @$(SIZE) $< - -@echo '' - -clean: - rm -rf build-$(BOARD) +include ../../rules.mk diff --git a/examples/device/msc_dual_lun/src/tusb_config.h b/examples/device/msc_dual_lun/src/tusb_config.h index b25510f25..492eba5f1 100644 --- a/examples/device/msc_dual_lun/src/tusb_config.h +++ b/examples/device/msc_dual_lun/src/tusb_config.h @@ -76,9 +76,7 @@ #define CFG_TUD_MIDI 0 #define CFG_TUD_CUSTOM_CLASS 0 -//-------------------------------------------------------------------- -// MSC -//-------------------------------------------------------------------- +//------------- MSC -------------// // Buffer size of Device Mass storage #define CFG_TUD_MSC_BUFSIZE 512 diff --git a/examples/device/msc_dual_lun/src/usb_descriptors.c b/examples/device/msc_dual_lun/src/usb_descriptors.c index ede516eb1..af2b1a091 100644 --- a/examples/device/msc_dual_lun/src/usb_descriptors.c +++ b/examples/device/msc_dual_lun/src/usb_descriptors.c @@ -43,7 +43,6 @@ tusb_desc_device_t const desc_device = .bDeviceClass = 0x00, .bDeviceSubClass = 0x00, .bDeviceProtocol = 0x00, - .bMaxPacketSize0 = CFG_TUD_ENDOINT0_SIZE, .idVendor = 0xCafe, @@ -76,12 +75,11 @@ enum uint8_t const desc_configuration[] = { - // Config: self-powered with remote wakeup support, max power up to 100 mA + // Inteface count, string index, total length, attribute, power in mA TUD_CONFIG_DESCRIPTOR(ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), -#if CFG_TUD_MSC - TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC, 0x80 | EPNUM_MSC, 64), // highspeed 512 -#endif + // Interface number, string index, EP Out & EP In address, EP size + TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EPNUM_MSC, 0x80 | EPNUM_MSC, 64), // highspeed 512 }; //------------- String Descriptors -------------// diff --git a/examples/make.mk b/examples/make.mk new file mode 100644 index 000000000..d76f611fb --- /dev/null +++ b/examples/make.mk @@ -0,0 +1,65 @@ +# +# Common make definition for all examples +# + +# Compiler +CROSS_COMPILE = arm-none-eabi- +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +OBJCOPY = $(CROSS_COMPILE)objcopy +SIZE = $(CROSS_COMPILE)size +MKDIR = mkdir +SED = sed +CP = cp +RM = rm + +# Select the board to build for. +ifeq ($(BOARD),) + $(info You must provide a BOARD parameter with 'BOARD=') + $(info Possible values are:) + $(info $(sort $(subst /.,,$(subst $(TOP)/hw/bsp/,,$(wildcard $(TOP)/hw/bsp/*/.))))) + $(error BOARD not defined) +else + ifeq ($(wildcard $(TOP)/hw/bsp/$(BOARD)/.),) + $(error Invalid BOARD specified) + endif +endif + +# Build directory +BUILD = build-$(BOARD) + +# Board specific +include $(TOP)/hw/bsp/$(BOARD)/board.mk + +# Compiler Flags +CFLAGS += \ + -fsingle-precision-constant \ + -fno-strict-aliasing \ + -Wdouble-promotion \ + -Wno-endif-labels \ + -Wstrict-prototypes \ + -Wall \ + -Werror \ + -Werror-implicit-function-declaration \ + -Wfloat-equal \ + -Wundef \ + -Wshadow \ + -Wwrite-strings \ + -Wsign-compare \ + -Wmissing-format-attribute \ + -Wno-deprecated-declarations \ + -Wnested-externs \ + -Wunreachable-code \ + -Wno-error=lto-type-mismatch \ + -ffunction-sections \ + -fdata-sections + +# This causes lots of warning with nrf5x build due to nrfx code +# CFLAGS += -Wcast-align + +# Debugging/Optimization +ifeq ($(DEBUG), 1) + CFLAGS += -O0 -ggdb +else + CFLAGS += -flto -Os +endif diff --git a/examples/rules.mk b/examples/rules.mk new file mode 100644 index 000000000..df9ffb7e5 --- /dev/null +++ b/examples/rules.mk @@ -0,0 +1,111 @@ +# +# Common make definition for all examples +# + +# libc +LIBS = -lgcc -lc -lm -lnosys + +# TinyUSB Stack source +SRC_C += \ + src/common/tusb_fifo.c \ + src/device/usbd.c \ + src/device/usbd_control.c \ + src/class/msc/msc_device.c \ + src/class/cdc/cdc_device.c \ + src/class/hid/hid_device.c \ + src/tusb.c \ + src/portable/$(VENDOR)/$(CHIP_FAMILY)/dcd_$(CHIP_FAMILY).c + +# TinyUSB stack include +INC += $(TOP)/src + +# +CFLAGS += $(addprefix -I,$(INC)) +LDFLAGS += $(CFLAGS) -fshort-enums -Wl,-T,$(TOP)/$(LD_FILE) -Wl,-Map=$@.map -Wl,-cref -Wl,-gc-sections -specs=nosys.specs -specs=nano.specs + +# Assembly files can be name with upper case .S, convert it to .s +SRC_S := $(SRC_S:.S=.s) + +# Due to GCC LTO bug https://bugs.launchpad.net/gcc-arm-embedded/+bug/1747966 +# assembly file should be placed first in linking order +OBJ += $(addprefix $(BUILD)/obj/, $(SRC_S:.s=.o)) +OBJ += $(addprefix $(BUILD)/obj/, $(SRC_C:.c=.o)) + +# Verbose mode +ifeq ("$(V)","1") +$(info CFLAGS $(CFLAGS) ) $(info ) +$(info LDFLAGS $(LDFLAGS)) $(info ) +$(info ASFLAGS $(ASFLAGS)) $(info ) +endif + +# Set all as default goal +.DEFAULT_GOAL := all +all: $(BUILD)/$(BOARD)-firmware.bin size + +OBJ_DIRS = $(sort $(dir $(OBJ))) +$(OBJ): | $(OBJ_DIRS) +$(OBJ_DIRS): + @$(MKDIR) -p $@ + +$(BUILD)/$(BOARD)-firmware.elf: $(OBJ) + @echo LINK $@ + @$(CC) -o $@ $(LDFLAGS) $^ -Wl,--start-group $(LIBS) -Wl,--end-group + +$(BUILD)/$(BOARD)-firmware.bin: $(BUILD)/$(BOARD)-firmware.elf + @echo CREATE $@ + @$(OBJCOPY) -O binary -j .vectors -j .text -j .data $^ $@ + +$(BUILD)/$(BOARD)-firmware.hex: $(BUILD)/$(BOARD)-firmware.elf + @echo CREATE $@ + @$(OBJCOPY) -O ihex $^ $@ + +# We set vpath to point to the top of the tree so that the source files +# can be located. By following this scheme, it allows a single build rule +# to be used to compile all .c files. +vpath %.c . $(TOP) +$(BUILD)/obj/%.o: %.c + @echo CC $(notdir $@) + @$(CC) $(CFLAGS) -c -MD -o $@ $< + @# The following fixes the dependency file. + @# See http://make.paulandlesley.org/autodep.html for details. + @# Regex adjusted from the above to play better with Windows paths, etc. + @$(CP) $(@:.o=.d) $(@:.o=.P); \ + $(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \ + -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \ + $(RM) $(@:.o=.d) + +# ASM sources lower case .s +vpath %.s . $(TOP) +$(BUILD)/obj/%.o: %.s + @echo AS $(notdir $@) + @$(CC) -x assembler-with-cpp $(ASFLAGS) -c -o $@ $< + +# ASM sources upper case .S +vpath %.S . $(TOP) +$(BUILD)/obj/%.o: %.S + @echo AS $(notdir $@) + @$(CC) -x assembler-with-cpp $(ASFLAGS) -c -o $@ $< + +size: $(BUILD)/$(BOARD)-firmware.elf + -@echo '' + @$(SIZE) $< + -@echo '' + +clean: + rm -rf build-$(BOARD) + +# Flash binary using Jlink +ifeq ($(OS),Windows_NT) + JLINKEXE = JLink.exe +else + JLINKEXE = JLinkExe +endif + +# Flash using jlink +flash-jlink: $(BUILD)/$(BOARD)-firmware.hex + @echo halt > $(BUILD)/$(BOARD).jlink + @echo loadfile $^ >> $(BUILD)/$(BOARD).jlink + @echo r >> $(BUILD)/$(BOARD).jlink + @echo go >> $(BUILD)/$(BOARD).jlink + @echo exit >> $(BUILD)/$(BOARD).jlink + $(JLINKEXE) -device $(JLINK_DEVICE) -if $(JLINK_IF) -speed auto -CommandFile $(BUILD)/$(BOARD).jlink diff --git a/hw/bsp/feather_nrf52840_express/board.mk b/hw/bsp/feather_nrf52840_express/board.mk new file mode 100644 index 000000000..317a4969f --- /dev/null +++ b/hw/bsp/feather_nrf52840_express/board.mk @@ -0,0 +1,54 @@ +CFLAGS += \ + -mthumb \ + -mabi=aapcs \ + -mcpu=cortex-m4 \ + -mfloat-abi=hard \ + -mfpu=fpv4-sp-d16 \ + -DCFG_TUSB_MCU=OPT_MCU_NRF5X \ + -DNRF52840_XXAA \ + -DCONFIG_GPIO_AS_PINRESET + +# nrfx issue undef _ARMCC_VERSION usage https://github.com/NordicSemiconductor/nrfx/issues/49 +CFLAGS += -Wno-error=undef + +# All source paths should be relative to the top level. +LD_FILE = hw/mcu/nordic/nrfx/mdk/nrf52840_xxaa.ld + +LDFLAGS += -L$(TOP)/hw/mcu/nordic/nrfx/mdk + +SRC_C += \ + hw/mcu/nordic/nrfx/drivers/src/nrfx_power.c \ + hw/mcu/nordic/nrfx/mdk/system_nrf52840.c \ + +# TODO remove later +SRC_C += src/portable/$(VENDOR)/$(CHIP_FAMILY)/hal_$(CHIP_FAMILY).c + +INC += \ + $(TOP)/hw/cmsis/Include \ + $(TOP)/hw/mcu/nordic \ + $(TOP)/hw/mcu/nordic/nrfx \ + $(TOP)/hw/mcu/nordic/nrfx/mdk \ + $(TOP)/hw/mcu/nordic/nrfx/hal \ + $(TOP)/hw/mcu/nordic/nrfx/drivers/include \ + $(TOP)/hw/mcu/nordic/nrfx/drivers/src \ + +SRC_S += hw/mcu/nordic/nrfx/mdk/gcc_startup_nrf52840.S + +ASFLAGS += -D__HEAP_SIZE=0 +ASFLAGS += -DSWI_DISABLE0 +ASFLAGS += -DFLOAT_ABI_HARD +ASFLAGS += -DNRF52840_XXAA + +# For TinyUSB port source +VENDOR = nordic +CHIP_FAMILY = nrf5x + +# For freeRTOS port source +FREERTOS_PORT = ARM_CM4F + +# For flash-jlink target +JLINK_DEVICE = nRF52840_xxAA +JLINK_IF = swd + +# flash using jlink +flash: flash-jlink diff --git a/hw/bsp/feather_nrf52840_express/board_feather_nrf52840_express.c b/hw/bsp/feather_nrf52840_express/board_feather_nrf52840_express.c new file mode 100644 index 000000000..aed869afe --- /dev/null +++ b/hw/bsp/feather_nrf52840_express/board_feather_nrf52840_express.c @@ -0,0 +1,197 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2018, hathach (tinyusb.org) + * + * 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. + * + * This file is part of the TinyUSB stack. + */ + +#include "bsp/board.h" + +#include "nrfx.h" +#include "nrfx/hal/nrf_gpio.h" +#include "nrfx/drivers/include/nrfx_power.h" +#include "nrfx/drivers/include/nrfx_qspi.h" + +#ifdef SOFTDEVICE_PRESENT +#include "nrf_sdm.h" +#include "nrf_soc.h" +#endif + +/*------------------------------------------------------------------*/ +/* MACRO TYPEDEF CONSTANT ENUM + *------------------------------------------------------------------*/ +#define _PINNUM(port, pin) ((port)*32 + (pin)) + +#define LED_PIN _PINNUM(1, 15) +#define LED_STATE_ON 1 + +#define BUTTON_PIN _PINNUM(1, 02) + +/*------------------------------------------------------------------*/ +/* TUSB HAL MILLISECOND + *------------------------------------------------------------------*/ +#if CFG_TUSB_OS == OPT_OS_NONE +volatile uint32_t system_ticks = 0; + +void SysTick_Handler (void) +{ + system_ticks++; +} + +uint32_t board_millis(void) +{ + return system_ticks; +} + +#endif + +/*------------------------------------------------------------------*/ +/* BOARD API + *------------------------------------------------------------------*/ + +// tinyusb function that handles power event (detected, ready, removed) +// We must call it within SD's SOC event handler, or set it as power event handler if SD is not enabled. +extern void tusb_hal_nrf_power_event(uint32_t event); + +void board_init(void) +{ + // Config clock source: XTAL or RC in sdk_config.h + NRF_CLOCK->LFCLKSRC = (uint32_t)((CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos) & CLOCK_LFCLKSRC_SRC_Msk); + NRF_CLOCK->TASKS_LFCLKSTART = 1UL; + + // LED + nrf_gpio_cfg_output(LED_PIN); + board_led_write(false); + + // Button + nrf_gpio_cfg_input(BUTTON_PIN, NRF_GPIO_PIN_PULLUP); + +#if CFG_TUSB_OS == OPT_OS_NONE + // 1ms tick timer + SysTick_Config(SystemCoreClock/1000); +#endif + + // Priorities 0, 1, 4 (nRF52) are reserved for SoftDevice + // 2 is highest for application + NVIC_SetPriority(USBD_IRQn, 2); + + // USB power may already be ready at this time -> no event generated + // We need to invoke the handler based on the status initially + uint32_t usb_reg; + +#ifdef SOFTDEVICE_PRESENT + uint8_t sd_en = false; + sd_softdevice_is_enabled(&sd_en); + + if ( sd_en ) { + sd_power_usbdetected_enable(true); + sd_power_usbpwrrdy_enable(true); + sd_power_usbremoved_enable(true); + + sd_power_usbregstatus_get(&usb_reg); + }else +#endif + { + // Power module init + const nrfx_power_config_t pwr_cfg = { 0 }; + nrfx_power_init(&pwr_cfg); + + // Register tusb function as USB power handler + const nrfx_power_usbevt_config_t config = { .handler = (nrfx_power_usb_event_handler_t) tusb_hal_nrf_power_event }; + nrfx_power_usbevt_init(&config); + + nrfx_power_usbevt_enable(); + + usb_reg = NRF_POWER->USBREGSTATUS; + } + + if ( usb_reg & POWER_USBREGSTATUS_VBUSDETECT_Msk ) tusb_hal_nrf_power_event(NRFX_POWER_USB_EVT_DETECTED); + if ( usb_reg & POWER_USBREGSTATUS_OUTPUTRDY_Msk ) tusb_hal_nrf_power_event(NRFX_POWER_USB_EVT_READY); +} + +void board_led_write(bool state) +{ + nrf_gpio_pin_write(LED_PIN, state ? LED_STATE_ON : (1-LED_STATE_ON)); +} + +uint32_t board_button_read(void) +{ + // button is active LOW + return (nrf_gpio_pin_read(BUTTON_PIN) ? 0 : 1); +} + +int board_uart_read(uint8_t* buf, int len) +{ + (void) buf; + (void) len; + return 0; +} + +int board_uart_write(void const * buf, int len) +{ + (void) buf; + (void) len; + return 0; +} + +#ifdef SOFTDEVICE_PRESENT +// process SOC event from SD +uint32_t proc_soc(void) +{ + uint32_t soc_evt; + uint32_t err = sd_evt_get(&soc_evt); + + if (NRF_SUCCESS == err) + { + /*------------- usb power event handler -------------*/ + int32_t usbevt = (soc_evt == NRF_EVT_POWER_USB_DETECTED ) ? NRFX_POWER_USB_EVT_DETECTED: + (soc_evt == NRF_EVT_POWER_USB_POWER_READY) ? NRFX_POWER_USB_EVT_READY : + (soc_evt == NRF_EVT_POWER_USB_REMOVED ) ? NRFX_POWER_USB_EVT_REMOVED : -1; + + if ( usbevt >= 0) tusb_hal_nrf_power_event(usbevt); + } + + return err; +} + +uint32_t proc_ble(void) +{ + // do nothing with ble + return NRF_ERROR_NOT_FOUND; +} + +void SD_EVT_IRQHandler(void) +{ + // process BLE and SOC until there is no more events + while( (NRF_ERROR_NOT_FOUND != proc_ble()) || (NRF_ERROR_NOT_FOUND != proc_soc()) ) + { + + } +} + +void nrf_error_cb(uint32_t id, uint32_t pc, uint32_t info) +{ + (void) id; + (void) pc; + (void) info; +} +#endif diff --git a/hw/bsp/metro_m0_express/board.mk b/hw/bsp/metro_m0_express/board.mk index 98c4401d2..76614d2ad 100644 --- a/hw/bsp/metro_m0_express/board.mk +++ b/hw/bsp/metro_m0_express/board.mk @@ -23,20 +23,26 @@ SRC_C += \ hw/mcu/microchip/samd/asf4/samd21/hal/src/hal_atomic.c INC += \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd21/ \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd21/config \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd21/include \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd21/hal/include \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd21/hal/utils/include \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd51/hpl/pm/ \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd21/hpl/port \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd21/hri \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd21/CMSIS/Include + $(TOP)/hw/mcu/microchip/samd/asf4/samd21/ \ + $(TOP)/hw/mcu/microchip/samd/asf4/samd21/config \ + $(TOP)/hw/mcu/microchip/samd/asf4/samd21/include \ + $(TOP)/hw/mcu/microchip/samd/asf4/samd21/hal/include \ + $(TOP)/hw/mcu/microchip/samd/asf4/samd21/hal/utils/include \ + $(TOP)/hw/mcu/microchip/samd/asf4/samd51/hpl/pm/ \ + $(TOP)/hw/mcu/microchip/samd/asf4/samd21/hpl/port \ + $(TOP)/hw/mcu/microchip/samd/asf4/samd21/hri \ + $(TOP)/hw/mcu/microchip/samd/asf4/samd21/CMSIS/Include +# For TinyUSB port source VENDOR = microchip CHIP_FAMILY = samd21 +# For freeRTOS port source +FREERTOS_PORT = ARM_CM0 + +# For flash-jlink target JLINK_DEVICE = ATSAMD21G18 +JLINK_IF = swd # flash using jlink flash: flash-jlink diff --git a/hw/bsp/metro_m4_express/board.mk b/hw/bsp/metro_m4_express/board.mk index a0c94c448..2063d9ea0 100644 --- a/hw/bsp/metro_m4_express/board.mk +++ b/hw/bsp/metro_m4_express/board.mk @@ -25,19 +25,25 @@ SRC_C += \ hw/mcu/microchip/samd/asf4/samd51/hal/src/hal_atomic.c INC += \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd51/ \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd51/config \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd51/include \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd51/hal/include \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd51/hal/utils/include \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd51/hpl/port \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd51/hri \ - -I$(TOP)/hw/mcu/microchip/samd/asf4/samd51/CMSIS/Include + $(TOP)/hw/mcu/microchip/samd/asf4/samd51/ \ + $(TOP)/hw/mcu/microchip/samd/asf4/samd51/config \ + $(TOP)/hw/mcu/microchip/samd/asf4/samd51/include \ + $(TOP)/hw/mcu/microchip/samd/asf4/samd51/hal/include \ + $(TOP)/hw/mcu/microchip/samd/asf4/samd51/hal/utils/include \ + $(TOP)/hw/mcu/microchip/samd/asf4/samd51/hpl/port \ + $(TOP)/hw/mcu/microchip/samd/asf4/samd51/hri \ + $(TOP)/hw/mcu/microchip/samd/asf4/samd51/CMSIS/Include +# For TinyUSB port source VENDOR = microchip CHIP_FAMILY = samd51 +# For freeRTOS port source +FREERTOS_PORT = ARM_CM4F + +# For flash-jlink target JLINK_DEVICE = ATSAMD51J19 +JLINK_IF = swd # flash using jlink flash: flash-jlink diff --git a/hw/bsp/pca10056/board.mk b/hw/bsp/pca10056/board.mk index 9dc02ed11..317a4969f 100644 --- a/hw/bsp/pca10056/board.mk +++ b/hw/bsp/pca10056/board.mk @@ -1,11 +1,12 @@ CFLAGS += \ - -DCFG_TUSB_MCU=OPT_MCU_NRF5X \ - -DNRF52840_XXAA \ -mthumb \ -mabi=aapcs \ -mcpu=cortex-m4 \ -mfloat-abi=hard \ - -mfpu=fpv4-sp-d16 + -mfpu=fpv4-sp-d16 \ + -DCFG_TUSB_MCU=OPT_MCU_NRF5X \ + -DNRF52840_XXAA \ + -DCONFIG_GPIO_AS_PINRESET # nrfx issue undef _ARMCC_VERSION usage https://github.com/NordicSemiconductor/nrfx/issues/49 CFLAGS += -Wno-error=undef @@ -23,27 +24,31 @@ SRC_C += \ SRC_C += src/portable/$(VENDOR)/$(CHIP_FAMILY)/hal_$(CHIP_FAMILY).c INC += \ - -I$(TOP)/hw/cmsis/Include \ - -I$(TOP)/hw/mcu/nordic \ - -I$(TOP)/hw/mcu/nordic/nrfx \ - -I$(TOP)/hw/mcu/nordic/nrfx/mdk \ - -I$(TOP)/hw/mcu/nordic/nrfx/hal \ - -I$(TOP)/hw/mcu/nordic/nrfx/drivers/include \ - -I$(TOP)/hw/mcu/nordic/nrfx/drivers/src \ + $(TOP)/hw/cmsis/Include \ + $(TOP)/hw/mcu/nordic \ + $(TOP)/hw/mcu/nordic/nrfx \ + $(TOP)/hw/mcu/nordic/nrfx/mdk \ + $(TOP)/hw/mcu/nordic/nrfx/hal \ + $(TOP)/hw/mcu/nordic/nrfx/drivers/include \ + $(TOP)/hw/mcu/nordic/nrfx/drivers/src \ SRC_S += hw/mcu/nordic/nrfx/mdk/gcc_startup_nrf52840.S ASFLAGS += -D__HEAP_SIZE=0 -ASFLAGS += -DCONFIG_GPIO_AS_PINRESET -ASFLAGS += -DBLE_STACK_SUPPORT_REQD ASFLAGS += -DSWI_DISABLE0 ASFLAGS += -DFLOAT_ABI_HARD ASFLAGS += -DNRF52840_XXAA +# For TinyUSB port source VENDOR = nordic CHIP_FAMILY = nrf5x +# For freeRTOS port source +FREERTOS_PORT = ARM_CM4F + +# For flash-jlink target JLINK_DEVICE = nRF52840_xxAA +JLINK_IF = swd # flash using jlink flash: flash-jlink diff --git a/hw/bsp/stm32f303disc/board.mk b/hw/bsp/stm32f303disc/board.mk index c81717c49..8efa5e6ab 100644 --- a/hw/bsp/stm32f303disc/board.mk +++ b/hw/bsp/stm32f303disc/board.mk @@ -25,15 +25,21 @@ SRC_S += \ hw/mcu/st/startup/stm32f3/startup_stm32f303xc.s INC += \ - -I$(TOP)/hw/bsp/stm32f303disc \ - -I$(TOP)/hw/mcu/st/cmsis \ - -I$(TOP)/hw/mcu/st/stm32lib/CMSIS/STM32F3xx/Include \ - -I$(TOP)/hw/mcu/st/stm32lib/STM32F3xx_HAL_Driver/Inc + $(TOP)/hw/bsp/stm32f303disc \ + $(TOP)/hw/mcu/st/cmsis \ + $(TOP)/hw/mcu/st/stm32lib/CMSIS/STM32F3xx/Include \ + $(TOP)/hw/mcu/st/stm32lib/STM32F3xx_HAL_Driver/Inc +# For TinyUSB port source VENDOR = st CHIP_FAMILY = stm32f3 +# For freeRTOS port source +FREERTOS_PORT = ARM_CM4F + +# For flash-jlink target JLINK_DEVICE = stm32f303vc +JLINK_IF = swd # Path to STM32 Cube Programmer CLI, should be added into system path STM32Prog = STM32_Programmer_CLI diff --git a/hw/bsp/stm32f407g_disc1/board.mk b/hw/bsp/stm32f407g_disc1/board.mk index e966f998c..ad13c1047 100644 --- a/hw/bsp/stm32f407g_disc1/board.mk +++ b/hw/bsp/stm32f407g_disc1/board.mk @@ -21,13 +21,19 @@ SRC_S += \ hw/mcu/st/startup/stm32f4/startup_stm32f407xx.s INC += \ - -I$(TOP)/hw/mcu/st/stm32lib/CMSIS/STM32F4xx/Include \ - -I$(TOP)/hw/mcu/st/cmsis + $(TOP)/hw/mcu/st/stm32lib/CMSIS/STM32F4xx/Include \ + $(TOP)/hw/mcu/st/cmsis +# For TinyUSB port source VENDOR = st CHIP_FAMILY = stm32f4 +# For freeRTOS port source +FREERTOS_PORT = ARM_CM4F + +# For flash-jlink target JLINK_DEVICE = stm32f407vg +JLINK_IF = swd # Path to STM32 Cube Programmer CLI, should be added into system path STM32Prog = STM32_Programmer_CLI diff --git a/examples/device/cdc_msc_hid_freertos/ses/nrf5x/FreeRTOSConfig.h b/hw/mcu/nordic/FreeRTOSConfig.h similarity index 98% rename from examples/device/cdc_msc_hid_freertos/ses/nrf5x/FreeRTOSConfig.h rename to hw/mcu/nordic/FreeRTOSConfig.h index 754158622..53f72a062 100644 --- a/examples/device/cdc_msc_hid_freertos/ses/nrf5x/FreeRTOSConfig.h +++ b/hw/mcu/nordic/FreeRTOSConfig.h @@ -69,7 +69,7 @@ /* Hook function related definitions. */ #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 -#define configUSE_MALLOC_FAILED_HOOK 1 +#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning #define configCHECK_FOR_STACK_OVERFLOW 2 /* Run time and task stats gathering related definitions. */ diff --git a/hw/mcu/nordic/nrfx b/hw/mcu/nordic/nrfx index 6f54f689e..9d68726e4 160000 --- a/hw/mcu/nordic/nrfx +++ b/hw/mcu/nordic/nrfx @@ -1 +1 @@ -Subproject commit 6f54f689e9555ea18f9aca87caf44a3419e5dd7a +Subproject commit 9d68726e41c321f1772c187bd12d82f5b13104f1 diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index c194aacd8..7a0380e6b 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -71,7 +71,7 @@ typedef struct //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC] = { { 0 } }; +CFG_TUSB_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; // TODO will be replaced by dcd_edpt_busy() bool pending_read_from_host; @@ -289,14 +289,12 @@ bool cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) ) { // next to endpoint descriptor - (*p_length) += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); - // Open endpoint pair with usbd helper - tusb_desc_endpoint_t const *p_desc_ep = (tusb_desc_endpoint_t const *) p_desc; - TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc_ep, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in) ); + // Open endpoint pair + TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &p_cdc->ep_out, &p_cdc->ep_in) ); - (*p_length) += 2*sizeof(tusb_desc_endpoint_t); + (*p_length) += sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t); } // Prepare for incoming data diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index 6c59bac7a..18d6f842f 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -89,9 +89,17 @@ static inline bool tud_cdc_write_flush (void) //--------------------------------------------------------------------+ // APPLICATION CALLBACK API (WEAK is optional) //--------------------------------------------------------------------+ + +// Invoked when received new data ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf); + +// Invoked when received `wanted_char` ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char); + +// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts); + +// Invoked when line coding is change via SET_LINE_CODING ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding); /** @} */ diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h index 637f13295..7c702f4de 100644 --- a/src/class/hid/hid.h +++ b/src/class/hid/hid.h @@ -43,6 +43,20 @@ /** \defgroup ClassDriver_HID_Common Common Definitions * @{ */ + /// USB HID Descriptor +typedef struct ATTR_PACKED +{ + uint8_t bLength; /**< Numeric expression that is the total size of the HID descriptor */ + uint8_t bDescriptorType; /**< Constant name specifying type of HID descriptor. */ + + uint16_t bcdHID; /**< Numeric expression identifying the HID Class Specification release */ + uint8_t bCountryCode; /**< Numeric expression identifying country code of the localized hardware. */ + uint8_t bNumDescriptors; /**< Numeric expression specifying the number of class descriptors */ + + uint8_t bReportType; /**< Type of HID class report. */ + uint16_t wReportLength; /**< the total size of the Report descriptor. */ +} tusb_hid_descriptor_hid_t; + /// HID Subclass typedef enum { @@ -69,9 +83,10 @@ typedef enum /// HID Request Report Type typedef enum { - HID_REPORT_TYPE_INPUT = 1, ///< Input - HID_REPORT_TYPE_OUTPUT, ///< Output - HID_REPORT_TYPE_FEATURE ///< Feature + HID_REPORT_TYPE_INVALID = 0, + HID_REPORT_TYPE_INPUT, ///< Input + HID_REPORT_TYPE_OUTPUT, ///< Output + HID_REPORT_TYPE_FEATURE ///< Feature }hid_report_type_t; /// HID Class Specific Control Request @@ -85,59 +100,45 @@ typedef enum HID_REQ_CONTROL_SET_PROTOCOL = 0x0b ///< Set Protocol }hid_request_type_t; -/// USB HID Descriptor -typedef struct ATTR_PACKED -{ - uint8_t bLength; /**< Numeric expression that is the total size of the HID descriptor */ - uint8_t bDescriptorType; /**< Constant name specifying type of HID descriptor. */ - - uint16_t bcdHID; /**< Numeric expression identifying the HID Class Specification release */ - uint8_t bCountryCode; /**< Numeric expression identifying country code of the localized hardware. */ - uint8_t bNumDescriptors; /**< Numeric expression specifying the number of class descriptors */ - - uint8_t bReportType; /**< Type of HID class report. */ - uint16_t wReportLength; /**< the total size of the Report descriptor. */ -} tusb_hid_descriptor_hid_t; - /// HID Country Code typedef enum { - HID_Local_NotSupported = 0 , ///< NotSupported - HID_Local_Arabic , ///< Arabic - HID_Local_Belgian , ///< Belgian - HID_Local_Canadian_Bilingual , ///< Canadian_Bilingual - HID_Local_Canadian_French , ///< Canadian_French - HID_Local_Czech_Republic , ///< Czech_Republic - HID_Local_Danish , ///< Danish - HID_Local_Finnish , ///< Finnish - HID_Local_French , ///< French - HID_Local_German , ///< German - HID_Local_Greek , ///< Greek - HID_Local_Hebrew , ///< Hebrew - HID_Local_Hungary , ///< Hungary - HID_Local_International , ///< International - HID_Local_Italian , ///< Italian - HID_Local_Japan_Katakana , ///< Japan_Katakana - HID_Local_Korean , ///< Korean - HID_Local_Latin_American , ///< Latin_American - HID_Local_Netherlands_Dutch , ///< Netherlands/Dutch - HID_Local_Norwegian , ///< Norwegian - HID_Local_Persian_Farsi , ///< Persian (Farsi) - HID_Local_Poland , ///< Poland - HID_Local_Portuguese , ///< Portuguese - HID_Local_Russia , ///< Russia - HID_Local_Slovakia , ///< Slovakia - HID_Local_Spanish , ///< Spanish - HID_Local_Swedish , ///< Swedish - HID_Local_Swiss_French , ///< Swiss/French - HID_Local_Swiss_German , ///< Swiss/German - HID_Local_Switzerland , ///< Switzerland - HID_Local_Taiwan , ///< Taiwan - HID_Local_Turkish_Q , ///< Turkish-Q - HID_Local_UK , ///< UK - HID_Local_US , ///< US - HID_Local_Yugoslavia , ///< Yugoslavia - HID_Local_Turkish_F ///< Turkish-F + HID_LOCAL_NotSupported = 0 , ///< NotSupported + HID_LOCAL_Arabic , ///< Arabic + HID_LOCAL_Belgian , ///< Belgian + HID_LOCAL_Canadian_Bilingual , ///< Canadian_Bilingual + HID_LOCAL_Canadian_French , ///< Canadian_French + HID_LOCAL_Czech_Republic , ///< Czech_Republic + HID_LOCAL_Danish , ///< Danish + HID_LOCAL_Finnish , ///< Finnish + HID_LOCAL_French , ///< French + HID_LOCAL_German , ///< German + HID_LOCAL_Greek , ///< Greek + HID_LOCAL_Hebrew , ///< Hebrew + HID_LOCAL_Hungary , ///< Hungary + HID_LOCAL_International , ///< International + HID_LOCAL_Italian , ///< Italian + HID_LOCAL_Japan_Katakana , ///< Japan_Katakana + HID_LOCAL_Korean , ///< Korean + HID_LOCAL_Latin_American , ///< Latin_American + HID_LOCAL_Netherlands_Dutch , ///< Netherlands/Dutch + HID_LOCAL_Norwegian , ///< Norwegian + HID_LOCAL_Persian_Farsi , ///< Persian (Farsi) + HID_LOCAL_Poland , ///< Poland + HID_LOCAL_Portuguese , ///< Portuguese + HID_LOCAL_Russia , ///< Russia + HID_LOCAL_Slovakia , ///< Slovakia + HID_LOCAL_Spanish , ///< Spanish + HID_LOCAL_Swedish , ///< Swedish + HID_LOCAL_Swiss_French , ///< Swiss/French + HID_LOCAL_Swiss_German , ///< Swiss/German + HID_LOCAL_Switzerland , ///< Switzerland + HID_LOCAL_Taiwan , ///< Taiwan + HID_LOCAL_Turkish_Q , ///< Turkish-Q + HID_LOCAL_UK , ///< UK + HID_LOCAL_US , ///< US + HID_LOCAL_Yugoslavia , ///< Yugoslavia + HID_LOCAL_Turkish_F ///< Turkish-F } hid_country_code_t; /** @} */ @@ -155,7 +156,7 @@ typedef struct ATTR_PACKED int8_t x; /**< Current delta x movement of the mouse. */ int8_t y; /**< Current delta y movement on the mouse. */ int8_t wheel; /**< Current delta wheel movement on the mouse. */ -// int8_t pan; + int8_t pan; // using AC Pan } hid_mouse_report_t; /// Standard Mouse Buttons Bitmap @@ -461,7 +462,7 @@ enum { HID_USAGE_PAGE_MSR = 0x8e, HID_USAGE_PAGE_CAMERA = 0x90, HID_USAGE_PAGE_ARCADE = 0x91, - HID_USAGE_PAGE_VENDOR = 0xFFFF // 0xFF00 - 0xFFFF + HID_USAGE_PAGE_VENDOR = 0xFF00 // 0xFF00 - 0xFFFF }; /// HID Usage Table - Table 6: Generic Desktop Page diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index 78def53f0..e82932e1f 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -38,24 +38,19 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ - -#ifndef CFG_TUD_HID_BUFSIZE -#define CFG_TUD_HID_BUFSIZE 16 -#endif - typedef struct { uint8_t itf_num; uint8_t ep_in; + uint8_t ep_out; // optional Out endpoint uint8_t boot_protocol; // Boot mouse or keyboard - bool boot_mode; - + bool boot_mode; // default = false (Report) + uint8_t idle_rate; // up to application to handle idle rate uint16_t reprot_desc_len; - uint8_t idle_rate; // Idle Rate = 0 : only send report if there is changes, i.e skip duplication - // Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms). - uint8_t mouse_button; // caching button for using with tud_hid_mouse_ API - CFG_TUSB_MEM_ALIGN uint8_t report_buf[CFG_TUD_HID_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_BUFSIZE]; + CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_BUFSIZE]; + }hidd_interface_t; CFG_TUSB_MEM_SECTION static hidd_interface_t _hidd_itf[CFG_TUD_HID]; @@ -91,15 +86,15 @@ bool tud_hid_report(uint8_t report_id, void const* report, uint8_t len) // If report id = 0, skip ID field if (report_id) { - p_hid->report_buf[0] = report_id; - memcpy(p_hid->report_buf+1, report, len); + p_hid->epin_buf[0] = report_id; + memcpy(p_hid->epin_buf+1, report, len); + len++; }else { - memcpy(p_hid->report_buf, report, len); + memcpy(p_hid->epin_buf, report, len); } - // TODO skip duplication ? and or idle rate - return dcd_edpt_xfer(TUD_OPT_RHPORT, p_hid->ep_in, p_hid->report_buf, len + (report_id ? 1 : 0) ); + return dcd_edpt_xfer(TUD_OPT_RHPORT, p_hid->ep_in, p_hid->epin_buf, len); } bool tud_hid_boot_mode(void) @@ -125,47 +120,26 @@ bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycod tu_memclr(report.keycode, 6); } - // TODO skip duplication ? and or idle rate return tud_hid_report(report_id, &report, sizeof(report)); } //--------------------------------------------------------------------+ // MOUSE APPLICATION API //--------------------------------------------------------------------+ -bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t scroll, int8_t pan) +bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal) { - (void) pan; hid_mouse_report_t report = { .buttons = buttons, .x = x, .y = y, - .wheel = scroll, - //.pan = pan + .wheel = vertical, + .pan = horizontal }; - uint8_t itf = 0; - _hidd_itf[itf].mouse_button = buttons; - return tud_hid_report(report_id, &report, sizeof(report)); } -bool tud_hid_mouse_move(uint8_t report_id, int8_t x, int8_t y) -{ - uint8_t itf = 0; - uint8_t const button = _hidd_itf[itf].mouse_button; - - return tud_hid_mouse_report(report_id, button, x, y, 0, 0); -} - -bool tud_hid_mouse_scroll(uint8_t report_id, int8_t scroll, int8_t pan) -{ - uint8_t itf = 0; - uint8_t const button = _hidd_itf[itf].mouse_button; - - return tud_hid_mouse_report(report_id, button, 0, 0, scroll, pan); -} - //--------------------------------------------------------------------+ // USBD-CLASS API //--------------------------------------------------------------------+ @@ -184,6 +158,10 @@ bool hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t { uint8_t const *p_desc = (uint8_t const *) desc_itf; + // TODO support multiple HID interface + uint8_t const itf = 0; + hidd_interface_t * p_hid = &_hidd_itf[itf]; + //------------- HID descriptor -------------// p_desc = tu_desc_next(p_desc); tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc; @@ -191,24 +169,19 @@ bool hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t //------------- Endpoint Descriptor -------------// p_desc = tu_desc_next(p_desc); - tusb_desc_endpoint_t const *desc_edpt = (tusb_desc_endpoint_t const *) p_desc; - TU_ASSERT(TUSB_DESC_ENDPOINT == desc_edpt->bDescriptorType); - - TU_ASSERT(dcd_edpt_open(rhport, desc_edpt)); - - // TODO support multiple HID interface - uint8_t itf = 0; - hidd_interface_t * p_hid = &_hidd_itf[itf]; + TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_INTERRUPT, &p_hid->ep_out, &p_hid->ep_in)); if ( desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT ) p_hid->boot_protocol = desc_itf->bInterfaceProtocol; p_hid->boot_mode = false; // default mode is REPORT p_hid->itf_num = desc_itf->bInterfaceNumber; - p_hid->ep_in = desc_edpt->bEndpointAddress; p_hid->reprot_desc_len = desc_hid->wReportLength; *p_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t); + // Prepare for output endpoint + if (p_hid->ep_out) TU_ASSERT(dcd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))); + return true; } @@ -245,20 +218,25 @@ bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque uint8_t const report_type = tu_u16_high(p_request->wValue); uint8_t const report_id = tu_u16_low(p_request->wValue); - uint16_t xferlen = tud_hid_get_report_cb(report_id, (hid_report_type_t) report_type, p_hid->report_buf, p_request->wLength); + uint16_t xferlen = tud_hid_get_report_cb(report_id, (hid_report_type_t) report_type, p_hid->epin_buf, p_request->wLength); TU_ASSERT( xferlen > 0 ); - usbd_control_xfer(rhport, p_request, p_hid->report_buf, xferlen); + usbd_control_xfer(rhport, p_request, p_hid->epin_buf, xferlen); } break; case HID_REQ_CONTROL_SET_REPORT: - usbd_control_xfer(rhport, p_request, p_hid->report_buf, p_request->wLength); + usbd_control_xfer(rhport, p_request, p_hid->epout_buf, p_request->wLength); break; case HID_REQ_CONTROL_SET_IDLE: - // TODO idle rate of report p_hid->idle_rate = tu_u16_high(p_request->wValue); + if ( tud_hid_set_idle_cb ) + { + // stall request if callback return false + if ( !tud_hid_set_idle_cb(p_hid->idle_rate) ) return false; + } + usbd_control_status(rhport, p_request); break; @@ -277,7 +255,7 @@ bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque case HID_REQ_CONTROL_SET_PROTOCOL: p_hid->boot_mode = 1 - p_request->wValue; // 0 is Boot, 1 is Report protocol - if (tud_hid_mode_changed_cb) tud_hid_mode_changed_cb(p_hid->boot_mode); + if (tud_hid_boot_mode_cb) tud_hid_boot_mode_cb(p_hid->boot_mode); usbd_control_status(rhport, p_request); break; @@ -307,19 +285,25 @@ bool hidd_control_request_complete(uint8_t rhport, tusb_control_request_t const uint8_t const report_type = tu_u16_high(p_request->wValue); uint8_t const report_id = tu_u16_low(p_request->wValue); - tud_hid_set_report_cb(report_id, (hid_report_type_t) report_type, p_hid->report_buf, p_request->wLength); + tud_hid_set_report_cb(report_id, (hid_report_type_t) report_type, p_hid->epout_buf, p_request->wLength); } return true; } -bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { - // nothing to do - (void) rhport; - (void) ep_addr; - (void) event; - (void) xferred_bytes; + (void) result; + + // TODO support multiple HID interface + uint8_t const itf = 0; + hidd_interface_t * p_hid = &_hidd_itf[itf]; + + if (ep_addr == p_hid->ep_out) + { + tud_hid_set_report_cb(0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, xferred_bytes); + TU_ASSERT(dcd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))); + } return true; } diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index 13a213277..825be2181 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -39,6 +39,9 @@ // Class Driver Default Configure & Validation //--------------------------------------------------------------------+ +#ifndef CFG_TUD_HID_BUFSIZE +#define CFG_TUD_HID_BUFSIZE 16 +#endif //--------------------------------------------------------------------+ // Application API @@ -53,51 +56,34 @@ bool tud_hid_boot_mode(void); // Send report to host bool tud_hid_report(uint8_t report_id, void const* report, uint8_t len); -/*------------- Callbacks (Weak is optional) -------------*/ +// KEYBOARD: convenient helper to send keyboard report if application +// use template layout report as defined by hid_keyboard_report_t +bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]); -// Invoked when receiving GET_REPORT control request +// MOUSE: convenient helper to send mouse report if application +// use template layout report as defined by hid_mouse_report_t +bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal); + +//--------------------------------------------------------------------+ +// Callbacks (Weak is optional) +//--------------------------------------------------------------------+ + +// Invoked when received GET_REPORT control request // Application must fill buffer report's content and return its length. // Return zero will cause the stack to STALL request uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen); -// Invoked when receiving SET_REPORT control request +// Invoked when received SET_REPORT control request or +// received data on OUT endpoint ( Report ID = 0, Type = 0 ) void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize); -// Invoked when host switch mode Boot <-> Report via SET_PROTOCOL request -void tud_hid_mode_changed_cb(uint8_t boot_mode) ATTR_WEAK; +// Invoked when received SET_PROTOCOL request ( mode switch Boot <-> Report ) +ATTR_WEAK void tud_hid_boot_mode_cb(uint8_t boot_mode); -//--------------------------------------------------------------------+ -// KEYBOARD API -// Convenient helper to send keyboard report if application use standard/boot -// layout report as defined by hid_keyboard_report_t -//--------------------------------------------------------------------+ - -bool tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]); - -static inline bool tud_hid_keyboard_key_release(uint8_t report_id) -{ - return tud_hid_keyboard_report(report_id, 0, NULL); -} - -//--------------------------------------------------------------------+ -// MOUSE API -// Convenient helper to send mouse report if application use standard/boot -// layout report as defined by hid_mouse_report_t -//--------------------------------------------------------------------+ - -bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t scroll, int8_t pan); -bool tud_hid_mouse_move(uint8_t report_id, int8_t x, int8_t y); -bool tud_hid_mouse_scroll(uint8_t report_id, int8_t scroll, int8_t pan); - -static inline bool tud_hid_mouse_button_press(uint8_t report_id, uint8_t buttons) -{ - return tud_hid_mouse_report(report_id, buttons, 0, 0, 0, 0); -} - -static inline bool tud_hid_mouse_button_release(uint8_t report_id) -{ - return tud_hid_mouse_report(report_id, 0, 0, 0, 0, 0); -} +// Invoked when received SET_IDLE request. return false will stall the request +// - Idle Rate = 0 : only send report if there is changes, i.e skip duplication +// - Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms). +ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t idle_rate); /* --------------------------------------------------------------------+ * HID Report Descriptor Template @@ -107,23 +93,24 @@ static inline bool tud_hid_mouse_button_release(uint8_t report_id) * empty if multiple reports is not used * * - Only 1 report: no parameter - * uint8_t const report_desc[] = { HID_REPORT_DESC_KEYBOARD() }; + * uint8_t const report_desc[] = { TUD_HID_REPORT_DESC_KEYBOARD() }; * * - Multiple Reports: "HID_REPORT_ID(ID)," must be passed to template * uint8_t const report_desc[] = * { - * HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(1), ) , - * HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(2), ) + * TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(1), ) , + * TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(2), ) * }; *--------------------------------------------------------------------*/ // Keyboard Report Descriptor Template -#define HID_REPORT_DESC_KEYBOARD(...) \ +#define TUD_HID_REPORT_DESC_KEYBOARD(...) \ HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ HID_USAGE ( HID_USAGE_DESKTOP_KEYBOARD ) ,\ HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ - /* 8 bits Modifier Keys (Shfit, Control, Alt) */ \ + /* Report ID if any */\ __VA_ARGS__ \ + /* 8 bits Modifier Keys (Shfit, Control, Alt) */ \ HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\ HID_USAGE_MIN ( 224 ) ,\ HID_USAGE_MAX ( 231 ) ,\ @@ -159,50 +146,60 @@ static inline bool tud_hid_mouse_button_release(uint8_t report_id) HID_COLLECTION_END \ // Mouse Report Descriptor Template -#define HID_REPORT_DESC_MOUSE(...) \ - HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ) ,\ - HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ +#define TUD_HID_REPORT_DESC_MOUSE(...) \ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ) ,\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ __VA_ARGS__ \ - HID_USAGE ( HID_USAGE_DESKTOP_POINTER ) ,\ - HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\ - HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\ - HID_USAGE_MIN ( 1 ) ,\ - HID_USAGE_MAX ( 3 ) ,\ - HID_LOGICAL_MIN ( 0 ) ,\ - HID_LOGICAL_MAX ( 1 ) ,\ - /* Left, Right, Middle, Backward, Forward mouse buttons */ \ - HID_REPORT_COUNT ( 3 ) ,\ - HID_REPORT_SIZE ( 1 ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_POINTER ) ,\ + HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\ + HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\ + HID_USAGE_MIN ( 1 ) ,\ + HID_USAGE_MAX ( 5 ) ,\ + HID_LOGICAL_MIN ( 0 ) ,\ + HID_LOGICAL_MAX ( 1 ) ,\ + /* Left, Right, Middle, Backward, Forward buttons */ \ + HID_REPORT_COUNT( 5 ) ,\ + HID_REPORT_SIZE ( 1 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ /* 3 bit padding */ \ - HID_REPORT_COUNT ( 1 ) ,\ - HID_REPORT_SIZE ( 5 ) ,\ - HID_INPUT ( HID_CONSTANT ) ,\ - HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ + HID_REPORT_COUNT( 1 ) ,\ + HID_REPORT_SIZE ( 3 ) ,\ + HID_INPUT ( HID_CONSTANT ) ,\ + HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ /* X, Y position [-127, 127] */ \ - HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\ - HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\ - HID_LOGICAL_MIN ( 0x81 ) ,\ - HID_LOGICAL_MAX ( 0x7f ) ,\ - HID_REPORT_COUNT ( 2 ) ,\ - HID_REPORT_SIZE ( 8 ) ,\ - HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\ - /* Mouse scroll [-127, 127] */ \ + HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\ + HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\ + HID_LOGICAL_MIN ( 0x81 ) ,\ + HID_LOGICAL_MAX ( 0x7f ) ,\ + HID_REPORT_COUNT( 2 ) ,\ + HID_REPORT_SIZE ( 8 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\ + /* Verital wheel scroll [-127, 127] */ \ HID_USAGE ( HID_USAGE_DESKTOP_WHEEL ) ,\ HID_LOGICAL_MIN ( 0x81 ) ,\ HID_LOGICAL_MAX ( 0x7f ) ,\ HID_REPORT_COUNT( 1 ) ,\ HID_REPORT_SIZE ( 8 ) ,\ HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\ - HID_COLLECTION_END ,\ + HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ), \ + /* Horizontal wheel scroll [-127, 127] */ \ + HID_USAGE_N ( HID_USAGE_CONSUMER_AC_PAN, 2 ), \ + HID_LOGICAL_MIN ( 0x81 ), \ + HID_LOGICAL_MAX ( 0x7f ), \ + HID_REPORT_COUNT( 1 ), \ + HID_REPORT_SIZE ( 8 ), \ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \ + HID_COLLECTION_END , \ HID_COLLECTION_END \ // Consumer Control Report Descriptor Template -#define HID_REPORT_DESC_CONSUMER(...) \ +#define TUD_HID_REPORT_DESC_CONSUMER(...) \ HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ) ,\ HID_USAGE ( HID_USAGE_CONSUMER_CONTROL ) ,\ HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ __VA_ARGS__ \ HID_LOGICAL_MIN ( 0x00 ) ,\ HID_LOGICAL_MAX_N( 0x03FF, 2 ) ,\ @@ -219,10 +216,11 @@ static inline bool tud_hid_mouse_button_release(uint8_t report_id) * 0x02 - Standby * 0x04 - Wake Host */ -#define HID_REPORT_DESC_SYSTEM_CONTROL(...) \ +#define TUD_HID_REPORT_DESC_SYSTEM_CONTROL(...) \ HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ HID_USAGE ( HID_USAGE_DESKTOP_SYSTEM_CONTROL ) ,\ HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ __VA_ARGS__ \ /* 2 bit system power control */ \ HID_LOGICAL_MIN ( 1 ) ,\ @@ -242,10 +240,11 @@ static inline bool tud_hid_mouse_button_release(uint8_t report_id) // Gamepad Report Descriptor Template // with 16 buttons and 2 joysticks with following layout // | Button Map (2 bytes) | X | Y | Z | Rz -#define HID_REPORT_DESC_GAMEPAD(...) \ +#define TUD_HID_REPORT_DESC_GAMEPAD(...) \ HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\ HID_USAGE ( HID_USAGE_DESKTOP_GAMEPAD ) ,\ HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\ + /* Report ID if any */\ __VA_ARGS__ \ /* 16 bit Button Map */ \ HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\ @@ -269,6 +268,31 @@ static inline bool tud_hid_mouse_button_release(uint8_t report_id) HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ HID_COLLECTION_END \ +// HID Generic Input & Output +// - 1st parameter is report size (mandatory) +// - 2nd parameter is report id HID_REPORT_ID(n) (optional) +#define TUD_HID_REPORT_DESC_GENERIC_INOUT(report_size, ...) \ + HID_USAGE_PAGE_N ( HID_USAGE_PAGE_VENDOR, 2 ),\ + HID_USAGE ( 0x01 ),\ + HID_COLLECTION ( HID_COLLECTION_APPLICATION ),\ + /* Report ID if any */\ + __VA_ARGS__ \ + /* Input */ \ + HID_USAGE ( 0x02 ),\ + HID_LOGICAL_MIN ( 0x00 ),\ + HID_LOGICAL_MAX ( 0xff ),\ + HID_REPORT_SIZE ( 8 ),\ + HID_REPORT_COUNT( report_size ),\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\ + /* Output */ \ + HID_USAGE ( 0x03 ),\ + HID_LOGICAL_MIN ( 0x00 ),\ + HID_LOGICAL_MAX ( 0xff ),\ + HID_REPORT_SIZE ( 8 ),\ + HID_REPORT_COUNT( report_size ),\ + HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\ + HID_COLLECTION_END \ + /*-------------------------------------------------------------------- * ASCII to KEYCODE Conversion * Expand to array of [128][2] (shift, keycode) diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index e2cf92324..f980e941e 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -42,13 +42,9 @@ enum MSC_STAGE_STATUS }; -typedef struct { - CFG_TUSB_MEM_ALIGN msc_cbw_t cbw; - -//#if defined (__ICCARM__) && (CFG_TUSB_MCU == OPT_MCU_LPC11UXX || CFG_TUSB_MCU == OPT_MCU_LPC13XX) -// uint8_t padding1[64-sizeof(msc_cbw_t)]; // IAR cannot align struct's member -//#endif - +typedef struct +{ + CFG_TUSB_MEM_ALIGN msc_cbw_t cbw; CFG_TUSB_MEM_ALIGN msc_csw_t csw; uint8_t itf_num; @@ -66,7 +62,7 @@ typedef struct { uint8_t add_sense_qualifier; }mscd_interface_t; -CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static mscd_interface_t _mscd_itf = { 0 }; +CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static mscd_interface_t _mscd_itf; CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _mscd_buf[CFG_TUD_MSC_BUFSIZE]; //--------------------------------------------------------------------+ @@ -135,9 +131,8 @@ bool mscd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t mscd_interface_t * p_msc = &_mscd_itf; - // Open endpoint pair with usbd helper - tusb_desc_endpoint_t const *p_desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next( itf_desc ); - TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc_ep, TUSB_XFER_BULK, &p_msc->ep_out, &p_msc->ep_in) ); + // Open endpoint pair + TU_ASSERT( usbd_open_edpt_pair(rhport, tu_desc_next(itf_desc), 2, TUSB_XFER_BULK, &p_msc->ep_out, &p_msc->ep_in) ); p_msc->itf_num = itf_desc->bInterfaceNumber; (*p_len) = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t); @@ -163,9 +158,12 @@ bool mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque case MSC_REQ_GET_MAX_LUN: { + uint8_t maxlun = 1; + if (tud_msc_maxlun_cb) maxlun = tud_msc_maxlun_cb(); + TU_VERIFY(maxlun); + // MAX LUN is minus 1 by specs - uint8_t maxlun = 0; - if (tud_msc_maxlun_cb) maxlun = tud_msc_maxlun_cb() -1; + maxlun--; usbd_control_xfer(rhport, p_request, &maxlun, 1); } diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index 6e3aef8bb..b1e7e8da1 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -64,10 +64,11 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_BUFSIZE < UINT16_MAX, "Size is not correct"); bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier); //--------------------------------------------------------------------+ -// APPLICATION CALLBACK (WEAK is optional) +// Application Callbacks (WEAK is optional) //--------------------------------------------------------------------+ + /** - * Callback invoked when received \ref SCSI_CMD_READ_10 command + * Invoked when received \ref SCSI_CMD_READ_10 command * \param[in] lun Logical unit number * \param[in] lba Logical Block Address to be read * \param[in] offset Byte offset from LBA @@ -86,7 +87,7 @@ bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, u int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); /** - * Callback invoked when received \ref SCSI_CMD_WRITE_10 command + * Invoked when received \ref SCSI_CMD_WRITE_10 command * \param[in] lun Logical unit number * \param[in] lba Logical Block Address to be write * \param[in] offset Byte offset from LBA @@ -104,7 +105,8 @@ int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buf */ int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); -// Invoked to determine the disk size +// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size +// Application update block count and block size void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size); /** @@ -128,13 +130,13 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, /*------------- Optional callbacks -------------*/ -// Invoked to determine max LUN +// Invoked when received GET_MAX_LUN request ATTR_WEAK uint8_t tud_msc_maxlun_cb(void); // Invoked when Read10 command is complete ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun); -// Invoke when Write10 command is complete +// Invoke when Write10 command is complete, can be used to flush flash caching ATTR_WEAK void tud_msc_write10_complete_cb(uint8_t lun); // Invoked when command in tud_msc_scsi_cb is complete diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index 7d57a7950..909deffa8 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -169,7 +169,7 @@ enum { #define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2) -/// Device State +/// Device State TODO remove typedef enum { TUSB_DEVICE_STATE_UNPLUG = 0 , @@ -184,7 +184,7 @@ typedef enum XFER_RESULT_STALLED, }xfer_result_t; -enum +enum // TODO remove { DESC_OFFSET_LEN = 0, DESC_OFFSET_TYPE = 1 diff --git a/src/device/usbd.c b/src/device/usbd.c index f02b21208..d811c471a 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -702,25 +702,25 @@ void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_ // Helper //--------------------------------------------------------------------+ -// Helper to parse an pair of endpoint descriptors (IN & OUT) -bool usbd_open_edpt_pair(uint8_t rhport, tusb_desc_endpoint_t const* ep_desc, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in) +// Parse consecutive endpoint descriptors (IN & OUT) +bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in) { - for(int i=0; i<2; i++) + for(int i=0; ibDescriptorType && - xfer_type == ep_desc->bmAttributes.xfer ); + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; - TU_ASSERT(dcd_edpt_open(rhport, ep_desc)); + TU_VERIFY(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && xfer_type == desc_ep->bmAttributes.xfer); + TU_ASSERT(dcd_edpt_open(rhport, desc_ep)); - if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN ) + if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) { - (*ep_in) = ep_desc->bEndpointAddress; + (*ep_in) = desc_ep->bEndpointAddress; }else { - (*ep_out) = ep_desc->bEndpointAddress; + (*ep_out) = desc_ep->bEndpointAddress; } - ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(ep_desc); + p_desc = tu_desc_next(p_desc); } return true; diff --git a/src/device/usbd.h b/src/device/usbd.h index de59731a2..8debbf535 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -107,7 +107,7 @@ ATTR_WEAK void tud_resume_cb(void); #define TUD_CDC_DESC_LEN (8+9+5+5+4+5+7+9+7+7) // CDC Descriptor Template -// interface number, string index, EP notification address and size, EP data address (out,in) and size. +// Interface number, string index, EP notification address and size, EP data address (out, in) and size. #define TUD_CDC_DESCRIPTOR(_itfnum, _stridx, _ep_notif, _ep_notif_size, _epout, _epin, _epsize) \ /* Interface Associate */\ 8, TUSB_DESC_INTERFACE_ASSOCIATION, _itfnum, 2, TUSB_CLASS_CDC, CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL, CDC_COMM_PROTOCOL_ATCOMMAND, 0,\ @@ -149,15 +149,31 @@ ATTR_WEAK void tud_resume_cb(void); // Length of template descriptor: 25 bytes #define TUD_HID_DESC_LEN (9 + 9 + 7) +// HID Input only descriptor // Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval #define TUD_HID_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epin, _epsize, _ep_interval) \ /* Interface */\ 9, TUSB_DESC_INTERFACE, _itfnum, 0, 1, TUSB_CLASS_HID, (_boot_protocol) ? HID_SUBCLASS_BOOT : 0, _boot_protocol, _stridx,\ /* HID descriptor */\ 9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\ - /* Endpoint descriptor */\ + /* Endpoint In */\ 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval +// Length of template descriptor: 32 bytes +#define TUD_HID_INOUT_DESC_LEN (9 + 9 + 7 + 7) + +// HID Input & Output descriptor +// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval +#define TUD_HID_INOUT_DESCRIPTOR(_itfnum, _stridx, _boot_protocol, _report_desc_len, _epin, _epout, _epsize, _ep_interval) \ + /* Interface */\ + 9, TUSB_DESC_INTERFACE, _itfnum, 0, 2, TUSB_CLASS_HID, (_boot_protocol) ? HID_SUBCLASS_BOOT : 0, _boot_protocol, _stridx,\ + /* HID descriptor */\ + 9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0111), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(_report_desc_len),\ + /* Endpoint In */\ + 7, TUSB_DESC_ENDPOINT, _epin, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval,\ + /* Endpoint Out */\ + 7, TUSB_DESC_ENDPOINT, _epout, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_epsize), _ep_interval + #ifdef __cplusplus } #endif diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h index 8518ee209..fb3672359 100644 --- a/src/device/usbd_pvt.h +++ b/src/device/usbd_pvt.h @@ -53,9 +53,8 @@ bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr); /*------------------------------------------------------------------*/ /* Helper *------------------------------------------------------------------*/ -// helper to parse an pair of In and Out endpoint descriptors. They must be consecutive -bool usbd_open_edpt_pair(uint8_t rhport, tusb_desc_endpoint_t const* p_desc_ep, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in); +bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in); void usbd_defer_func( osal_task_func_t func, void* param, bool in_isr ); diff --git a/src/osal/osal.h b/src/osal/osal.h index cdeaa2974..7304fdbd2 100644 --- a/src/osal/osal.h +++ b/src/osal/osal.h @@ -47,56 +47,49 @@ enum typedef void (*osal_task_func_t)( void * ); +#if CFG_TUSB_OS == OPT_OS_NONE + #include "osal_none.h" +#elif CFG_TUSB_OS == OPT_OS_FREERTOS + #include "osal_freertos.h" +#elif CFG_TUSB_OS == OPT_OS_MYNEWT + #include "osal_mynewt.h" +#else + #error OS is not supported yet +#endif + //--------------------------------------------------------------------+ // OSAL Porting API //--------------------------------------------------------------------+ -#if 0 -void osal_task_delay(uint32_t msec); +static inline void osal_task_delay(uint32_t msec); //------------- Semaphore -------------// -osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef); -bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr); -bool osal_semaphore_wait (osal_semaphore_t sem_hdl, uint32_t msec); +static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef); +static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr); +static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec); -void osal_semaphore_reset(osal_semaphore_t sem_hdl); // TODO removed +static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl); // TODO removed //------------- Mutex -------------// -osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef); -bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec); -bool osal_mutex_unlock(osal_mutex_t mutex_hdl); +static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef); +static inline bool osal_mutex_lock (osal_mutex_t sem_hdl, uint32_t msec); +static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl); //------------- Queue -------------// -osal_queue_t osal_queue_create(osal_queue_def_t* qdef); -bool osal_queue_receive(osal_queue_t const qhdl, void* data); -bool osal_queue_send(osal_queue_t const qhdl, void const * data, bool in_isr); -#endif +static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef); +static inline bool osal_queue_receive(osal_queue_t const qhdl, void* data); +static inline bool osal_queue_send(osal_queue_t const qhdl, void const * data, bool in_isr); -#if CFG_TUSB_OS == OPT_OS_NONE - #include "osal_none.h" -#else - #if CFG_TUSB_OS == OPT_OS_FREERTOS - #include "osal_freertos.h" - #elif CFG_TUSB_OS == OPT_OS_MYNEWT - #include "osal_mynewt.h" - #else - #error CFG_TUSB_OS is not defined or OS is not supported yet - #endif +#if 0 // TODO remove subtask related macros later +// Sub Task +#define OSAL_SUBTASK_BEGIN +#define OSAL_SUBTASK_END return TUSB_ERROR_NONE; - // TODO remove subtask related macros later +#define STASK_RETURN(_error) return _error; +#define STASK_INVOKE(_subtask, _status) (_status) = _subtask - //------------- Sub Task -------------// - #define OSAL_SUBTASK_BEGIN - #define OSAL_SUBTASK_END return TUSB_ERROR_NONE; - - #define STASK_RETURN(_error) return _error; - #define STASK_INVOKE(_subtask, _status) (_status) = _subtask - - //------------- Sub Task Assert -------------// - #define STASK_ASSERT_ERR(_err) TU_VERIFY_ERR(_err) - #define STASK_ASSERT_ERR_HDLR(_err, _func) TU_VERIFY_ERR_HDLR(_err, _func) - - #define STASK_ASSERT(_cond) TU_VERIFY(_cond, TUSB_ERROR_OSAL_TASK_FAILED) - #define STASK_ASSERT_HDLR(_cond, _func) TU_VERIFY_HDLR(_cond, _func) +// Sub Task Assert +#define STASK_ASSERT_ERR(_err) TU_VERIFY_ERR(_err) +#define STASK_ASSERT(_cond) TU_VERIFY(_cond, TUSB_ERROR_OSAL_TASK_FAILED) #endif #ifdef __cplusplus diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index 1f8e94420..3e5f69f79 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -489,7 +489,7 @@ void USBD_IRQHandler(void) { xfer->total_len = xfer->actual_len; - // BULK/INT OUT complete + // CBI OUT complete dcd_event_xfer_complete(0, epnum, xfer->actual_len, XFER_RESULT_SUCCESS, true); } } @@ -524,7 +524,7 @@ void USBD_IRQHandler(void) xact_in_prepare(epnum); } else { - // Bulk/Int IN complete + // CBI IN complete dcd_event_xfer_complete(0, epnum | TUSB_DIR_IN_MASK, xfer->actual_len, XFER_RESULT_SUCCESS, true); } } diff --git a/tests/support/descriptor_test.c b/tests/support/descriptor_test.c index 20e10af56..f4b1a6d17 100644 --- a/tests/support/descriptor_test.c +++ b/tests/support/descriptor_test.c @@ -166,7 +166,7 @@ const app_configuration_desc_t desc_configuration = .bLength = sizeof(tusb_hid_descriptor_hid_t), .bDescriptorType = HID_DESC_TYPE_HID, .bcdHID = 0x0111, - .bCountryCode = HID_Local_NotSupported, + .bCountryCode = HID_LOCAL_NotSupported, .bNumDescriptors = 1, .bReportType = HID_DESC_TYPE_REPORT, .wReportLength = sizeof(keyboard_report_descriptor) @@ -201,7 +201,7 @@ const app_configuration_desc_t desc_configuration = .bLength = sizeof(tusb_hid_descriptor_hid_t), .bDescriptorType = HID_DESC_TYPE_HID, .bcdHID = 0x0111, - .bCountryCode = HID_Local_NotSupported, + .bCountryCode = HID_LOCAL_NotSupported, .bNumDescriptors = 1, .bReportType = HID_DESC_TYPE_REPORT, .wReportLength = sizeof(mouse_report_descriptor) diff --git a/tools/build_all.py b/tools/build_all.py index e3439cb5b..d65bb0730 100644 --- a/tools/build_all.py +++ b/tools/build_all.py @@ -4,10 +4,53 @@ import sys import subprocess import time -all_device_example = ["cdc_msc_hid", "msc_dual_lun"] -all_boards = ["metro_m0_express", "metro_m4_express", "pca10056", "stm32f407g_disc1"] +travis = False +if "TRAVIS" in os.environ and os.environ["TRAVIS"] == "true": + PARALLEL="-j 2" + travis = True + +success_count = 0 +fail_count = 0 +exit_status = 0 + +all_device_example = ["cdc_msc_hid", "msc_dual_lun", "hid_generic_inout"] +all_boards = ["metro_m0_express", "metro_m4_express", "pca10056", "feather_nrf52840_express", "stm32f407g_disc1"] + +def build_example(example, board): + subprocess.run("make -C examples/device/{} BOARD={} clean".format(example, board), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + return subprocess.run("make -j 4 -C examples/device/{} BOARD={} all".format(example, board), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + +total_time = time.monotonic() for example in all_device_example: for board in all_boards: - subprocess.run("make -j2 -C examples/device/{} BOARD={} clean".format(example, board), shell=True) - subprocess.run("make -j2 -C examples/device/{} BOARD={} all".format(example, board), shell=True) + start_time = time.monotonic() + build_result = build_example(example, board) + build_duration = time.monotonic() - start_time + + if build_result.returncode != 0: + exit_status = build_result.returncode + success = "\033[31mfailed\033[0m" + fail_count += 1 + else: + success = "\033[32msucceeded\033[0m" + success_count += 1 + + if travis: + print('travis_fold:start:build-{}-{}\\r'.format(example, board)) + print("Build {} on {} took {:.2f}s and {}".format(example, board, build_duration, success)) + if build_result.returncode != 0: + print(build_result.stdout.decode("utf-8")) + if travis: + print('travis_fold:end:build-{}-{}\\r'.format(example, board)) + +# FreeRTOS example +#example = 'cdc_msc_hid_freertos' +#board = 'pca10056' +#subprocess.run("make -j2 -C examples/device/{} BOARD={} clean all".format(example, board), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + + +total_time = time.monotonic() - total_time + +print("Total build time took {:.2f}s".format(total_time)) +sys.exit(exit_status)