Skip to content

Commit 3690c41

Browse files
committed
Fill in multi-hogp sessions.
1 parent 5a14563 commit 3690c41

5 files changed

Lines changed: 135 additions & 33 deletions

File tree

device/src/bt_conn.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
#define BLE_ADDR_LEN 6
2929
#define BLE_KEY_LEN 16
3030

31+
// Holds each host peer's c2usb ble_session (~144 B); size checked in transport_ble.cpp.
32+
#define BLE_HID_SESSION_STORAGE_SIZE 160
33+
3134

3235
// Typedefs:
3336

@@ -46,6 +49,8 @@
4649
struct bt_conn* conn;
4750
uint32_t lastSwitchover;
4851
uint32_t bleReportIntervalMs;
52+
bool hidSessionActive;
53+
uint8_t hidSessionStorage[BLE_HID_SESSION_STORAGE_SIZE] __attribute__((aligned(8)));
4954
} peer_t;
5055

5156
typedef enum {

device/src/main.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,10 @@ void mainRuntime(void) {
196196

197197
}
198198

199+
#if DEVICE_IS_UHK80_RIGHT
200+
HOGP_Register(); // must be before bt_enable() registers static GATT services
201+
#endif
202+
199203
bt_enable(NULL); // has to be before InitSettings
200204

201205
// has to be after bt_enable; has to be before ApplyConfig

right/src/hid/transport.cpp

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ extern "C" {
2828
#include "controls_app.hpp"
2929
#include "keyboard_app.hpp"
3030
#include "mouse_app.hpp"
31+
#if DEVICE_IS_UHK80_RIGHT
32+
#include "ble_app.hpp"
33+
#endif
3134

3235
#if defined(__ZEPHYR__) && (defined(CONFIG_DEBUG) == defined(NDEBUG))
3336
#error "Either CONFIG_DEBUG or NDEBUG must be defined"
@@ -97,6 +100,23 @@ static report_sink_t determineSink()
97100
#endif
98101
}
99102

103+
#if DEVICE_IS_UHK80_RIGHT
104+
// Resolve the BLE HID session bound to the current host connection, if any.
105+
static ble_session *currentHostBleSession()
106+
{
107+
connection_id_t connId = ActiveHostConnectionId;
108+
if (connId <= ConnectionId_Invalid || connId >= ConnectionId_Count) {
109+
return nullptr;
110+
}
111+
uint8_t peerId = Connections[connId].peerId;
112+
if (peerId < PeerIdFirstHost || peerId > PeerIdLastHost) {
113+
return nullptr;
114+
}
115+
struct bt_conn *conn = Peers[peerId].conn;
116+
return conn ? ble_session::lookup_by_conn(conn) : nullptr;
117+
}
118+
#endif
119+
100120
// TODO: when switching sinks, or when USB only and transport comes up
101121
// keyboard_buffer.reset_to(session->protocol(), (session->channel() == hid::channel::BLE) ? HID_ROLLOVER_N_KEY : HID_GetKeyboardRollover());
102122

@@ -120,8 +140,7 @@ extern "C" errno_t Hid_SendKeyboardReport(const hid_keyboard_report_t *report)
120140
break;
121141
#if DEVICE_IS_UHK80_RIGHT
122142
case ReportSink_BleHid: {
123-
// TODO: select the BLE session by bt_conn pointer
124-
hid::session *session = nullptr;
143+
hid::session *session = currentHostBleSession();
125144

126145
if (!session) {
127146
break;
@@ -204,8 +223,7 @@ extern "C" errno_t Hid_SendMouseReport(const hid_mouse_report_t *report)
204223
break;
205224
#if DEVICE_IS_UHK80_RIGHT
206225
case ReportSink_BleHid: {
207-
// TODO: select the BLE session by bt_conn pointer
208-
hid::session *session = nullptr;
226+
hid::session *session = currentHostBleSession();
209227

210228
if (!session) {
211229
break;
@@ -268,8 +286,7 @@ extern "C" errno_t Hid_SendControlsReport(const hid_controls_report_t *report)
268286
break;
269287
#if DEVICE_IS_UHK80_RIGHT
270288
case ReportSink_BleHid: {
271-
// TODO: select the BLE session by bt_conn pointer
272-
hid::session *session = nullptr;
289+
hid::session *session = currentHostBleSession();
273290

274291
if (!session) {
275292
break;
@@ -361,7 +378,7 @@ extern "C" void Hid_UpdateKeyboardLedsState()
361378
break;
362379
#if DEVICE_IS_UHK80_RIGHT
363380
case ConnectionType_BtHid:
364-
// TODO
381+
session = currentHostBleSession();
365382
break;
366383
#endif
367384
case ConnectionType_NusDongle:
@@ -382,8 +399,16 @@ extern "C" void Hid_UpdateKeyboardLedsState()
382399
void keyboard_leds_changed_callback(keyboard_base_session &session)
383400
{
384401
#if DEVICE_IS_UHK80_RIGHT
385-
// TODO: adapt connection check
386-
connection_id_t connectionId = ConnectionId_UsbHidRight;
402+
connection_id_t connectionId;
403+
if (session.channel() == hid::channel::USB) {
404+
connectionId = ConnectionId_UsbHidRight;
405+
} else {
406+
struct bt_conn *conn = static_cast<ble_session &>(session).get_conn();
407+
int8_t peerId = conn ? GetPeerIdByConn(conn) : PeerIdUnknown;
408+
connectionId = (peerId >= PeerIdFirstHost && peerId <= PeerIdLastHost)
409+
? (connection_id_t)Peers[peerId].connectionId
410+
: ConnectionId_Invalid;
411+
}
387412
if (Connections_IsActiveHostConnection(connectionId)) {
388413
setKeyboardLedsState(session.get_leds_report());
389414
}
@@ -408,7 +433,9 @@ extern "C" float VerticalScrollMultiplier(void)
408433
switch (Connections_Type(ActiveHostConnectionId)) {
409434
#if DEVICE_IS_UHK80_RIGHT
410435
case ConnectionType_BtHid:
411-
// TODO: adapt to multiple BLE sessions
436+
if (auto *session = currentHostBleSession(); session) {
437+
return session->resolution_report().vertical_scroll_multiplier();
438+
}
412439
return 1.f;
413440
#endif
414441
case ConnectionType_NusDongle:
@@ -435,7 +462,9 @@ extern "C" float HorizontalScrollMultiplier(void)
435462
switch (Connections_Type(ActiveHostConnectionId)) {
436463
#if DEVICE_IS_UHK80_RIGHT
437464
case ConnectionType_BtHid:
438-
// TODO: adapt to multiple BLE sessions
465+
if (auto *session = currentHostBleSession(); session) {
466+
return session->resolution_report().horizontal_scroll_multiplier();
467+
}
439468
return 1.f;
440469
#endif
441470
case ConnectionType_NusDongle:

right/src/hid/transport.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,7 @@ void USB_Reconfigure(void);
5757
bool USB_IsMsHost(void);
5858

5959
// HOGP (BLE HID) management
60+
// Instantiates the HOGP GATT service; must be called before bt_enable() so the
61+
// static service entry is populated when Zephyr registers static services.
62+
void HOGP_Register(void);
6063
int HOGP_HealthCheck(void);

right/src/hid/transport_ble.cpp

Lines changed: 83 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,21 @@
22
#include <bluetooth/hid_over_gatt.hpp>
33
#include <zephyr/bluetooth/conn.h>
44
#include <zephyr/kernel.h>
5+
#include <new>
6+
extern "C" {
7+
#include "bt_conn.h"
8+
}
59

610
using namespace magic_enum::bitwise_operators;
711

12+
static_assert(sizeof(ble_session) <= BLE_HID_SESSION_STORAGE_SIZE, "BLE_HID_SESSION_STORAGE_SIZE too small for ble_session");
13+
static_assert(alignof(ble_session) <= 8, "ble_session alignment exceeds peer storage alignment");
14+
15+
static ble_session *peerSession(peer_t *peer)
16+
{
17+
return std::launder(reinterpret_cast<ble_session *>(peer->hidSessionStorage));
18+
}
19+
820
static auto &hog_service()
921
{
1022
using namespace magic_enum::bitwise_operators;
@@ -34,39 +46,88 @@ ::bt_conn *ble_session::get_conn()
3446

3547
hid::session &ble_app::start(const hid::session_params &params)
3648
{
37-
::bt_conn *conn = static_cast<bluetooth::hid_over_gatt::session_params>(params).conn;
38-
ble_session *sess;
39-
// TODO
40-
// create session from memory pool (allocate + construct)
41-
// Connections_SetStateAsync
49+
::bt_conn *conn = static_cast<const bluetooth::hid_over_gatt::session_params &>(params).conn;
50+
int8_t peerId = GetPeerIdByConn(conn);
51+
if (peerId < PeerIdFirstHost || peerId > PeerIdLastHost) {
52+
// A HOGP session should only ever start for a connected host peer
53+
printk("ble_app::start: no host peer for conn (peerId %d)\n", peerId);
54+
static ble_session fallback;
55+
return fallback;
56+
}
57+
peer_t *peer = &Peers[peerId];
58+
59+
// destroy any stale session left in this slot
60+
if (peer->hidSessionActive) {
61+
peerSession(peer)->~ble_session();
62+
peer->hidSessionActive = false;
63+
}
4264

43-
// mouse_resolution_changed_callback(*sess, sess->resolution_report());
65+
ble_session *sess = new (peer->hidSessionStorage) ble_session();
66+
peer->hidSessionActive = true;
67+
68+
if (peer->connectionId != ConnectionId_Invalid) {
69+
printk("ble_app::start: marking BtHid connection %d (peer %d) ready\n",
70+
peer->connectionId, peerId);
71+
Connections_SetStateAsync((connection_id_t)peer->connectionId, ConnectionState_Ready);
72+
} else {
73+
printk("ble_app::start: peer %d has invalid connectionId, cannot mark ready\n", peerId);
74+
}
4475
return *sess;
4576
}
4677

4778
void ble_app::stop(hid::session &sess)
4879
{
49-
// TODO
50-
// return session to memory pool (destruct + dealloc)
51-
// Connections_SetStateAsync
80+
for (uint8_t peerId = PeerIdFirstHost; peerId <= PeerIdLastHost; peerId++) {
81+
peer_t *peer = &Peers[peerId];
82+
if (!peer->hidSessionActive) {
83+
continue;
84+
}
85+
ble_session *ps = peerSession(peer);
86+
if (static_cast<hid::session *>(ps) == &sess) {
87+
// On a real disconnect bt_conn.c may already have cleared connectionId.
88+
if (peer->connectionId != ConnectionId_Invalid) {
89+
printk("ble_app::stop: marking BtHid connection %d (peer %d) disconnected\n",
90+
peer->connectionId, peerId);
91+
Connections_SetStateAsync(
92+
(connection_id_t)peer->connectionId, ConnectionState_Disconnected);
93+
} else {
94+
printk("ble_app::stop: peer %d has invalid connectionId\n", peerId);
95+
}
96+
ps->~ble_session();
97+
peer->hidSessionActive = false;
98+
return;
99+
}
100+
}
52101
}
53102

54-
extern "C" int HOGP_HealthCheck()
103+
extern "C" void HOGP_Register()
55104
{
56-
// TODO: refactoring needed
57-
struct bt_conn *peer = nullptr;
58-
if (!peer) {
59-
printk("HOGP HealthCheck: service registered, no active peer\n");
60-
return -2;
61-
}
105+
// Forces the function-local static HOGP service (and its bt_gatt_service_static
106+
// entry) to be constructed so bt_enable() can register it.
107+
(void)hog_service();
108+
}
62109

63-
struct bt_conn_info info;
64-
int err = bt_conn_get_info(peer, &info);
65-
if (err) {
66-
printk("HOGP HealthCheck: active peer has INVALID conn pointer (err %d)\n", err);
67-
return -3;
110+
extern "C" int HOGP_HealthCheck()
111+
{
112+
int activeSessions = 0;
113+
for (uint8_t peerId = PeerIdFirstHost; peerId <= PeerIdLastHost; peerId++) {
114+
peer_t *peer = &Peers[peerId];
115+
if (!peer->hidSessionActive) {
116+
continue;
117+
}
118+
activeSessions++;
119+
if (peer->conn == nullptr) {
120+
printk("HOGP HealthCheck: peer %s has an active session but no conn\n", peer->name);
121+
return -2;
122+
}
123+
struct bt_conn_info info;
124+
int err = bt_conn_get_info(peer->conn, &info);
125+
if (err) {
126+
printk("HOGP HealthCheck: peer %s has INVALID conn pointer (err %d)\n", peer->name, err);
127+
return -3;
128+
}
68129
}
69130

70-
printk("HOGP HealthCheck: OK (registered, peer connected, interval %u)\n", info.le.interval_us);
131+
printk("HOGP HealthCheck: OK (%d active HID session(s))\n", activeSessions);
71132
return 0;
72133
}

0 commit comments

Comments
 (0)