23
23
*
24
24
*/
25
25
26
- // This example runs both host and device concurrently. The USB host looks for
27
- // any HID device with reports that are 8 bytes long and then assumes they are
28
- // keyboard reports. It translates the keypresses of the reports to ASCII and
29
- // transmits it over CDC to the device's host.
26
+ // This example runs both host and device concurrently. The USB host receive
27
+ // reports from HID device and print it out over USB Device CDC interface.
30
28
31
29
#include <stdlib.h>
32
30
#include <stdio.h>
@@ -73,28 +71,28 @@ enum {
73
71
static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED ;
74
72
75
73
void led_blinking_task (void );
76
- void cdc_task (void );
77
74
78
75
/*------------- MAIN -------------*/
79
76
int main (void )
80
77
{
81
78
board_init ();
79
+
80
+ printf ("TinyUSB Host HID <-> Device CDC Example\r\n" );
81
+
82
82
tusb_init ();
83
83
84
84
while (1 )
85
85
{
86
86
tud_task (); // tinyusb device task
87
87
tuh_task (); // tinyusb host task
88
88
led_blinking_task ();
89
-
90
- cdc_task ();
91
89
}
92
90
93
91
return 0 ;
94
92
}
95
93
96
94
//--------------------------------------------------------------------+
97
- // Device callbacks
95
+ // Device CDC
98
96
//--------------------------------------------------------------------+
99
97
100
98
// Invoked when device is mounted
@@ -124,8 +122,20 @@ void tud_resume_cb(void)
124
122
blink_interval_ms = BLINK_MOUNTED ;
125
123
}
126
124
125
+ // Invoked when CDC interface received data from host
126
+ void tud_cdc_rx_cb (uint8_t itf )
127
+ {
128
+ (void ) itf ;
129
+
130
+ char buf [64 ];
131
+ uint32_t count = tud_cdc_read (buf , sizeof (buf ));
132
+
133
+ // TODO control LED on keyboard of host stack
134
+ (void ) count ;
135
+ }
136
+
127
137
//--------------------------------------------------------------------+
128
- // Host callbacks
138
+ // Host HID
129
139
//--------------------------------------------------------------------+
130
140
131
141
// Invoked when device with hid interface is mounted
@@ -137,169 +147,140 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
137
147
{
138
148
(void )desc_report ;
139
149
(void )desc_len ;
150
+
151
+ // Interface protocol (hid_interface_protocol_enum_t)
152
+ const char * protocol_str [] = { "None" , "Keyboard" , "Mouse" };
153
+ uint8_t const itf_protocol = tuh_hid_interface_protocol (dev_addr , instance );
154
+
140
155
uint16_t vid , pid ;
141
156
tuh_vid_pid_get (dev_addr , & vid , & pid );
142
157
143
- printf ("HID device address = %d, instance = %d is mounted\r\n" , dev_addr , instance );
144
- printf ("VID = %04x, PID = %04x\r\n" , vid , pid );
158
+ char tempbuf [256 ];
159
+ int count = sprintf (tempbuf , "[%04x:%04x][%u] HID Interface%u, Protocol = %s\r\n" , vid , pid , dev_addr , instance , protocol_str [itf_protocol ]);
160
+
161
+ tud_cdc_write (tempbuf , count );
162
+ tud_cdc_write_flush ();
145
163
146
- // Receive any report and treat it like a keyboard.
164
+ // Receive report from boot keyboard & mouse only
147
165
// tuh_hid_report_received_cb() will be invoked when report is available
148
- if ( ! tuh_hid_receive_report ( dev_addr , instance ) )
166
+ if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD || itf_protocol == HID_ITF_PROTOCOL_MOUSE )
149
167
{
150
- printf ("Error: cannot request to receive report\r\n" );
168
+ if ( !tuh_hid_receive_report (dev_addr , instance ) )
169
+ {
170
+ tud_cdc_write_str ("Error: cannot request report\r\n" );
171
+ }
151
172
}
152
173
}
153
174
154
175
// Invoked when device with hid interface is un-mounted
155
176
void tuh_hid_umount_cb (uint8_t dev_addr , uint8_t instance )
156
177
{
157
- printf ("HID device address = %d, instance = %d is unmounted\r\n" , dev_addr , instance );
178
+ char tempbuf [256 ];
179
+ int count = sprintf (tempbuf , "[%u] HID Interface%u is unmounted\r\n" , dev_addr , instance );
180
+ tud_cdc_write (tempbuf , count );
181
+ tud_cdc_write_flush ();
158
182
}
159
183
160
- // keycodes from last report to check if key is holding or newly pressed
161
- uint8_t last_keycodes [6 ] = {0 };
162
-
163
184
// look up new key in previous keys
164
- static inline bool key_in_last_report ( const uint8_t key_arr [ 6 ] , uint8_t keycode )
185
+ static inline bool find_key_in_report ( hid_keyboard_report_t const * report , uint8_t keycode )
165
186
{
166
187
for (uint8_t i = 0 ; i < 6 ; i ++ )
167
188
{
168
- if (key_arr [i ] == keycode ) return true;
189
+ if (report -> keycode [i ] == keycode ) return true;
169
190
}
170
191
171
192
return false;
172
193
}
173
194
174
- // Invoked when received report from device via interrupt endpoint
175
- void tuh_hid_report_received_cb (uint8_t dev_addr , uint8_t instance , uint8_t const * report , uint16_t len )
176
- {
177
- if (len != 8 )
178
- {
179
- char ch_num ;
180
-
181
- tud_cdc_write_str ("incorrect report len: " );
182
-
183
- if ( len > 10 )
184
- {
185
- ch_num = '0' + (len / 10 );
186
- tud_cdc_write (& ch_num , 1 );
187
- len = len % 10 ;
188
- }
189
-
190
- ch_num = '0' + len ;
191
- tud_cdc_write (& ch_num , 1 );
192
-
193
- tud_cdc_write_str ("\r\n" );
194
- tud_cdc_write_flush ();
195
195
196
- // Don't request a new report for a wrong sized endpoint.
197
- return ;
198
- }
199
-
200
- uint8_t const modifiers = report [ 0 ];
196
+ // convert hid keycode to ascii and print via usb device CDC (ignore non-printable)
197
+ static void process_kbd_report ( uint8_t dev_addr , hid_keyboard_report_t const * report )
198
+ {
199
+ ( void ) dev_addr ;
200
+ static hid_keyboard_report_t prev_report = { 0 , 0 , { 0 } }; // previous report to check key released
201
201
bool flush = false;
202
202
203
- for ( int i = 2 ; i < 8 ; i ++ )
203
+ for ( uint8_t i = 0 ; i < 6 ; i ++ )
204
204
{
205
- uint8_t keycode = report [i ];
206
-
207
- if (keycode )
205
+ uint8_t keycode = report -> keycode [i ];
206
+ if ( keycode )
208
207
{
209
- if ( key_in_last_report ( last_keycodes , keycode ) )
208
+ if ( find_key_in_report ( & prev_report , keycode ) )
210
209
{
211
210
// exist in previous report means the current key is holding
212
- // do nothing
213
211
}else
214
212
{
215
213
// not existed in previous report means the current key is pressed
216
- // Only print keycodes 0 - 128.
217
- if (keycode < 128 )
214
+
215
+ // remap the key code for Colemak layout
216
+ #ifdef KEYBOARD_COLEMAK
217
+ uint8_t colemak_key_code = colemak [keycode ];
218
+ if (colemak_key_code != 0 ) keycode = colemak_key_code ;
219
+ #endif
220
+
221
+ bool const is_shift = report -> modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT );
222
+ uint8_t ch = keycode2ascii [keycode ][is_shift ? 1 : 0 ];
223
+
224
+ if (ch )
218
225
{
219
- // remap the key code for Colemak layout so @tannewt can type.
220
- #ifdef KEYBOARD_COLEMAK
221
- uint8_t colemak_key_code = colemak [keycode ];
222
- if (colemak_key_code != 0 ) keycode = colemak_key_code ;
223
- #endif
224
-
225
- bool const is_shift = modifiers & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT );
226
- char c = keycode2ascii [keycode ][is_shift ? 1 : 0 ];
227
- if (c )
228
- {
229
- if (c == '\n' ) tud_cdc_write ("\r" , 1 );
230
- tud_cdc_write (& c , 1 );
231
- flush = true;
232
- }
226
+ if (ch == '\n' ) tud_cdc_write ("\r" , 1 );
227
+ tud_cdc_write (& ch , 1 );
228
+ flush = true;
233
229
}
234
230
}
235
231
}
232
+ // TODO example skips key released
236
233
}
237
234
238
235
if (flush ) tud_cdc_write_flush ();
239
236
240
- // save current report
241
- memcpy (last_keycodes , report + 2 , 6 );
242
-
243
- // continue to request to receive report
244
- if ( !tuh_hid_receive_report (dev_addr , instance ) )
245
- {
246
- printf ("Error: cannot request to receive report\r\n" );
247
- }
237
+ prev_report = * report ;
248
238
}
249
239
240
+ // send mouse report to usb device CDC
241
+ static void process_mouse_report (uint8_t dev_addr , hid_mouse_report_t const * report )
242
+ {
243
+ //------------- button state -------------//
244
+ //uint8_t button_changed_mask = report->buttons ^ prev_report.buttons;
245
+ char l = report -> buttons & MOUSE_BUTTON_LEFT ? 'L' : '-' ;
246
+ char m = report -> buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-' ;
247
+ char r = report -> buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-' ;
250
248
249
+ char tempbuf [32 ];
250
+ int count = sprintf (tempbuf , "[%u] %c%c%c %d %d %d\r\n" , dev_addr , l , m , r , report -> x , report -> y , report -> wheel );
251
251
252
- //--------------------------------------------------------------------+
253
- // USB CDC
254
- //--------------------------------------------------------------------+
255
- void cdc_task (void )
256
- {
257
- // connected() check for DTR bit
258
- // Most but not all terminal client set this when making connection
259
- // if ( tud_cdc_connected() )
260
- {
261
- // connected and there are data available
262
- if ( tud_cdc_available () )
263
- {
264
- // read datas
265
- char buf [64 ];
266
- uint32_t count = tud_cdc_read (buf , sizeof (buf ));
267
- (void ) count ;
268
-
269
- // Echo back
270
- // Note: Skip echo by commenting out write() and write_flush()
271
- // for throughput test e.g
272
- // $ dd if=/dev/zero of=/dev/ttyACM0 count=10000
273
- tud_cdc_write (buf , count );
274
- tud_cdc_write_flush ();
275
- }
276
- }
252
+ tud_cdc_write (tempbuf , count );
253
+ tud_cdc_write_flush ();
277
254
}
278
255
279
- // Invoked when cdc when line state changed e.g connected/disconnected
280
- void tud_cdc_line_state_cb (uint8_t itf , bool dtr , bool rts )
256
+ // Invoked when received report from device via interrupt endpoint
257
+ void tuh_hid_report_received_cb (uint8_t dev_addr , uint8_t instance , uint8_t const * report , uint16_t len )
281
258
{
282
- (void ) itf ;
283
- ( void ) rts ;
259
+ (void ) len ;
260
+ uint8_t const itf_protocol = tuh_hid_interface_protocol ( dev_addr , instance ) ;
284
261
285
- // TODO set some indicator
286
- if ( dtr )
262
+ switch (itf_protocol )
287
263
{
288
- // Terminal connected
289
- }else
290
- {
291
- // Terminal disconnected
264
+ case HID_ITF_PROTOCOL_KEYBOARD :
265
+ process_kbd_report (dev_addr , (hid_keyboard_report_t const * ) report );
266
+ break ;
267
+
268
+ case HID_ITF_PROTOCOL_MOUSE :
269
+ process_mouse_report (dev_addr , (hid_mouse_report_t const * ) report );
270
+ break ;
271
+
272
+ default : break ;
292
273
}
293
- }
294
274
295
- // Invoked when CDC interface received data from host
296
- void tud_cdc_rx_cb (uint8_t itf )
297
- {
298
- (void ) itf ;
275
+ // continue to request to receive report
276
+ if ( !tuh_hid_receive_report (dev_addr , instance ) )
277
+ {
278
+ tud_cdc_write_str ("Error: cannot request report\r\n" );
279
+ }
299
280
}
300
281
301
282
//--------------------------------------------------------------------+
302
- // BLINKING TASK
283
+ // Blinking Task
303
284
//--------------------------------------------------------------------+
304
285
void led_blinking_task (void )
305
286
{
0 commit comments