From ca98996e1f9ac802c60d9da4c28ab0e16ca640d6 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 1 Jul 2021 22:46:39 +0700 Subject: [PATCH 1/3] better support for hid device set/get protocol add caplock detection for hid_composite --- examples/device/hid_composite/src/main.c | 31 +++++++++++-- hw/bsp/board.c | 58 ++++++++++++++++++++++-- hw/bsp/board.h | 9 +++- src/class/hid/hid_device.c | 28 +++++++++++- src/device/usbd.c | 2 +- src/device/usbd_control.c | 1 + 6 files changed, 115 insertions(+), 14 deletions(-) diff --git a/examples/device/hid_composite/src/main.c b/examples/device/hid_composite/src/main.c index 512f6f9d9..6ddad5aae 100644 --- a/examples/device/hid_composite/src/main.c +++ b/examples/device/hid_composite/src/main.c @@ -255,12 +255,30 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t // received data on OUT endpoint ( Report ID = 0, Type = 0 ) void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) { - // TODO set LED based on CAPLOCK, NUMLOCK etc... (void) itf; - (void) report_id; - (void) report_type; - (void) buffer; - (void) bufsize; + + if (report_type == HID_REPORT_TYPE_OUTPUT) + { + // Set keyboard LED e.g Capslock, Numlock etc... + if (report_id == REPORT_ID_KEYBOARD) + { + // bufsize should be (at least) 1 + if ( bufsize < 1 ) return; + + uint8_t const kbd_leds = buffer[0]; + + if (kbd_leds & KEYBOARD_LED_CAPSLOCK) + { + // Capslock On: disable blink, turn led on + blink_interval_ms = 0; + board_led_write(true); + }else + { + // Caplocks Off: back to normal link + blink_interval_ms = BLINK_MOUNTED; + } + } + } } //--------------------------------------------------------------------+ @@ -271,6 +289,9 @@ void led_blinking_task(void) static uint32_t start_ms = 0; static bool led_state = false; + // blink is disabled + if (!blink_interval_ms) return; + // Blink every interval ms if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time start_ms += blink_interval_ms; diff --git a/hw/bsp/board.c b/hw/bsp/board.c index 383a02ef4..c21c9e976 100644 --- a/hw/bsp/board.c +++ b/hw/bsp/board.c @@ -25,6 +25,60 @@ #include "board.h" +#if 0 +#define LED_PHASE_MAX 8 + +static struct +{ + uint32_t phase[LED_PHASE_MAX]; + uint8_t phase_count; + + bool led_state; + uint8_t current_phase; + uint32_t current_ms; +}led_pattern; + +void board_led_pattern(uint32_t const phase_ms[], uint8_t count) +{ + memcpy(led_pattern.phase, phase_ms, 4*count); + led_pattern.phase_count = count; + + // reset with 1st phase is on + led_pattern.current_ms = board_millis(); + led_pattern.current_phase = 0; + led_pattern.led_state = true; + board_led_on(); +} + +void board_led_task(void) +{ + if ( led_pattern.phase_count == 0 ) return; + + uint32_t const duration = led_pattern.phase[led_pattern.current_phase]; + + // return if not enough time + if (board_millis() - led_pattern.current_ms < duration) return; + + led_pattern.led_state = !led_pattern.led_state; + board_led_write(led_pattern.led_state); + + led_pattern.current_ms += duration; + led_pattern.current_phase++; + + if (led_pattern.current_phase == led_pattern.phase_count) + { + led_pattern.current_phase = 0; + led_pattern.led_state = true; + board_led_on(); + } +} + +#endif + +//--------------------------------------------------------------------+ +// newlib read()/write() retarget +//--------------------------------------------------------------------+ + #if defined(__MSP430__) #define sys_write write #define sys_read read @@ -33,10 +87,6 @@ #define sys_read _read #endif -//--------------------------------------------------------------------+ -// newlib read()/write() retarget -//--------------------------------------------------------------------+ - #if defined(LOGGER_RTT) // Logging with RTT diff --git a/hw/bsp/board.h b/hw/bsp/board.h index 7b77def50..782e0939c 100644 --- a/hw/bsp/board.h +++ b/hw/bsp/board.h @@ -54,6 +54,10 @@ void board_init(void); // Turn LED on or off void board_led_write(bool state); +// Control led pattern using phase duration in ms. +// For each phase, LED is toggle then repeated, board_led_task() is required to be called +//void board_led_pattern(uint32_t const phase_ms[], uint8_t count); + // Get the current state of button // a '1' means active (pressed), a '0' means inactive. uint32_t board_button_read(void); @@ -81,11 +85,12 @@ int board_uart_write(void const * buf, int len); } #elif CFG_TUSB_OS == OPT_OS_PICO -#include "pico/time.h" -static inline uint32_t board_millis(void) + #include "pico/time.h" + static inline uint32_t board_millis(void) { return to_ms_since_boot(get_absolute_time()); } + #elif CFG_TUSB_OS == OPT_OS_RTTHREAD static inline uint32_t board_millis(void) { diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index e44f282c4..65c7d1a18 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -280,7 +280,21 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t uint8_t const report_type = tu_u16_high(request->wValue); uint8_t const report_id = tu_u16_low(request->wValue); - uint16_t xferlen = tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, p_hid->epin_buf, request->wLength); + uint8_t* report_buf = p_hid->epin_buf; + uint16_t req_len = request->wLength; + + uint16_t xferlen = 0; + + // If host request a specific Report ID, add ID to as 1 byte of response + if ( (report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1) ) + { + *report_buf++ = report_id; + req_len--; + + xferlen++; + } + + xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len); TU_ASSERT( xferlen > 0 ); tud_control_xfer(rhport, request, p_hid->epin_buf, xferlen); @@ -298,7 +312,17 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t uint8_t const report_type = tu_u16_high(request->wValue); uint8_t const report_id = tu_u16_low(request->wValue); - tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, p_hid->epout_buf, request->wLength); + uint8_t const* report_buf = p_hid->epout_buf; + uint16_t report_len = request->wLength; + + // If host request a specific Report ID, extract report ID in buffer before invoking callback + if ( (report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == p_hid->epout_buf[0]) ) + { + report_buf++; + report_len--; + } + + tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, report_len); } break; diff --git a/src/device/usbd.c b/src/device/usbd.c index 587d487dc..af4fd58c4 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1243,7 +1243,7 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); - TU_LOG2(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes); + TU_LOG2(" Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes); // Attempt to transfer on a busy endpoint, sound like an race condition ! TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c index 724c652e6..7a8244699 100644 --- a/src/device/usbd_control.c +++ b/src/device/usbd_control.c @@ -186,6 +186,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result { TU_VERIFY(_ctrl_xfer.buffer); memcpy(_ctrl_xfer.buffer, _usbd_ctrl_buf, xferred_bytes); + TU_LOG_MEM(2, _usbd_ctrl_buf, xferred_bytes, 2); } _ctrl_xfer.total_xferred += xferred_bytes; From 6de023d54b944bb467327062e79f3854e79b71a2 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 1 Jul 2021 22:54:57 +0700 Subject: [PATCH 2/3] update hid_composite freertos with capslock as well --- examples/device/hid_composite/src/main.c | 3 +- .../device/hid_composite_freertos/src/main.c | 29 +++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/examples/device/hid_composite/src/main.c b/examples/device/hid_composite/src/main.c index 6ddad5aae..d2a8a28fa 100644 --- a/examples/device/hid_composite/src/main.c +++ b/examples/device/hid_composite/src/main.c @@ -274,7 +274,8 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep board_led_write(true); }else { - // Caplocks Off: back to normal link + // Caplocks Off: back to normal blink + board_led_write(false); blink_interval_ms = BLINK_MOUNTED; } } diff --git a/examples/device/hid_composite_freertos/src/main.c b/examples/device/hid_composite_freertos/src/main.c index 47f976427..a61710858 100644 --- a/examples/device/hid_composite_freertos/src/main.c +++ b/examples/device/hid_composite_freertos/src/main.c @@ -315,12 +315,31 @@ uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t // received data on OUT endpoint ( Report ID = 0, Type = 0 ) void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) { - // TODO set LED based on CAPLOCK, NUMLOCK etc... (void) itf; - (void) report_id; - (void) report_type; - (void) buffer; - (void) bufsize; + + if (report_type == HID_REPORT_TYPE_OUTPUT) + { + // Set keyboard LED e.g Capslock, Numlock etc... + if (report_id == REPORT_ID_KEYBOARD) + { + // bufsize should be (at least) 1 + if ( bufsize < 1 ) return; + + uint8_t const kbd_leds = buffer[0]; + + if (kbd_leds & KEYBOARD_LED_CAPSLOCK) + { + // Capslock On: disable blink, turn led on + xTimerStop(blinky_tm, portMAX_DELAY); + board_led_write(true); + }else + { + // Caplocks Off: back to normal blink + board_led_write(false); + xTimerStart(blinky_tm, portMAX_DELAY); + } + } + } } //--------------------------------------------------------------------+ From 2b3d547b7bccf46c6a274c75cb1769532611c5bf Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 1 Jul 2021 23:05:21 +0700 Subject: [PATCH 3/3] clean up --- src/class/hid/hid_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index 65c7d1a18..a10e3a5e3 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -316,7 +316,7 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t uint16_t report_len = request->wLength; // If host request a specific Report ID, extract report ID in buffer before invoking callback - if ( (report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == p_hid->epout_buf[0]) ) + if ( (report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0]) ) { report_buf++; report_len--;