Skip to content

Commit 0eeacc8

Browse files
committed
Provide thread-safe USBHID::SendReport
1 parent a7fab63 commit 0eeacc8

15 files changed

+117
-224
lines changed

libraries/USB/examples/CompositeDevice/CompositeDevice.ino

+1-2
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t eve
9494
HWSerial.printf("MSC Update ERROR! Progress: %u bytes\n", data->error.size);
9595
break;
9696
case ARDUINO_FIRMWARE_MSC_POWER_EVENT:
97-
HWSerial.printf("MSC Update Power: power: %u, start: %u, eject: %u", data->power.power_condition, data->power.start, data->power.load_eject);
97+
HWSerial.printf("MSC Update Power: power: %u, start: %u, eject: %u\n", data->power.power_condition, data->power.start, data->power.load_eject);
9898
break;
9999

100100
default:
@@ -173,7 +173,6 @@ void setup() {
173173
Gamepad.begin();
174174
ConsumerControl.begin();
175175
SystemControl.begin();
176-
HID.begin();
177176
USB.begin();
178177
}
179178

libraries/USB/src/USBHID.cpp

+53-29
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,14 @@ extern "C" uint16_t tusb_hid_load_descriptor(uint8_t * dst, uint8_t * itf)
128128
static USBHIDDevice * tinyusb_hid_devices[USB_HID_DEVICES_MAX+1];
129129
static uint8_t tinyusb_hid_devices_num = 0;
130130
static bool tinyusb_hid_devices_is_initialized = false;
131+
static xSemaphoreHandle tinyusb_hid_device_input_sem = NULL;
132+
static xSemaphoreHandle tinyusb_hid_device_input_mutex = NULL;
131133

132134

133135
// Invoked when received GET HID REPORT DESCRIPTOR request
134136
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
135137
uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance){
136-
log_d("instance: %u", instance);
138+
log_v("instance: %u", instance);
137139
return tinyusb_hid_device_descriptor;
138140
}
139141

@@ -191,48 +193,70 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_
191193
}
192194
}
193195

194-
// Invoked when sent REPORT successfully to host
195-
// Application can use this to send the next report
196-
// Note: For composite reports, report[0] is report ID
197-
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len){
198-
if(report[0] < USB_HID_DEVICES_MAX && tinyusb_hid_devices[report[0]]){
199-
tinyusb_hid_devices[report[0]]->_onInputDone(report+1, len-1);
200-
} else {
201-
log_i("instance: %u, report_id: %u, report_type: %s, bufsize:%u", instance, report[0], tinyusb_hid_device_report_types[HID_REPORT_TYPE_INPUT], len-1);
202-
log_print_buf(report+1, len-1);
203-
}
204-
}
205-
206-
bool tud_hid_n_wait_ready(uint8_t instance, uint32_t timeout_ms){
207-
if(tud_hid_n_ready(instance)){
208-
return true;
209-
}
210-
uint32_t start_ms = millis();
211-
while(!tud_hid_n_ready(instance)){
212-
if((millis() - start_ms) > timeout_ms){
213-
return false;
214-
}
215-
delay(1);
216-
}
217-
return true;
218-
}
219-
220196
USBHID::USBHID(){
221197
if(!tinyusb_hid_devices_is_initialized){
222198
tinyusb_hid_devices_is_initialized = true;
223199
memset(tinyusb_hid_devices, 0, sizeof(tinyusb_hid_devices));
224200
tinyusb_hid_devices_num = 0;
225201
tinyusb_enable_interface(USB_INTERFACE_HID, TUD_HID_INOUT_DESC_LEN, tusb_hid_load_descriptor);
226202
}
227-
228203
}
229204

230205
void USBHID::begin(){
231-
206+
if(tinyusb_hid_device_input_sem == NULL){
207+
tinyusb_hid_device_input_sem = xSemaphoreCreateBinary();
208+
}
209+
if(tinyusb_hid_device_input_mutex == NULL){
210+
tinyusb_hid_device_input_mutex = xSemaphoreCreateMutex();
211+
}
232212
}
233213

