Skip to content

Commit c4a9a04

Browse files
authored
Merge pull request #1025 from hathach/add-hid-boot-example
add hid_boot_interface example
2 parents 3a24895 + c050612 commit c4a9a04

File tree

11 files changed

+641
-16
lines changed

11 files changed

+641
-16
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
cmake_minimum_required(VERSION 3.5)
2+
3+
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
4+
5+
# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
6+
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
7+
8+
project(${PROJECT})
9+
10+
# Checks this example is valid for the family and initializes the project
11+
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
12+
13+
add_executable(${PROJECT})
14+
15+
# Example source
16+
target_sources(${PROJECT} PUBLIC
17+
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
18+
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
19+
)
20+
21+
# Example include
22+
target_include_directories(${PROJECT} PUBLIC
23+
${CMAKE_CURRENT_SOURCE_DIR}/src
24+
)
25+
26+
# Configure compilation flags and libraries for the example... see the corresponding function
27+
# in hw/bsp/FAMILY/family.cmake for details.
28+
family_configure_device_example(${PROJECT})
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
include ../../../tools/top.mk
2+
include ../../make.mk
3+
4+
INC += \
5+
src \
6+
$(TOP)/hw \
7+
8+
# Example source
9+
EXAMPLE_SOURCE += \
10+
src/main.c \
11+
src/usb_descriptors.c
12+
13+
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
14+
15+
include ../../rules.mk
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2019 Ha Thach (tinyusb.org)
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*
24+
*/
25+
26+
#include <stdlib.h>
27+
#include <stdio.h>
28+
#include <string.h>
29+
30+
#include "bsp/board.h"
31+
#include "tusb.h"
32+
#include "usb_descriptors.h"
33+
34+
//--------------------------------------------------------------------+
35+
// MACRO CONSTANT TYPEDEF PROTYPES
36+
//--------------------------------------------------------------------+
37+
38+
/* Blink pattern
39+
* - 250 ms : device not mounted
40+
* - 1000 ms : device mounted
41+
* - 2500 ms : device is suspended
42+
*/
43+
enum {
44+
BLINK_NOT_MOUNTED = 250,
45+
BLINK_MOUNTED = 1000,
46+
BLINK_SUSPENDED = 2500,
47+
};
48+
49+
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
50+
51+
void led_blinking_task(void);
52+
void hid_task(void);
53+
54+
/*------------- MAIN -------------*/
55+
int main(void)
56+
{
57+
board_init();
58+
tusb_init();
59+
60+
while (1)
61+
{
62+
tud_task(); // tinyusb device task
63+
led_blinking_task();
64+
65+
hid_task();
66+
}
67+
68+
return 0;
69+
}
70+
71+
//--------------------------------------------------------------------+
72+
// Device callbacks
73+
//--------------------------------------------------------------------+
74+
75+
// Invoked when device is mounted
76+
void tud_mount_cb(void)
77+
{
78+
blink_interval_ms = BLINK_MOUNTED;
79+
}
80+
81+
// Invoked when device is unmounted
82+
void tud_umount_cb(void)
83+
{
84+
blink_interval_ms = BLINK_NOT_MOUNTED;
85+
}
86+
87+
// Invoked when usb bus is suspended
88+
// remote_wakeup_en : if host allow us to perform remote wakeup
89+
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
90+
void tud_suspend_cb(bool remote_wakeup_en)
91+
{
92+
(void) remote_wakeup_en;
93+
blink_interval_ms = BLINK_SUSPENDED;
94+
}
95+
96+
// Invoked when usb bus is resumed
97+
void tud_resume_cb(void)
98+
{
99+
blink_interval_ms = BLINK_MOUNTED;
100+
}
101+
102+
//--------------------------------------------------------------------+
103+
// USB HID
104+
//--------------------------------------------------------------------+
105+
106+
// Every 10ms, we will sent 1 report for each HID profile (keyboard, mouse etc ..)
107+
// tud_hid_report_complete_cb() is used to send the next report after previous one is complete
108+
void hid_task(void)
109+
{
110+
// Poll every 10ms
111+
const uint32_t interval_ms = 10;
112+
static uint32_t start_ms = 0;
113+
114+
if ( board_millis() - start_ms < interval_ms) return; // not enough time
115+
start_ms += interval_ms;
116+
117+
uint32_t const btn = board_button_read();
118+
119+
if ( tud_suspended() && btn )
120+
{
121+
// Wake up host if we are in suspend mode
122+
// and REMOTE_WAKEUP feature is enabled by host
123+
tud_remote_wakeup();
124+
}
125+
else
126+
{
127+
// keyboard interface
128+
if ( tud_hid_n_ready(ITF_NUM_KEYBOARD) )
129+
{
130+
// used to avoid send multiple consecutive zero report for keyboard
131+
static bool has_keyboard_key = false;
132+
133+
uint8_t const report_id = 0;
134+
uint8_t const modifier = 0;
135+
136+
if ( btn )
137+
{
138+
uint8_t keycode[6] = { 0 };
139+
keycode[0] = HID_KEY_ARROW_RIGHT;
140+
141+
tud_hid_n_keyboard_report(ITF_NUM_KEYBOARD, report_id, modifier, keycode);
142+
has_keyboard_key = true;
143+
}else
144+
{
145+
// send empty key report if previously has key pressed
146+
if (has_keyboard_key) tud_hid_n_keyboard_report(ITF_NUM_KEYBOARD, report_id, modifier, NULL);
147+
has_keyboard_key = false;
148+
}
149+
}
150+
151+
// mouse interface
152+
if ( tud_hid_n_ready(ITF_NUM_MOUSE) )
153+
{
154+
if ( btn )
155+
{
156+
uint8_t const report_id = 0;
157+
uint8_t const button_mask = 0;
158+
uint8_t const veritical = 0;
159+
uint8_t const horizontal = 0;
160+
int8_t const delta = 5;
161+
162+
tud_hid_n_mouse_report(ITF_NUM_MOUSE, report_id, button_mask, delta, delta, veritical, horizontal);
163+
}
164+
}
165+
}
166+
}
167+
168+
// Invoked when received SET_PROTOCOL request
169+
// protocol is either HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
170+
void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol)
171+
{
172+
(void) instance;
173+
(void) protocol;
174+
175+
// nothing to do since we use the same compatible boot report for both Boot and Report mode.
176+
// TOOD set a indicator for user
177+
}
178+
179+
// Invoked when sent REPORT successfully to host
180+
// Application can use this to send the next report
181+
// Note: For composite reports, report[0] is report ID
182+
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len)
183+
{
184+
(void) instance;
185+
(void) report;
186+
(void) len;
187+
188+
// nothing to do
189+
}
190+
191+
// Invoked when received GET_REPORT control request
192+
// Application must fill buffer report's content and return its length.
193+
// Return zero will cause the stack to STALL request
194+
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
195+
{
196+
// TODO not Implemented
197+
(void) instance;
198+
(void) report_id;
199+
(void) report_type;
200+
(void) buffer;
201+
(void) reqlen;
202+
203+
return 0;
204+
}
205+
206+
// Invoked when received SET_REPORT control request or
207+
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
208+
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
209+
{
210+
(void) report_id;
211+
212+
// keyboard interface
213+
if (instance == ITF_NUM_KEYBOARD)
214+
{
215+
// Set keyboard LED e.g Capslock, Numlock etc...
216+
if (report_type == HID_REPORT_TYPE_OUTPUT)
217+
{
218+
// bufsize should be (at least) 1
219+
if ( bufsize < 1 ) return;
220+
221+
uint8_t const kbd_leds = buffer[0];
222+
223+
if (kbd_leds & KEYBOARD_LED_CAPSLOCK)
224+
{
225+
// Capslock On: disable blink, turn led on
226+
blink_interval_ms = 0;
227+
board_led_write(true);
228+
}else
229+
{
230+
// Caplocks Off: back to normal blink
231+
board_led_write(false);
232+
blink_interval_ms = BLINK_MOUNTED;
233+
}
234+
}
235+
}
236+
}
237+
238+
//--------------------------------------------------------------------+
239+
// BLINKING TASK
240+
//--------------------------------------------------------------------+
241+
void led_blinking_task(void)
242+
{
243+
static uint32_t start_ms = 0;
244+
static bool led_state = false;
245+
246+
// blink is disabled
247+
if (!blink_interval_ms) return;
248+
249+
// Blink every interval ms
250+
if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time
251+
start_ms += blink_interval_ms;
252+
253+
board_led_write(led_state);
254+
led_state = 1 - led_state; // toggle
255+
}

0 commit comments

Comments
 (0)