Skip to content

Commit bdc579c

Browse files
committed
add HID output endpoint support
1 parent 07e5a00 commit bdc579c

File tree

5 files changed

+163
-10
lines changed

5 files changed

+163
-10
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2019 Ha Thach for Adafruit Industries
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+
/* This example demonstrate HID Generic raw Input & Output.
26+
* It will receive data from Host (In endpoint) and echo back (Out endpoint).
27+
* HID Report descriptor use vendor for usage page (using template TUD_HID_REPORT_DESC_GENERIC_INOUT)
28+
*
29+
* Run 'python3 hid_test.py' on your PC to send and receive data to this device.
30+
* Python and `hid` package is required, for installation please follow
31+
* https://pypi.org/project/hid/
32+
*/
33+
34+
#include "Adafruit_TinyUSB.h"
35+
36+
// HID report descriptor using TinyUSB's template
37+
// Generic In Out with 64 bytes report (max)
38+
uint8_t const desc_hid_report[] =
39+
{
40+
TUD_HID_REPORT_DESC_GENERIC_INOUT(64)
41+
};
42+
43+
Adafruit_USBD_HID usb_hid;
44+
45+
// the setup function runs once when you press reset or power the board
46+
void setup()
47+
{
48+
usb_hid.enableOutEndpoint(true);
49+
usb_hid.setPollInterval(2);
50+
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
51+
usb_hid.setReportCallback(get_report_callback, set_report_callback);
52+
53+
usb_hid.begin();
54+
55+
Serial.begin(115200);
56+
while ( !Serial ) delay(10); // wait for native usb
57+
58+
Serial.println("Adafruit TinyUSB HID Generic In Out example");
59+
}
60+
61+
void loop()
62+
{
63+
// nothing to do
64+
}
65+
66+
// Invoked when received GET_REPORT control request
67+
// Application must fill buffer report's content and return its length.
68+
// Return zero will cause the stack to STALL request
69+
uint16_t get_report_callback (uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
70+
{
71+
// not used in this example
72+
return 0;
73+
}
74+
75+
// Invoked when received SET_REPORT control request or
76+
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
77+
void set_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
78+
{
79+
// This example doesn't use multiple report and report ID
80+
(void) report_id;
81+
(void) report_type;
82+
83+
// echo back anything we received from host
84+
usb_hid.sendReport(0, buffer, bufsize);
85+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Install python3 HID package https://pypi.org/project/hid/
2+
import hid
3+
4+
# default is Adafruit VID
5+
USB_VID = 0x239A
6+
7+
print("Openning HID device with VID = 0x%X" % USB_VID)
8+
9+
for dict in hid.enumerate(USB_VID):
10+
print(dict)
11+
dev = hid.Device(dict['vendor_id'], dict['product_id'])
12+
if dev:
13+
while True:
14+
# Get input from console and encode to UTF8 for array of chars.
15+
str_out = input("Send text to HID Device : ").encode('utf-8')
16+
dev.write(str_out)
17+
str_in = dev.read(64)
18+
print("Received from HID Device:", str_in, '\n')

src/Adafruit_USBD_HID.cpp

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,20 @@
2424

2525
#include "Adafruit_USBD_HID.h"
2626

27-
28-
//--------------------------------------------------------------------+
29-
//
30-
//--------------------------------------------------------------------+
3127
#define EPOUT 0x00
3228
#define EPIN 0x80
3329

3430
uint8_t const _ascii2keycode[128][2] = { HID_ASCII_TO_KEYCODE };
3531

32+
static Adafruit_USBD_HID* _hid_dev = NULL;
33+
3634
//------------- IMPLEMENTATION -------------//
3735
Adafruit_USBD_HID::Adafruit_USBD_HID(void)
3836
{
3937
_interval_ms = 10;
4038
_protocol = HID_PROTOCOL_NONE;
4139

40+
_out_endpoint = false;
4241
_mouse_button = 0;
4342

4443
_desc_report = NULL;
@@ -58,6 +57,11 @@ void Adafruit_USBD_HID::setBootProtocol(uint8_t protocol)
5857
_protocol = protocol;
5958
}
6059

60+
void Adafruit_USBD_HID::enableOutEndpoint(bool enable)
61+
{
62+
_out_endpoint = enable;
63+
}
64+
6165
void Adafruit_USBD_HID::setReportDescriptor(uint8_t const* desc_report, uint16_t len)
6266
{
6367
_desc_report = desc_report;
@@ -74,18 +78,33 @@ uint16_t Adafruit_USBD_HID::getDescriptor(uint8_t* buf, uint16_t bufsize)
7478
{
7579
if ( !_desc_report_len ) return 0;
7680

77-
uint8_t desc[] = { TUD_HID_DESCRIPTOR(0, 0, _protocol, _desc_report_len, EPIN, 16, _interval_ms) };
78-
uint16_t const len = sizeof(desc);
81+
if ( _out_endpoint )
82+
{
83+
uint8_t desc[] = { TUD_HID_INOUT_DESCRIPTOR(0, 0, _protocol, _desc_report_len, EPIN, EPOUT, CFG_TUD_HID_BUFSIZE, _interval_ms) };
84+
uint16_t const len = sizeof(desc);
85+
86+
if ( bufsize < len ) return 0;
87+
memcpy(buf, desc, len);
88+
89+
return len;
90+
}else
91+
{
92+
uint8_t desc[] = { TUD_HID_DESCRIPTOR(0, 0, _protocol, _desc_report_len, EPIN, CFG_TUD_HID_BUFSIZE, _interval_ms) };
93+
uint16_t const len = sizeof(desc);
7994

80-
if ( bufsize < len ) return 0;
81-
memcpy(buf, desc, len);
82-
return len;
95+
if ( bufsize < len ) return 0;
96+
memcpy(buf, desc, len);
97+
98+
return len;
99+
}
83100
}
84101

85102
bool Adafruit_USBD_HID::begin(void)
86103
{
87104
if ( !USBDevice.addInterface(*this) ) return false;
105+
88106
tud_desc_set.hid_report = _desc_report;
107+
_hid_dev = this;
89108

90109
return true;
91110
}
@@ -100,6 +119,31 @@ bool Adafruit_USBD_HID::sendReport(uint8_t report_id, void const* report, uint8_
100119
return tud_hid_report(report_id, report, len);
101120
}
102121

122+
//------------- TinyUSB callbacks -------------//
123+
extern "C"
124+
{
125+
126+
// Invoked when received GET_REPORT control request
127+
// Application must fill buffer report's content and return its length.
128+
// Return zero will cause the stack to STALL request
129+
uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
130+
{
131+
if ( !(_hid_dev && _hid_dev->_get_report_cb) ) return 0;
132+
133+
return _hid_dev->_get_report_cb(report_id, report_type, buffer, reqlen);
134+
}
135+
136+
// Invoked when received SET_REPORT control request or
137+
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
138+
void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
139+
{
140+
if ( !(_hid_dev && _hid_dev->_set_report_cb) ) return;
141+
142+
_hid_dev->_set_report_cb(report_id, report_type, buffer, bufsize);
143+
}
144+
145+
} // extern "C"
146+
103147
//--------------------------------------------------------------------+
104148
// Keyboard
105149
//--------------------------------------------------------------------+

src/Adafruit_USBD_HID.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class Adafruit_USBD_HID : Adafruit_USBD_Interface
3737

3838
void setPollInterval(uint8_t interval_ms);
3939
void setBootProtocol(uint8_t protocol); // 0: None, 1: Keyboard, 2:Mouse
40+
void enableOutEndpoint(bool enable);
4041
void setReportDescriptor(uint8_t const* desc_report, uint16_t len);
4142
void setReportCallback(get_report_callback_t get_report, set_report_callback_t set_report);
4243

@@ -63,13 +64,17 @@ class Adafruit_USBD_HID : Adafruit_USBD_Interface
6364
private:
6465
uint8_t _interval_ms;
6566
uint8_t _protocol;
67+
bool _out_endpoint;
6668
uint8_t _mouse_button;
6769

6870
uint16_t _desc_report_len;
6971
uint8_t const* _desc_report;
7072

7173
get_report_callback_t _get_report_cb;
7274
set_report_callback_t _set_report_cb;
75+
76+
friend uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen);
77+
friend void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize);
7378
};
7479

7580
#endif /* ADAFRUIT_USBD_HID_H_ */

src/Adafruit_USBD_MSC.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ bool Adafruit_USBD_MSC::begin(void)
8383
return true;
8484
}
8585

86+
//------------- TinyUSB callbacks -------------//
8687
extern "C"
8788
{
8889

@@ -180,5 +181,5 @@ void tud_msc_write10_complete_cb (uint8_t lun)
180181
return _msc_dev->_lun[lun].fl_cb();
181182
}
182183

183-
}
184+
} // extern "C"
184185

0 commit comments

Comments
 (0)