234214
void USBHID::end(){
215+
if (tinyusb_hid_device_input_sem != NULL) {
216+
vSemaphoreDelete(tinyusb_hid_device_input_sem);
217+
tinyusb_hid_device_input_sem = NULL;
218+
}
219+
if (tinyusb_hid_device_input_mutex != NULL) {
220+
vSemaphoreDelete(tinyusb_hid_device_input_mutex);
221+
tinyusb_hid_device_input_mutex = NULL;
222+
}
223+
}
224+
225+
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len){
226+
if (tinyusb_hid_device_input_sem) {
227+
xSemaphoreGive(tinyusb_hid_device_input_sem);
228+
}
229+
}
230+
231+
bool USBHID::SendReport(uint8_t id, const void* data, size_t len, uint32_t timeout_ms){
232+
if(!tinyusb_hid_device_input_sem || !tinyusb_hid_device_input_mutex){
233+
log_e("TX Semaphore is NULL. You must call USBHID::begin() before you can send reports");
234+
return false;
235+
}
236+
237+
if(xSemaphoreTake(tinyusb_hid_device_input_mutex, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){
238+
log_e("report %u mutex failed", id);
239+
return false;
240+
}
241+
242+
bool res = tud_hid_n_ready(0);
243+
if(!res){
244+
log_e("not ready");
245+
} else {
246+
res = tud_hid_n_report(0, id, data, len);
247+
if(!res){
248+
log_e("report %u failed", id);
249+
} else {
250+
xSemaphoreTake(tinyusb_hid_device_input_sem, 0);
251+
if(xSemaphoreTake(tinyusb_hid_device_input_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){
252+
log_e("report %u wait failed", id);
253+
res = false;
254+
}
255+
}
256+
}
235257

258+
xSemaphoreGive(tinyusb_hid_device_input_mutex);
259+
return res;
236260
}
237261

238262
bool USBHID::addDevice(USBHIDDevice * device, uint16_t descriptor_len, tinyusb_hid_device_descriptor_cb_t cb){

libraries/USB/src/USBHID.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ class USBHIDDevice
5353
virtual uint16_t _onGetFeature(uint8_t* buffer, uint16_t len){return 0;}
5454
virtual void _onSetFeature(const uint8_t* buffer, uint16_t len){}
5555
virtual void _onOutput(const uint8_t* buffer, uint16_t len){}
56-
virtual void _onInputDone(const uint8_t* buffer, uint16_t len){}
5756
};
5857

5958
class USBHID
@@ -62,11 +61,10 @@ class USBHID
6261
USBHID(void);
6362
void begin(void);
6463
void end(void);
64+
bool SendReport(uint8_t id, const void* data, size_t len, uint32_t timeout_ms = 100);
6565
void onEvent(esp_event_handler_t callback);
6666
void onEvent(arduino_usb_hid_event_t event, esp_event_handler_t callback);
6767
static bool addDevice(USBHIDDevice * device, uint16_t descriptor_len, tinyusb_hid_device_descriptor_cb_t cb);
6868
};
6969

70-
bool tud_hid_n_wait_ready(uint8_t instance, uint32_t timeout_ms);
71-
7270
#endif

libraries/USB/src/USBHIDConsumerControl.cpp

+3-28
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_i
2626
return sizeof(report_descriptor);
2727
}
2828

