Skip to content

Commit 979cb34

Browse files
authored
Merge pull request #1587 from UltimateHackingKeyboard/semaphore_rework
Semaphore refactor.
2 parents b9aa5fb + 3833511 commit 979cb34

31 files changed

Lines changed: 1167 additions & 446 deletions

device/src/messenger.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#if DEVICE_IS_UHK_DONGLE
3535
#include <zephyr/kernel.h>
3636
#include "usb_report_updater.h"
37+
#include "usb_report_sender.h"
3738

3839
static K_SEM_DEFINE(dongleUsbSem, 0, 1);
3940

@@ -229,8 +230,8 @@ static void processSyncablePropertyDongle(device_id_t src, const uint8_t* data,
229230

230231
#if DEVICE_IS_UHK_DONGLE
231232
uint8_t retryCounter = 0;
232-
while (ShouldResendReport(ret == 0, &retryCounter)) {
233-
uint16_t delay = GetResendThrottleDelay(retryCounter);
233+
while (!UsbReportSender_ShouldGiveUp(ret, &retryCounter)) {
234+
uint16_t delay = UsbReportSender_ComputeResendDelay(retryCounter);
234235
k_sleep(K_MSEC(delay));
235236
k_sem_take(&dongleUsbSem, K_MSEC(128));
236237
ret = sendDongleReport(propertyId, message);

right/src/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ target_sources(${PROJECT_NAME} PRIVATE
6868
$<$<BOOL:${IS_MCUX_SDK}>:${CMAKE_CURRENT_SOURCE_DIR}/trace_reasons.c>
6969
usb_log_buffer.c
7070
usb_protocol_handler.c
71+
usb_report_sender.c
72+
usb_scheduler.c
73+
usb_semaphore.c
7174
usb_report_updater.c
7275
usb_state.c
7376
user_logic.c

right/src/debug.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@
150150
#define WATCH_SEMAPHORE_TAKE(SEM, FILENAME, N) if(CurrentWatch == N) { WatchSemaforeTake(SEM, FILENAME, N); } else { k_sem_take(SEM, K_FOREVER); }
151151
#define SEM_TAKE(SEM) WATCH_SEMAPHORE_TAKE(SEM, __FILE__, 0)
152152
#else
153-
#define SEM_TAKE(SEM) if (k_sem_take(SEM, K_MSEC(256)) != 0) { uint8_t tgt = Cfg.DevMode ? LogTarget_Uart | LogTarget_ErrorBuffer : LogTarget_Uart; LogTo(DEVICE_ID, tgt, "Failed to take semaphore " #SEM " in file %s. This shouldn't have happened. Please report it!\n", __FILE__); Trace_Print(tgt, "Failed semaphore"); }
153+
#define SEM_TAKE(SEM) if (k_sem_take(SEM, K_MSEC(256)) != 0) { uint8_t tgt = Cfg.DevMode ? LogTarget_Uart | LogTarget_ErrorBuffer : LogTarget_Uart; LogTo(DEVICE_ID, tgt, "Failed to take semaphore " #SEM " in file %s.!\n", __FILE__); Trace_Print(tgt, "Failed semaphore"); }
154154
#define WATCH_SEMAPHORE_TAKE(SEM, LABEL, N) k_sem_take(SEM, K_FOREVER);
155155
#endif
156156

right/src/event_scheduler.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "slave_drivers/uhk_module_driver.h"
1111
#include "peripherals/merge_sensor.h"
1212
#include "power_mode.h"
13+
#include "usb_report_updater.h"
1314
#include "oneshot.h"
1415
#include "trace.h"
1516

right/src/hid/command_app.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,19 @@ void command_app::get_report(hid::report::selector select, const std::span<uint8
6565

6666
void command_app::in_report_sent(const std::span<const uint8_t> &data)
6767
{
68+
#if DEVICE_IS_UHK80_RIGHT
69+
// On BLE all apps share one merged HOGP interface, so in_report_sent is broadcast
70+
// to every app; act only on our own (command) report ID. The USB handle is a
71+
// standalone interface (whose report may carry no report-ID byte), so the filter
72+
// must not be applied there.
73+
if ((this == &ble_handle()) && (data.front() != report_ids::IN_COMMAND)) {
74+
return;
75+
}
76+
#else
6877
if (data.front() != report_ids::IN_COMMAND) {
6978
return;
7079
}
80+
#endif
7181
auto buf_idx = in_buffer_.indexof(data.data());
7282
in_buffer_.compare_swap(buf_idx);
7383
}

right/src/hid/controls_app.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ int controls_app::send_report(const hid_controls_report_t &report)
3333

3434
void controls_app::in_report_sent(const std::span<const uint8_t> &data)
3535
{
36+
#if DEVICE_IS_UHK80_RIGHT
37+
// On BLE all apps share one merged HOGP interface, so in_report_sent is broadcast
38+
// to every app for every sent report. Act only on our own (controls) report ID.
39+
// The USB handle is a standalone interface, so the filter must not be applied there.
40+
if ((this == &ble_handle()) && (data.front() != report_ids::IN_CONTROLS)) {
41+
return;
42+
}
43+
#endif
3644
Hid_ControlsReportSentCallback((this == &usb_handle()) ? HID_TRANSPORT_USB : HID_TRANSPORT_BLE);
3745
}
3846

right/src/hid/keyboard_app.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,8 @@ void keyboard_app::set_report(hid::report::type type, const std::span<const uint
180180
void keyboard_app::in_report_sent(const std::span<const uint8_t> &data)
181181
{
182182
#if DEVICE_IS_UHK80_RIGHT
183-
if ((prot_ == hid::protocol::REPORT) && (data.front() != KEYS_NKRO_REPORT_ID) &&
184-
(data.front() != KEYS_6KRO_REPORT_ID)) {
183+
if ((this == &ble_handle()) && (prot_ == hid::protocol::REPORT) &&
184+
(data.front() != KEYS_NKRO_REPORT_ID) && (data.front() != KEYS_6KRO_REPORT_ID)) {
185185
return;
186186
}
187187
#endif

right/src/hid/mouse_app.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ int mouse_app::send_report(const hid_mouse_report_t &report)
3434

3535
void mouse_app::in_report_sent(const std::span<const uint8_t> &data)
3636
{
37+
#if DEVICE_IS_UHK80_RIGHT
38+
// On BLE all apps share one merged HOGP interface, so in_report_sent is broadcast
39+
// to every app for every sent report. Act only on our own (mouse) report ID. The
40+
// USB handle is a standalone interface that only ever receives mouse completions,
41+
// so the filter must not be applied there.
42+
if ((this == &ble_handle()) && (data.front() != report_ids::IN_MOUSE)) {
43+
return;
44+
}
45+
#endif
3746
Hid_MouseReportSentCallback((this == &usb_handle()) ? HID_TRANSPORT_USB : HID_TRANSPORT_BLE);
3847
}
3948

right/src/hid/transport.cpp

Lines changed: 44 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@ extern "C" {
1616
#include "timer.h"
1717
#include "trace.h"
1818
#include "usb_report_updater.h"
19+
#include "usb_semaphore.h"
20+
#include "usb_scheduler.h"
1921
#include "led_display.h"
2022
#include "jitter_test.h"
2123
#include "usb_state.h"
24+
#include "utils.h"
25+
#include "test_suite/test_hooks.h"
2226
}
2327
#include "command_app.hpp"
2428
#include "controls_app.hpp"
@@ -30,87 +34,37 @@ extern "C" {
3034
#error "Either CONFIG_DEBUG or NDEBUG must be defined"
3135
#endif
3236

33-
typedef enum {
34-
ReportSink_Invalid,
35-
ReportSink_Usb,
36-
ReportSink_BleHid,
37-
ReportSink_Dongle,
38-
} report_sink_t;
37+
#ifdef __ZEPHYR__
38+
#include <zephyr/logging/log.h>
39+
LOG_MODULE_REGISTER(Transport, LOG_LEVEL_INF);
40+
#endif
41+
// On mcux, logger.h provides the LOG_WRN / LOG_ERR / ... redirects.
3942

4043
// Exponential moving average (alpha=1/8) of the measured delay between a
4144
// BLE HID report being handed to the stack and the corresponding sent callback
42-
// firing. Populated when DEBUG_BLE_LATENCY_STATS is enabled; useful for
43-
// observing whether the send pipeline is saturated.
45+
// firing. Populated when DEBUG_BLE_LATENCY_STATS is enabled (in usb_report_sender.c);
46+
// useful for observing whether the send pipeline is saturated.
4447
extern "C" {
4548
float HidReportBleLatencyAvgMs = 0;
4649
}
47-
static uint32_t dispatchTimeMs = 0;
4850

49-
// Approximate transport window intervals (ms) used by the report-construction
50-
// throttle. After dispatch we estimate the next free window at "now + 2 *
51-
// interval" (worst case: we just missed a window). The send-completion
52-
// callback then reduces the estimate to "now + interval".
53-
static constexpr uint32_t USB_REPORT_INTERVAL_MS = 1;
54-
55-
static uint32_t reportIntervalForSink(report_sink_t sink)
56-
{
57-
switch (sink) {
58-
case ReportSink_Usb:
59-
return USB_REPORT_INTERVAL_MS;
60-
case ReportSink_BleHid:
61-
case ReportSink_Dongle:
62-
#if DEVICE_IS_UHK80_RIGHT
63-
return BtConn_GetReportIntervalMs(ActiveHostConnectionId);
64-
#else
65-
return 11;
66-
#endif
67-
default:
68-
return 0;
69-
}
70-
}
71-
72-
static void noteReportDispatched(report_sink_t sink)
73-
{
74-
if (DEBUG_BLE_LATENCY_STATS) {
75-
if (dispatchTimeMs == 0) {
76-
dispatchTimeMs = Timer_GetCurrentTime();
77-
}
78-
}
79-
UsbReportWindowEstimate = UsbReportWindowEstimateLast + 2 * reportIntervalForSink(sink);
80-
}
81-
82-
static void noteReportSent(report_sink_t transport)
83-
{
84-
if (DEBUG_BLE_LATENCY_STATS) {
85-
if (dispatchTimeMs != 0) {
86-
uint32_t delta = Timer_GetCurrentTime() - dispatchTimeMs;
87-
HidReportBleLatencyAvgMs = (HidReportBleLatencyAvgMs * 7 + delta) / 8;
88-
dispatchTimeMs = 0;
89-
}
90-
}
91-
uint32_t reportInterval = reportIntervalForSink(transport);
92-
uint32_t currentTime = Timer_GetCurrentTime();
93-
int16_t jitterGuess = (currentTime - UsbReportWindowEstimateLast - reportInterval + 1) / 2;
94-
jitterGuess = MAX(0, jitterGuess);
95-
UsbReportWindowEstimateLast = currentTime - jitterGuess;
96-
UsbReportWindowEstimate = currentTime - jitterGuess + reportInterval;
97-
uint32_t nextIn = UsbReportWindowEstimate - USB_REPORT_WINDOW_LOOKAHEAD_MS;
98-
99-
if (DEVICE_IS_UHK80_RIGHT) {
100-
EventScheduler_Schedule(nextIn, EventSchedulerEvent_Postponer, "Report sent. Recalculate report throttles");
101-
}
102-
}
51+
bool UnreliableTransportTestMode = false;
10352

10453
extern "C" void HidTransport_NoteNusReportSent(void)
10554
{
106-
noteReportSent(ReportSink_Dongle);
55+
UsbScheduler_ReportDelivered(ReportSink_Dongle);
10756
}
10857

10958
static report_sink_t determineSink()
11059
{
60+
if (TestHooks_Active) {
61+
return ReportSink_TestSuite;
62+
}
63+
11164
#if DEVICE_IS_UHK_DONGLE || DEVICE_IS_UHK60
11265
return ReportSink_Usb;
11366
#else
67+
11468
connection_type_t connectionType = Connections_Type(ActiveHostConnectionId);
11569

11670
if (!Connections_IsReady(ActiveHostConnectionId)) {
@@ -170,9 +124,12 @@ extern "C" void Hid_TransportStateChanged(
170124
extern "C" errno_t Hid_SendKeyboardReport(const hid_keyboard_report_t *report)
171125
{
172126
report_sink_t sink = determineSink();
173-
noteReportDispatched(sink);
127+
UsbScheduler_ReportAcceptedByTransport(sink);
174128
Trace_Printf("z11,%d", sink);
175129
errno_t err;
130+
if (UnreliableTransportTestMode && Utils_Random() % 7 == 0) {
131+
return -EAGAIN;
132+
}
176133
switch (sink) {
177134
case ReportSink_Usb:
178135
err = keyboard_app::usb_handle().send_report(*report);
@@ -187,9 +144,16 @@ extern "C" errno_t Hid_SendKeyboardReport(const hid_keyboard_report_t *report)
187144
err = Messenger_Send2(DeviceId_Uhk_Dongle, MessageId_SyncableProperty, SyncablePropertyId_KeyboardReport, (const uint8_t *)report, sizeof(*report));
188145
if (err != 0) {
189146
printk("Failed to send keyboard report to dongle: %d\n", err);
147+
} else {
148+
UsbSemaphore_Release(&UsbSemaphore.keyboard);
190149
}
191150
break;
192151
#endif
152+
case ReportSink_TestSuite:
153+
err = 0;
154+
TestHooks_CaptureReport(report);
155+
Hid_KeyboardReportSentCallback(HID_TRANSPORT_USB);
156+
break;
193157
default:
194158
#ifdef __ZEPHYR__
195159
printk("Unhandled and unexpected switch state!\n");
@@ -203,8 +167,11 @@ extern "C" errno_t Hid_SendKeyboardReport(const hid_keyboard_report_t *report)
203167

204168
extern "C" void Hid_KeyboardReportSentCallback(hid_transport_t transport)
205169
{
206-
UsbReportUpdateSemaphore &= ~UsbReportUpdate_Keyboard;
207-
noteReportSent(transport == HID_TRANSPORT_USB ? ReportSink_Usb : ReportSink_BleHid);
170+
if (UnreliableTransportTestMode && Utils_Random() % 7 == 0) {
171+
return;
172+
}
173+
UsbSemaphore_Release(&UsbSemaphore.keyboard);
174+
UsbScheduler_ReportDelivered(transport == HID_TRANSPORT_USB ? ReportSink_Usb : ReportSink_BleHid);
208175
#if DEVICE_IS_UHK_DONGLE
209176
Dongle_SignalUsbReportSent();
210177
#endif
@@ -213,7 +180,7 @@ extern "C" void Hid_KeyboardReportSentCallback(hid_transport_t transport)
213180
extern "C" errno_t Hid_SendMouseReport(const hid_mouse_report_t *report)
214181
{
215182
report_sink_t sink = determineSink();
216-
noteReportDispatched(sink);
183+
UsbScheduler_ReportAcceptedByTransport(sink);
217184
Trace_Printf("z21,%d", sink);
218185
errno_t err;
219186
switch (sink) {
@@ -230,6 +197,8 @@ extern "C" errno_t Hid_SendMouseReport(const hid_mouse_report_t *report)
230197
err = Messenger_Send2(DeviceId_Uhk_Dongle, MessageId_SyncableProperty, SyncablePropertyId_MouseReport, (const uint8_t *)report, sizeof(*report));
231198
if (err != 0) {
232199
printk("Failed to send mouse report to dongle: %d\n", err);
200+
} else {
201+
UsbSemaphore_Release(&UsbSemaphore.mouse);
233202
}
234203
break;
235204
#endif
@@ -249,8 +218,8 @@ extern "C" errno_t Hid_SendMouseReport(const hid_mouse_report_t *report)
249218

250219
extern "C" void Hid_MouseReportSentCallback(hid_transport_t transport)
251220
{
252-
UsbReportUpdateSemaphore &= ~UsbReportUpdate_Mouse;
253-
noteReportSent( transport == HID_TRANSPORT_USB ? ReportSink_Usb : ReportSink_BleHid);
221+
UsbSemaphore_Release(&UsbSemaphore.mouse);
222+
UsbScheduler_ReportDelivered( transport == HID_TRANSPORT_USB ? ReportSink_Usb : ReportSink_BleHid);
254223
#if DEVICE_IS_UHK_DONGLE
255224
Dongle_SignalUsbReportSent();
256225
#endif
@@ -259,7 +228,7 @@ extern "C" void Hid_MouseReportSentCallback(hid_transport_t transport)
259228
extern "C" errno_t Hid_SendControlsReport(const hid_controls_report_t *report)
260229
{
261230
report_sink_t sink = determineSink();
262-
noteReportDispatched(sink);
231+
UsbScheduler_ReportAcceptedByTransport(sink);
263232
Trace_Printf("z31,%d", sink);
264233
errno_t err;
265234
switch (sink) {
@@ -276,6 +245,8 @@ extern "C" errno_t Hid_SendControlsReport(const hid_controls_report_t *report)
276245
err = Messenger_Send2(DeviceId_Uhk_Dongle, MessageId_SyncableProperty, SyncablePropertyId_ControlsReport, (const uint8_t *)report, sizeof(*report));
277246
if (err != 0) {
278247
printk("Failed to send controls report to dongle: %d\n", err);
248+
} else {
249+
UsbSemaphore_Release(&UsbSemaphore.controls);
279250
}
280251
break;
281252
#endif
@@ -292,8 +263,8 @@ extern "C" errno_t Hid_SendControlsReport(const hid_controls_report_t *report)
292263

293264
extern "C" void Hid_ControlsReportSentCallback(hid_transport_t transport)
294265
{
295-
UsbReportUpdateSemaphore &= ~UsbReportUpdate_Controls;
296-
noteReportSent( transport == HID_TRANSPORT_USB ? ReportSink_Usb : ReportSink_BleHid);
266+
UsbSemaphore_Release(&UsbSemaphore.controls);
267+
UsbScheduler_ReportDelivered( transport == HID_TRANSPORT_USB ? ReportSink_Usb : ReportSink_BleHid);
297268
#if DEVICE_IS_UHK_DONGLE
298269
Dongle_SignalUsbReportSent();
299270
#endif

right/src/hid/transport.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ typedef enum {
1818
HID_TRANSPORT_BLE,
1919
} hid_transport_t;
2020

21+
// Which physical sink a report is dispatched to. Determined by transport.c's
22+
// determineSink(); shared so the report-sender module can size transport windows per sink.
23+
typedef enum {
24+
ReportSink_Invalid,
25+
ReportSink_Usb,
26+
ReportSink_BleHid,
27+
ReportSink_Dongle,
28+
ReportSink_TestSuite,
29+
} report_sink_t;
30+
2131
typedef enum
2232
{
2333
ROLLOVER_N_KEY = 0,
@@ -26,6 +36,7 @@ typedef enum
2636

2737

2838
extern float HidReportBleLatencyAvgMs;
39+
extern bool UnreliableTransportTestMode;
2940

3041
void Hid_TransportStateChanged(hid_transport_t transport, bool enabled);
3142

0 commit comments

Comments
 (0)