29-
USBHIDConsumerControl::USBHIDConsumerControl(): hid(), tx_sem(NULL){
29+
USBHIDConsumerControl::USBHIDConsumerControl(): hid(){
3030
static bool initialized = false;
3131
if(!initialized){
3232
initialized = true;
@@ -41,39 +41,14 @@ USBHIDConsumerControl::USBHIDConsumerControl(): hid(), tx_sem(NULL){
4141
}
4242

4343
void USBHIDConsumerControl::begin(){
44-
if(tx_sem == NULL){
45-
tx_sem = xSemaphoreCreateBinary();
46-
xSemaphoreTake(tx_sem, 0);
47-
}
44+
hid.begin();
4845
}
4946

5047
void USBHIDConsumerControl::end(){
51-
if (tx_sem != NULL) {
52-
vSemaphoreDelete(tx_sem);
53-
tx_sem = NULL;
54-
}
55-
}
56-
57-
void USBHIDConsumerControl::_onInputDone(const uint8_t* buffer, uint16_t len){
58-
//log_i("len: %u", len);
59-
xSemaphoreGive(tx_sem);
6048
}
6149

6250
bool USBHIDConsumerControl::send(uint16_t value){
63-
uint32_t timeout_ms = 100;
64-
if(!tud_hid_n_wait_ready(0, timeout_ms)){
65-
log_e("not ready");
66-
return false;
67-
}
68-
bool res = tud_hid_n_report(0, id, &value, 2);
69-
if(!res){
70-
log_e("report failed");
71-
return false;
72-
} else if(xSemaphoreTake(tx_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){
73-
log_e("report wait failed");
74-
return false;
75-
}
76-
return true;
51+
return hid.SendReport(id, &value, 2);
7752
}
7853

7954
size_t USBHIDConsumerControl::press(uint16_t k){

libraries/USB/src/USBHIDConsumerControl.h

-4
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,13 @@
7070
class USBHIDConsumerControl: public USBHIDDevice {
7171
private:
7272
USBHID hid;
73-
xSemaphoreHandle tx_sem;
7473
bool send(uint16_t value);
7574
public:
7675
USBHIDConsumerControl(void);
7776
void begin(void);
7877
void end(void);
7978
size_t press(uint16_t k);
8079
size_t release();
81-
82-
//internal use
83-
void _onInputDone(const uint8_t* buffer, uint16_t len);
8480
};
8581

8682
#endif

libraries/USB/src/USBHIDGamepad.cpp

+13-27
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_i
2626
return sizeof(report_descriptor);
2727
}
2828

29-
USBHIDGamepad::USBHIDGamepad(): hid(), tx_sem(NULL), _x(0), _y(0), _z(0), _rz(0), _rx(0), _ry(0), _hat(0), _buttons(0){
29+
USBHIDGamepad::USBHIDGamepad(): hid(), _x(0), _y(0), _z(0), _rz(0), _rx(0), _ry(0), _hat(0), _buttons(0){
3030
static bool initialized = false;
3131
if(!initialized){
3232
initialized = true;
@@ -41,39 +41,25 @@ USBHIDGamepad::USBHIDGamepad(): hid(), tx_sem(NULL), _x(0), _y(0), _z(0), _rz(0)
4141
}
4242

4343
void USBHIDGamepad::begin(){
44-
if(tx_sem == NULL){
45-
tx_sem = xSemaphoreCreateBinary();
46-
xSemaphoreTake(tx_sem, 0);
47-
}
44+
hid.begin();
4845
}
4946

5047
void USBHIDGamepad::end(){
51-
if (tx_sem != NULL) {
52-
vSemaphoreDelete(tx_sem);
53-
tx_sem = NULL;
54-
}
55-
}
5648

57-
void USBHIDGamepad::_onInputDone(const uint8_t* buffer, uint16_t len){
58-
//log_i("len: %u", len);
59-
xSemaphoreGive(tx_sem);
6049
}
6150

6251
bool USBHIDGamepad::write(){
63-
uint32_t timeout_ms = 100;
64-
if(!tud_hid_n_wait_ready(0, timeout_ms)){
65-
log_e("not ready");
66-
return false;
67-
}
68-
bool res = tud_hid_n_gamepad_report(0, id, _x, _y, _z, _rz, _rx, _ry, _hat, _buttons);
69-
if(!res){
70-
log_e("report failed");
71-
return false;
72-
} else if(xSemaphoreTake(tx_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){
73-
log_e("report wait failed");
74-
return false;
75-
}
76-
return true;
52+
hid_gamepad_report_t report = {
53+
.x = _x,
54+
.y = _y,
55+
.z = _z,
56+
.rz = _rz,
57+
.rx = _rx,
58+
.ry = _ry,
59+
.hat = _hat,
60+
.buttons = _buttons
61+
};
62+
return hid.SendReport(id, &report, sizeof(report));
7763
}
7864

7965
bool USBHIDGamepad::leftStick(int8_t x, int8_t y){

libraries/USB/src/USBHIDGamepad.h

-4
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
class USBHIDGamepad: public USBHIDDevice {
5454
private:
5555
USBHID hid;
56-
xSemaphoreHandle tx_sem;
5756
int8_t _x; ///< Delta x movement of left analog-stick
5857
int8_t _y; ///< Delta y movement of left analog-stick
5958
int8_t _z; ///< Delta z movement of right analog-joystick
@@ -80,9 +79,6 @@ class USBHIDGamepad: public USBHIDDevice {
8079
bool releaseButton(uint8_t button);
8180

8281
bool send(int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons);
83-
84-
//internal use
85-
void _onInputDone(const uint8_t* buffer, uint16_t len);
8682
};
8783

8884
#endif

libraries/USB/src/USBHIDKeyboard.cpp

+10-24
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ static uint16_t tinyusb_hid_device_descriptor_cb(uint8_t * dst, uint8_t report_i
3737
return sizeof(report_descriptor);
3838
}
3939

40-
USBHIDKeyboard::USBHIDKeyboard(): hid(), tx_sem(NULL){
40+
USBHIDKeyboard::USBHIDKeyboard(): hid(){
4141
static bool initialized = false;
4242
if(!initialized){
4343
initialized = true;
@@ -52,17 +52,10 @@ USBHIDKeyboard::USBHIDKeyboard(): hid(), tx_sem(NULL){
5252
}
5353

5454
void USBHIDKeyboard::begin(){
55-
if(tx_sem == NULL){
56-
tx_sem = xSemaphoreCreateBinary();
57-
xSemaphoreTake(tx_sem, 0);
58-
}
55+
hid.begin();
5956
}
6057

6158
void USBHIDKeyboard::end(){
62-
if (tx_sem != NULL) {
63-
vSemaphoreDelete(tx_sem);
64-
tx_sem = NULL;
65-
}
6659
}
6760

6861
void USBHIDKeyboard::onEvent(esp_event_handler_t callback){
@@ -72,11 +65,6 @@ void USBHIDKeyboard::onEvent(arduino_usb_hid_keyboard_event_t event, esp_event_h
7265
arduino_usb_event_handler_register_with(ARDUINO_USB_HID_KEYBOARD_EVENTS, event, callback, this);
7366
}
7467

75-
void USBHIDKeyboard::_onInputDone(const uint8_t* buffer, uint16_t len){
76-
//log_d("len: %u", len);
77-
xSemaphoreGive(tx_sem);
78-
}
79-
8068
void USBHIDKeyboard::_onOutput(const uint8_t* buffer, uint16_t len){
8169
//log_d("LEDS: 0x%02x", buffer[0]);
8270
arduino_usb_hid_keyboard_event_data_t p = {0};
@@ -86,17 +74,15 @@ void USBHIDKeyboard::_onOutput(const uint8_t* buffer, uint16_t len){
8674

8775
void USBHIDKeyboard::sendReport(KeyReport* keys)
8876
{
89-
uint32_t timeout_ms = 100;
90-
if(!tud_hid_n_wait_ready(0, timeout_ms)){
91-
log_e("not ready");
92-
return;
93-
}
94-
bool res = tud_hid_n_keyboard_report(0, id, keys->modifiers, keys->keys);
95-
if(!res){
96-
log_e("report failed");
97-
} else if(xSemaphoreTake(tx_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){
98-
log_e("report wait failed");
77+
hid_keyboard_report_t report;
78+
report.reserved = 0;
79+
report.modifier = keys->modifiers;
80+
if (keys->keys) {
81+
memcpy(report.keycode, keys->keys, 6);
82+
} else {
83+
memset(report.keycode, 0, 6);
9984
}
85+
hid.SendReport(id, &report, sizeof(report));
10086
}
10187

10288
#define SHIFT 0x80

libraries/USB/src/USBHIDKeyboard.h

-2
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ class USBHIDKeyboard: public USBHIDDevice, public Print
113113
{
114114
private:
115115
USBHID hid;
116-
xSemaphoreHandle tx_sem;
117116
KeyReport _keyReport;
118117
void sendReport(KeyReport* keys);
119118
public:
@@ -135,7 +134,6 @@ class USBHIDKeyboard: public USBHIDDevice, public Print
135134

136135
//internal use
137136
void _onOutput(const uint8_t* buffer, uint16_t len);
138-
void _onInputDone(const uint8_t* buffer, uint16_t len);
139137
};
140138

141139
#endif

0 commit comments

Comments
 (0)