diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f0191edd..892a6350 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -3,10 +3,10 @@ name: CI
on:
push:
branches:
- - master
+ - master*
pull_request:
branches:
- - master
+ - master*
jobs:
release:
diff --git a/build.sh b/build.sh
index 65fef24a..fe13d55a 100755
--- a/build.sh
+++ b/build.sh
@@ -11,7 +11,7 @@ usage: ./build DEVICE1 DEVICE2 ... ACTION1 ACTION2 ...
DEVICE is in { uhk-80-left | uhk-80-right | uhk-60-right | uhk-dongle }
there are also these aliases: { left | right | dongle | all }
- ACTION is in { clean | setup | update | build | make | flash | flashUsb | shell | uart }
+ ACTION is in { clean | setup | update | build | make | flash | flashUsb | shell | uart | addrline
}
setup initialize submodules and set up zephyr environment
clean removes zephyr libraries
@@ -75,6 +75,19 @@ function processArguments() {
TARGET_TMUX_SESSION=$BUILD_SESSION_NAME
shift
;;
+ addrline)
+ shift
+ ADDR=$1
+ shift
+ for device in $DEVICES
+ do
+ echo "addrline for $ADDR:"
+ printf " "
+ # addr2line -e device/build/$device/zephyr/zephyr.elf $ADDR
+ arm-none-eabi-addr2line -e device/build/$device/zephyr/zephyr.elf $ADDR
+ done
+ exit 0
+ ;;
uart)
ACTIONS="$ACTIONS $1"
TARGET_TMUX_SESSION=$UART_SESSION_NAME
@@ -276,6 +289,8 @@ END
uart)
setupUartMonitor
;;
+ addrline)
+ ;;
*)
help
;;
diff --git a/device/prj.conf b/device/prj.conf
index 3baf7cce..079dbf37 100644
--- a/device/prj.conf
+++ b/device/prj.conf
@@ -95,4 +95,3 @@ CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y
# we can't just do it from the main thread
CONFIG_C2USB_UDC_MAC_THREAD_STACK_SIZE=2048
-
diff --git a/device/src/bt_advertise.c b/device/src/bt_advertise.c
index 929732d8..728caf86 100644
--- a/device/src/bt_advertise.c
+++ b/device/src/bt_advertise.c
@@ -1,7 +1,9 @@
#include "bt_advertise.h"
#include
#include
+#include "device.h"
+#undef DEVICE_NAME
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
@@ -36,7 +38,7 @@ static const struct bt_data sdHid[] = {SD_HID_DATA};
static const struct bt_data sdNusHid[] = {SD_NUS_DATA SD_HID_DATA};
-void Advertise(uint8_t adv_type)
+void BtAdvertise_Start(uint8_t adv_type)
{
int err;
const char *adv_type_string;
@@ -51,7 +53,7 @@ void Advertise(uint8_t adv_type)
adv_type_string = "HID";
err = bt_le_adv_start(BT_LE_ADV_CONN, adHid, ARRAY_SIZE(adHid), sdHid, ARRAY_SIZE(sdHid));
} else {
- assert(false);
+ printk("Attempted to start advertising without any type! Ignoring.\n");
return;
}
@@ -63,3 +65,26 @@ void Advertise(uint8_t adv_type)
printk("%s advertising failed to start (err %d)\n", adv_type_string, err);
}
}
+
+void BtAdvertise_Stop() {
+ int err = bt_le_adv_stop();
+ if (err) {
+ printk("Advertising failed to stop (err %d)\n", err);
+ } else {
+ printk("Advertising successfully stopped\n");
+ }
+}
+
+uint8_t BtAdvertise_Type() {
+ switch (DEVICE_ID) {
+ case DeviceId_Uhk80_Left:
+ return ADVERTISE_NUS;
+ case DeviceId_Uhk80_Right:
+ return ADVERTISE_NUS | ADVERTISE_HID;
+ case DeviceId_Uhk_Dongle:
+ return 0;
+ default:
+ printk("unknown device!\n");
+ return 0;
+ }
+}
diff --git a/device/src/bt_advertise.h b/device/src/bt_advertise.h
index 8859141b..f43a39c3 100644
--- a/device/src/bt_advertise.h
+++ b/device/src/bt_advertise.h
@@ -12,6 +12,8 @@
// Functions:
- extern void Advertise(uint8_t adv_type);
+ void BtAdvertise_Start(uint8_t adv_type);
+ void BtAdvertise_Stop();
+ uint8_t BtAdvertise_Type();
#endif // __BT_ADVERTISE_H__
diff --git a/device/src/bt_conn.c b/device/src/bt_conn.c
index 0baf70d6..47f72d04 100644
--- a/device/src/bt_conn.c
+++ b/device/src/bt_conn.c
@@ -4,17 +4,26 @@
#include
#include "bt_advertise.h"
#include "bt_conn.h"
+#include "bt_scan.h"
#include "device_state.h"
#include "keyboard/oled/screens/screen_manager.h"
#include "keyboard/oled/widgets/widget.h"
+#include "legacy/host_connection.h"
#include "nus_client.h"
#include "nus_server.h"
#include "device.h"
#include "keyboard/oled/screens/pairing_screen.h"
#include "usb/usb.h"
#include "keyboard/oled/widgets/widgets.h"
+#include
+#include "bt_pair.h"
+#include "bt_manager.h"
+#include
+
+bool Bt_NewPairedDevice = false;
-#define PeerCount 3
+#define BLE_KEY_LEN 16
+#define BLE_ADDR_LEN 6
peer_t Peers[PeerCount] = {
{
@@ -29,8 +38,13 @@ peer_t Peers[PeerCount] = {
.id = PeerIdDongle,
.name = "dongle",
},
+ {
+ .id = PeerIdHid,
+ .name = "bthid",
+ },
};
+
peer_t *getPeerByAddr(const bt_addr_le_t *addr) {
for (uint8_t i = 0; i < PeerCount; i++) {
if (bt_addr_le_eq(addr, &Peers[i].addr)) {
@@ -38,6 +52,17 @@ peer_t *getPeerByAddr(const bt_addr_le_t *addr) {
}
}
+ for (uint8_t hostConnectionId = 0; hostConnectionId < HOST_CONNECTION_COUNT_MAX; hostConnectionId++) {
+ host_connection_t* hostConnection = &HostConnections[hostConnectionId];
+
+ if (hostConnection->type == HostConnectionType_Dongle && bt_addr_le_eq(addr, &hostConnection->bleAddress)) {
+ return &Peers[PeerIdDongle];
+ }
+ if (hostConnection->type == HostConnectionType_Ble && bt_addr_le_eq(addr, &hostConnection->bleAddress)) {
+ return &Peers[PeerIdHid];
+ }
+ }
+
return NULL;
}
@@ -77,7 +102,7 @@ char *GetPeerStringByConn(const struct bt_conn *conn) {
static struct bt_conn_le_data_len_param *data_len;
-static void set_data_length_extension_params(struct bt_conn *conn) {
+static void enableDataLengthExtension(struct bt_conn *conn) {
data_len = BT_LE_DATA_LEN_PARAM_MAX;
int err = bt_conn_le_data_len_update(conn, data_len);
@@ -86,7 +111,10 @@ static void set_data_length_extension_params(struct bt_conn *conn) {
}
}
-static void set_latency_params(struct bt_conn *conn) {
+static void configureLatency(struct bt_conn *conn) {
+ // https://developer.apple.com/library/archive/qa/qa1931/_index.html
+ // https://punchthrough.com/manage-ble-connection/
+ // https://devzone.nordicsemi.com/f/nordic-q-a/28058/what-is-connection-parameters
static const struct bt_le_conn_param conn_params = BT_LE_CONN_PARAM_INIT(
6, 9, // keep it low, lowest allowed is 6 (7.5ms), lowest supported widely is 9 (11.25ms)
0, // keeping it higher allows power saving on peripheral when there's nothing to send (keep it under 30 though)
@@ -94,8 +122,19 @@ static void set_latency_params(struct bt_conn *conn) {
);
int err = bt_conn_le_param_update(conn, &conn_params);
if (err) {
- printk("LE latencies update failed: %d", err);
+ printk("LE latencies update failed: %d\n", err);
+ }
+}
+
+static void assignPeer(const bt_addr_le_t *addr, int8_t peerId) {
+ if (Peers[peerId].isConnected) {
+ char addrString[32];
+ bt_addr_le_to_str(addr, addrString, sizeof(addrString));
+ printk("Peer slot %s already occupied. Overwriting with address %s\n", Peers[peerId].name, addrString);
+ return;
}
+ Peers[peerId].addr = *addr;
+ Peers[peerId].isConnected = true;
}
static void connected(struct bt_conn *conn, uint8_t err) {
@@ -114,13 +153,16 @@ static void connected(struct bt_conn *conn, uint8_t err) {
return;
}
- printk("Connected to %s\n", GetPeerStringByConn(conn));
+ printk("Bt connected to %s\n", GetPeerStringByConn(conn));
if (peerId == PeerIdUnknown) {
+ peerId = PeerIdHid;
+ }
+
+ assignPeer(bt_conn_get_dst(conn), peerId);
+
+ if (peerId == PeerIdHid) {
if (DEVICE_IS_UHK80_RIGHT) {
- // https://developer.apple.com/library/archive/qa/qa1931/_index.html
- // https://punchthrough.com/manage-ble-connection/
- // https://devzone.nordicsemi.com/f/nordic-q-a/28058/what-is-connection-parameters
static const struct bt_le_conn_param conn_params = BT_LE_CONN_PARAM_INIT(
6, 9, // keep it low, lowest allowed is 6 (7.5ms), lowest supported widely is 9 (11.25ms)
10, // keeping it higher allows power saving on peripheral when there's nothing to send (keep it under 30 though)
@@ -129,17 +171,10 @@ static void connected(struct bt_conn *conn, uint8_t err) {
bt_conn_le_param_update(conn, &conn_params);
USB_DisableHid();
-
- DeviceState_SetConnection(ConnectionId_BluetoothHid, ConnectionType_Bt);
}
} else {
- set_latency_params(conn);
-
- set_data_length_extension_params(conn);
-
- if (DEVICE_IS_UHK80_RIGHT || DEVICE_IS_UHK_DONGLE) {
- NusClient_Setup(conn);
- }
+ bt_conn_set_security(conn, BT_SECURITY_L4);
+ // continue connection process in in `connectionSecured()`
}
}
@@ -147,23 +182,29 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) {
int8_t peerId = getPeerIdByConn(conn);
ARG_UNUSED(peerId);
- printk("Disconnected from %s, reason %u\n", GetPeerStringByConn(conn), reason);
+ printk("Bt disconnected from %s, reason %u\n", GetPeerStringByConn(conn), reason);
- if (DEVICE_IS_UHK80_RIGHT || DEVICE_IS_UHK_DONGLE) {
- if (peerId == PeerIdUnknown) {
- Advertise(ADVERTISE_NUS | ADVERTISE_HID);
- if (DEVICE_IS_UHK80_RIGHT) {
+ if (!BtPair_OobPairingInProgress && !BtManager_Restarting) {
+ if (DEVICE_IS_UHK80_RIGHT) {
+ if (peerId == PeerIdHid || peerId == PeerIdUnknown) {
+ BtAdvertise_Start(BtAdvertise_Type());
USB_EnableHid();
}
- } else if (peerId == PeerIdDongle) {
- Advertise(ADVERTISE_NUS);
- } else if (peerId == PeerIdLeft || peerId == PeerIdRight) {
- int err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
- printk("Start scan\n");
- if (err) {
- printk("Scanning failed to start (err %d)\n", err);
+ if (peerId == PeerIdDongle) {
+ BtAdvertise_Start(BtAdvertise_Type());
+ }
+ if (peerId == PeerIdLeft) {
+ BtScan_Start();
}
}
+
+ if (DEVICE_IS_UHK_DONGLE && peerId == PeerIdRight) {
+ BtScan_Start();
+ }
+
+ if (DEVICE_IS_UHK80_LEFT && peerId == PeerIdRight) {
+ BtScan_Start();
+ }
}
if (DEVICE_IS_UHK80_LEFT && peerId == PeerIdRight) {
@@ -181,20 +222,19 @@ static void disconnected(struct bt_conn *conn, uint8_t reason) {
if (peerId != PeerIdUnknown) {
Peers[peerId].isConnected = false;
+ Peers[peerId].isConnectedAndConfigured = false;
DeviceState_TriggerUpdate();
- } else {
- DeviceState_SetConnection(ConnectionId_BluetoothHid, ConnectionType_None);
}
}
bool Bt_DeviceIsConnected(device_id_t deviceId) {
switch (deviceId) {
case DeviceId_Uhk80_Left:
- return Peers[PeerIdLeft].isConnected;
+ return Peers[PeerIdLeft].isConnectedAndConfigured;
case DeviceId_Uhk80_Right:
- return Peers[PeerIdRight].isConnected;
+ return Peers[PeerIdRight].isConnectedAndConfigured;
case DeviceId_Uhk_Dongle:
- return Peers[PeerIdDongle].isConnected;
+ return Peers[PeerIdDongle].isConnectedAndConfigured;
default:
return false;
}
@@ -203,13 +243,13 @@ bool Bt_DeviceIsConnected(device_id_t deviceId) {
void Bt_SetDeviceConnected(device_id_t deviceId) {
switch (deviceId) {
case DeviceId_Uhk80_Left:
- Peers[PeerIdLeft].isConnected = true;
+ Peers[PeerIdLeft].isConnectedAndConfigured = true;
break;
case DeviceId_Uhk80_Right:
- Peers[PeerIdRight].isConnected = true;
+ Peers[PeerIdRight].isConnectedAndConfigured = true;
break;
case DeviceId_Uhk_Dongle:
- Peers[PeerIdDongle].isConnected = true;
+ Peers[PeerIdDongle].isConnectedAndConfigured = true;
break;
default:
break;
@@ -217,11 +257,29 @@ void Bt_SetDeviceConnected(device_id_t deviceId) {
DeviceState_TriggerUpdate();
}
-static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) {
- if (!err) {
- printk("Security changed: %s, level %u\n", GetPeerStringByConn(conn), level);
- } else {
- printk("Security failed: %s, level %u, err %d\n", GetPeerStringByConn(conn), level, err);
+static void securityChanged(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) {
+ int8_t peerId = getPeerIdByConn(conn);
+
+ bool isUhkPeer = peerId == PeerIdLeft || peerId == PeerIdRight || peerId == PeerIdDongle;
+ if (err || (isUhkPeer && level < BT_SECURITY_L4)) {
+ printk("Bt security failed: %s, level %u, err %d, disconnecting\n", GetPeerStringByConn(conn), level, err);
+ bt_conn_auth_cancel(conn);
+ return;
+ }
+
+ printk("Bt connection secured: %s, level %u, peerId %d\n", GetPeerStringByConn(conn), level, peerId);
+
+ if (isUhkPeer) {
+ configureLatency(conn);
+ enableDataLengthExtension(conn);
+
+ if (
+ (DEVICE_IS_UHK80_RIGHT && peerId == PeerIdLeft)
+ || (DEVICE_IS_UHK_DONGLE && peerId == PeerIdRight)
+ ) {
+ printk("Initiating NUS connection with %s\n", GetPeerStringByConn(conn));
+ NusClient_Connect(conn);
+ }
}
#if DEVICE_IS_UHK80_LEFT
@@ -229,9 +287,10 @@ static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_
#endif
}
-__attribute__((unused)) static void le_param_updated(struct bt_conn* conn, uint16_t interval, uint16_t latency, uint16_t timeout)
+__attribute__((unused)) static void infoLatencyParamsUpdated(struct bt_conn* conn, uint16_t interval, uint16_t latency, uint16_t timeout)
{
- if (getPeerIdByConn(conn) == PeerIdUnknown) {
+ uint8_t peerId = getPeerIdByConn(conn);
+ if (peerId == PeerIdUnknown || peerId == PeerIdHid) {
printk("BLE HID conn params: interval=%u ms, latency=%u, timeout=%u ms\n",
interval * 5 / 4, latency, timeout * 10);
}
@@ -240,8 +299,8 @@ __attribute__((unused)) static void le_param_updated(struct bt_conn* conn, uint1
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
- .security_changed = security_changed,
- .le_param_updated = le_param_updated,
+ .security_changed = securityChanged,
+ .le_param_updated = infoLatencyParamsUpdated,
};
// Auth callbacks
@@ -255,7 +314,19 @@ static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey)
static void auth_passkey_confirm(struct bt_conn *conn, unsigned int passkey) {
auth_conn = bt_conn_ref(conn);
+
+ printk("Received passkey pairing inquiry.\n");
+
if (!auth_conn) {
+ printk("Returning: no auth conn\n");
+ return;
+ }
+
+ int8_t peerId = getPeerIdByConn(conn);
+ bool isUhkPeer = peerId == PeerIdLeft || peerId == PeerIdRight || peerId == PeerIdDongle;
+ if (isUhkPeer || BtPair_OobPairingInProgress) {
+ printk("refusing passkey authentification for %s\n", GetPeerStringByConn(conn));
+ bt_conn_auth_cancel(conn);
return;
}
@@ -271,9 +342,34 @@ static void auth_cancel(struct bt_conn *conn) {
printk("Pairing cancelled: peer %s\n", GetPeerStringByConn(conn));
}
+static void auth_oob_data_request(struct bt_conn *conn, struct bt_conn_oob_info *oob_info) {
+ int err;
+ struct bt_conn_info info;
+
+ err = bt_conn_get_info(conn, &info);
+ if (err) {
+ return;
+ }
+
+
+ struct bt_le_oob* oobLocal = BtPair_GetLocalOob();
+ struct bt_le_oob* oobRemote = BtPair_GetRemoteOob();
+
+ if (memcmp(info.le.remote->a.val, oobRemote->addr.a.val, sizeof(info.le.remote->a.val))) {
+ printk("Addresses not matching! Cancelling authentication\n");
+ bt_conn_auth_cancel(conn);
+ return;
+ }
+
+ printk("Pairing OOB data requested!\n");
+
+ bt_le_oob_set_sc_data(conn, &oobLocal->le_sc_data, &oobRemote->le_sc_data);
+}
+
static struct bt_conn_auth_cb conn_auth_callbacks = {
.passkey_display = auth_passkey_display,
.passkey_confirm = auth_passkey_confirm,
+ .oob_data_request = auth_oob_data_request,
.cancel = auth_cancel,
};
@@ -281,6 +377,23 @@ static struct bt_conn_auth_cb conn_auth_callbacks = {
static void pairing_complete(struct bt_conn *conn, bool bonded) {
printk("Pairing completed: %s, bonded %d\n", GetPeerStringByConn(conn), bonded);
+ BtPair_EndPairing(true, "Successfuly bonded!");
+
+ bt_addr_le_t addr = *bt_conn_get_dst(conn);
+ uint8_t peerId = getPeerIdByConn(conn);
+ bool isUhkPeer = peerId == PeerIdLeft || peerId == PeerIdRight || peerId == PeerIdDongle;
+ if (!HostConnections_IsKnownBleAddress(&addr) && !isUhkPeer) {
+ Bt_NewPairedDevice = true;
+ }
+}
+
+static void bt_foreach_conn_cb(struct bt_conn *conn, void *user_data) {
+ bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
+ // gpt says you should unref here. Don't believe it!
+}
+
+void BtConn_DisconnectAll() {
+ bt_conn_foreach(BT_CONN_TYPE_LE, bt_foreach_conn_cb, NULL);
}
static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason) {
@@ -290,6 +403,7 @@ static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason) {
if (auth_conn == conn) {
bt_conn_unref(auth_conn);
+ printk("Pairing of auth conn failed because of %d\n", reason);
auth_conn = NULL;
}
@@ -301,8 +415,7 @@ static struct bt_conn_auth_info_cb conn_auth_info_callbacks = {
.pairing_failed = pairing_failed
};
-void bt_init(void)
-{
+void BtConn_Init(void) {
int err = 0;
err = bt_conn_auth_cb_register(&conn_auth_callbacks);
@@ -314,8 +427,6 @@ void bt_init(void)
if (err) {
printk("Failed to register authorization info callbacks.\n");
}
-
- bt_enable(NULL);
}
void num_comp_reply(uint8_t accept) {
diff --git a/device/src/bt_conn.h b/device/src/bt_conn.h
index f02328fb..911ddd70 100644
--- a/device/src/bt_conn.h
+++ b/device/src/bt_conn.h
@@ -9,13 +9,18 @@
// Macros:
- #define PeerCount 3
#define PeerNameMaxLength 8
#define PeerIdUnknown -1
#define PeerIdLeft 0
#define PeerIdRight 1
#define PeerIdDongle 2
+ #define PeerIdHid 3
+ #define PeerCount 4
+
+
+ #define BLE_ADDR_LEN 6
+ #define BLE_KEY_LEN 16
// Typedefs:
@@ -24,19 +29,23 @@
char name[PeerNameMaxLength + 1];
bt_addr_le_t addr;
bool isConnected;
+ bool isConnectedAndConfigured;
} peer_t;
+// Variables:
+
+ extern peer_t Peers[];
+ extern bool Bt_NewPairedDevice;
+
// Functions:
char *GetPeerStringByAddr(const bt_addr_le_t *addr);
char *GetPeerStringByConn(const struct bt_conn *conn);
- extern void bt_init(void);
extern void num_comp_reply(uint8_t accept);
void Bt_SetDeviceConnected(device_id_t deviceId);
bool Bt_DeviceIsConnected(uint8_t deviceId);
-// Variables:
-
- extern peer_t Peers[];
+ void BtConn_Init(void);
+ void BtConn_DisconnectAll();
#endif // __BT_CONN_H__
diff --git a/device/src/bt_manager.c b/device/src/bt_manager.c
new file mode 100644
index 00000000..d8c2fbfa
--- /dev/null
+++ b/device/src/bt_manager.c
@@ -0,0 +1,113 @@
+#include "bt_manager.h"
+#include "event_scheduler.h"
+#include "usb/usb.h"
+#include "bt_advertise.h"
+#include "nus_client.h"
+#include "nus_server.h"
+#include "legacy/event_scheduler.h"
+#include
+#include
+#include
+#include
+#include "bt_conn.h"
+#include "bt_scan.h"
+
+bool BtManager_Restarting = false;
+
+static void bt_ready(int err)
+{
+ if (err) {
+ printk("Bluetooth init failed (err %d)\n", err);
+ } else {
+ printk("Bluetooth initialized successfully\n");
+ }
+}
+
+void BtManager_InitBt() {
+ BtConn_Init();
+
+ if (DEVICE_IS_UHK80_LEFT || DEVICE_IS_UHK80_RIGHT) {
+ int err = NusServer_Init();
+ if (err) {
+ printk("NusServer_Init failed with error %d\n", err);
+ }
+ }
+
+ if (DEVICE_IS_UHK80_RIGHT || DEVICE_IS_UHK_DONGLE) {
+ BtScan_Init();
+ NusClient_Init();
+ }
+}
+
+void BtManager_StartBt() {
+ printk("Starting bluetooth services.\n");
+
+ if (DEVICE_IS_UHK80_RIGHT) {
+ HOGP_Enable();
+ }
+
+ if (DEVICE_IS_UHK80_LEFT || DEVICE_IS_UHK80_RIGHT) {
+ BtAdvertise_Start(BtAdvertise_Type());
+ }
+
+ if (DEVICE_IS_UHK80_RIGHT || DEVICE_IS_UHK_DONGLE) {
+ // This scan effectively initiates NUS client connection.
+ BtScan_Start();
+ }
+}
+
+void BtManager_StopBt() {
+ if (DEVICE_IS_UHK80_RIGHT) {
+ HOGP_Disable();
+ }
+
+ if (DEVICE_IS_UHK80_LEFT || DEVICE_IS_UHK80_RIGHT) {
+ BtAdvertise_Stop();
+ }
+
+ if (DEVICE_IS_UHK80_RIGHT || DEVICE_IS_UHK_DONGLE) {
+ BtScan_Stop();
+ }
+}
+
+void BtManager_RestartBt() {
+ printk("Going to reset bluetooth stack\n");
+
+ BtManager_Restarting = true;
+ int err;
+
+ BtManager_StopBt();
+
+ BtConn_DisconnectAll();
+
+ err = bt_disable();
+ if (err) {
+ printk("Bluetooth disable failed (err %d)\n", err);
+ return;
+ }
+
+ //wait for them to properly disconnect
+ k_sleep(K_MSEC(100));
+
+ err = bt_hci_cmd_send(BT_HCI_OP_RESET, NULL);
+ if (err) {
+ printk("HCI Reset failed (err %d)\n", err);
+ }
+
+ err = bt_enable(bt_ready);
+ if (err) {
+ printk("Bluetooth init failed (err %d)\n", err);
+ }
+
+ settings_load();
+
+ BtManager_StartBt();
+
+ BtManager_Restarting = false;
+
+ printk("Bluetooth subsystem restart finished\n");
+}
+
+void BtManager_RestartBtAsync() {
+ EventScheduler_Schedule(k_uptime_get()+10, EventSchedulerEvent_RestartBt, "Restart bluetooth");
+}
diff --git a/device/src/bt_manager.h b/device/src/bt_manager.h
new file mode 100644
index 00000000..76c5b653
--- /dev/null
+++ b/device/src/bt_manager.h
@@ -0,0 +1,25 @@
+#ifndef __BT_MANAGER_H__
+#define __BT_MANAGER_H__
+
+// Includes:
+
+ #include
+ #include
+ #include "device.h"
+
+// Macros:
+
+// Typedefs:
+
+// Variables:
+
+ extern bool BtManager_Restarting;
+
+// Functions:
+
+ void BtManager_InitBt();
+ void BtManager_StartBt();
+ void BtManager_StopBt();
+ void BtManager_RestartBt();
+
+#endif // __BT_MANAGER_H__
diff --git a/device/src/bt_pair.c b/device/src/bt_pair.c
new file mode 100644
index 00000000..5390c436
--- /dev/null
+++ b/device/src/bt_pair.c
@@ -0,0 +1,198 @@
+#include "bt_pair.h"
+#include "nus_client.h"
+#include
+#include
+#include
+#include
+#include
+#include "bt_conn.h"
+#include "bt_scan.h"
+#include "legacy/event_scheduler.h"
+#include "zephyr/kernel.h"
+#include "bt_manager.h"
+#include "bt_advertise.h"
+
+bool BtPair_LastPairingSucceeded = true;
+bool BtPair_OobPairingInProgress = false;
+
+static bool pairingAsCentral = false;
+static bool initialized = false;
+static struct bt_le_oob oobRemote;
+static struct bt_le_oob oobLocal;
+
+void BtManager_EnterPairingMode() {
+ printk("--- Entering pairing mode. Going to stop BT and disconnect all connections. ---\n");
+ BtPair_OobPairingInProgress = true;
+ BtManager_StopBt();
+ BtConn_DisconnectAll();
+}
+
+struct bt_le_oob* BtPair_GetLocalOob() {
+ if (!initialized) {
+ int err = bt_le_oob_get_local(BT_ID_DEFAULT, &oobLocal);
+ if (err) {
+ printk("Failed to get local OOB data (err %d)\n", err);
+ return NULL;
+ }
+ initialized = true;
+ }
+ return &oobLocal;
+}
+
+struct bt_le_oob* BtPair_GetRemoteOob() {
+ return &oobRemote;
+}
+
+void BtPair_SetRemoteOob(const struct bt_le_oob* oob) {
+ oobRemote = *oob;
+}
+
+void BtPair_PairCentral() {
+ pairingAsCentral = true;
+ settings_load();
+ bt_le_oob_set_sc_flag(true);
+ BtScan_Start();
+ printk ("Scanning for pairable device\n");
+ EventScheduler_Reschedule(k_uptime_get_32() + PAIRING_TIMEOUT, EventSchedulerEvent_EndBtPairing, "Oob pairing timeout.");
+}
+
+void BtPair_PairPeripheral() {
+ pairingAsCentral = false;
+ settings_load();
+ bt_le_oob_set_sc_flag(true);
+ BtAdvertise_Start(ADVERTISE_NUS);
+ printk ("Waiting for central to pair to me.\n");
+ EventScheduler_Reschedule(k_uptime_get_32() + PAIRING_TIMEOUT, EventSchedulerEvent_EndBtPairing, "Oob pairing timeout.");
+}
+
+void BtPair_EndPairing(bool success, const char* msg) {
+ printk("--- Pairing ended, success = %d: %s ---\n", success, msg);
+
+ initialized = false;
+
+ memset(&oobRemote, 0, sizeof(oobRemote));
+ memset(&oobLocal, 0, sizeof(oobLocal));
+
+ BtPair_OobPairingInProgress = false;
+ BtPair_LastPairingSucceeded = success;
+ bt_le_oob_set_sc_flag(false);
+ EventScheduler_Unschedule(EventSchedulerEvent_EndBtPairing);
+
+ if (pairingAsCentral) {
+ BtScan_Stop();
+ } else {
+ BtAdvertise_Stop();
+ }
+
+ k_sleep(K_MSEC(100));
+
+ BtManager_StartBt();
+}
+
+struct delete_args_t {
+ bool all;
+ const bt_addr_le_t* addr;
+};
+
+static void bt_foreach_bond_cb_delete(const struct bt_bond_info *info, void *user_data)
+{
+ int err;
+
+ struct bt_conn* conn;
+
+ struct delete_args_t* args = (struct delete_args_t*)user_data;
+
+ if (!args->all && bt_addr_le_cmp(args->addr, &info->addr) != 0) {
+ char addr[32];
+ bt_addr_le_to_str(&info->addr, addr, sizeof(addr));
+ printk("Not deleting bond for %s\n", addr);
+ return;
+ }
+
+ if (bt_addr_le_cmp(&Peers[PeerIdLeft].addr, &info->addr) == 0) {
+ settings_delete("uhk/addr/left");
+ }
+ if (bt_addr_le_cmp(&Peers[PeerIdRight].addr, &info->addr) == 0) {
+ settings_delete("uhk/addr/right");
+ }
+ if (bt_addr_le_cmp(&Peers[PeerIdDongle].addr, &info->addr) == 0) {
+ settings_delete("uhk/addr/dongle");
+ }
+
+ // Get the connection object if the device is currently connected
+ conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, &info->addr);
+
+ // Unpair the device
+ err = bt_unpair(BT_ID_DEFAULT, &info->addr);
+ if (err) {
+ printk("Failed to unpair (err %d)\n", err);
+ } else {
+ char addr[32];
+ bt_addr_le_to_str(&info->addr, addr, sizeof(addr));
+ printk("Unpaired device %s\n", addr);
+ }
+
+ // If the device was connected, release the connection object
+ if (conn) {
+ bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
+ bt_conn_unref(conn);
+ }
+}
+
+void BtPair_Unpair(const bt_addr_le_t addr) {
+ bool deleteAll = true;
+
+ for (uint8_t i = 0; i < BLE_ADDR_LEN; i++) {
+ if (addr.a.val[i] != 0) {
+ deleteAll = false;
+ break;
+ }
+ }
+
+ if (deleteAll) {
+ printk("Deleting all bonds!\n");
+ settings_delete("uhk/addr/left");
+ settings_delete("uhk/addr/right");
+ settings_delete("uhk/addr/dongle");
+ }
+
+ struct delete_args_t args = {
+ .all = deleteAll,
+ .addr = &addr
+ };
+
+ // Iterate through all stored bonds
+ bt_foreach_bond(BT_ID_DEFAULT, bt_foreach_bond_cb_delete, (void*)&args);
+}
+
+struct check_bonded_device_args_t {
+ const bt_addr_le_t* addr;
+ bool* bonded;
+};
+
+void checkBondedDevice(const struct bt_bond_info *info, void *user_data) {
+ struct check_bonded_device_args_t* args = (struct check_bonded_device_args_t*)user_data;
+ char addr[32];
+ bt_addr_le_to_str(&info->addr, addr, sizeof(addr));
+ char ref[32];
+ bt_addr_le_to_str(args->addr, ref, sizeof(ref));
+ if (bt_addr_le_cmp(&info->addr, args->addr) == 0) {
+ *args->bonded = true;
+ printk("Device %s is bonded, ref %s\n", addr, ref);
+ }
+};
+
+bool BtPair_IsDeviceBonded(const bt_addr_le_t *addr)
+{
+ bool bonded = false;
+
+ struct check_bonded_device_args_t args = {
+ .addr = addr,
+ .bonded = &bonded
+ };
+
+ // Iterate over all bonded devices
+ bt_foreach_bond(BT_ID_DEFAULT, checkBondedDevice, (void*)&args);
+
+ return bonded;
+}
diff --git a/device/src/bt_pair.h b/device/src/bt_pair.h
new file mode 100644
index 00000000..1b6f4230
--- /dev/null
+++ b/device/src/bt_pair.h
@@ -0,0 +1,34 @@
+#ifndef __BT_PAIR_H__
+#define __BT_PAIR_H__
+
+// Includes:
+
+ #include
+ #include
+ #include "device.h"
+ #include
+
+// Macros:
+
+// Typedefs:
+
+ #define PAIRING_TIMEOUT 20000
+
+// Functions:
+
+ struct bt_le_oob* BtPair_GetLocalOob();
+ struct bt_le_oob* BtPair_GetRemoteOob();
+ void BtPair_SetRemoteOob(const struct bt_le_oob* oob);
+ void BtPair_PairCentral();
+ void BtPair_PairPeripheral();
+ void BtPair_EndPairing(bool success, const char* msg);
+ void BtPair_Unpair(const bt_addr_le_t addr);
+ bool BtPair_IsDeviceBonded(const bt_addr_le_t *addr);
+ void BtManager_EnterPairingMode();
+
+// Variables
+
+ extern bool BtPair_OobPairingInProgress;
+ extern bool BtPair_LastPairingSucceeded;
+
+#endif // __BT_PAIR_H__
diff --git a/device/src/bt_scan.c b/device/src/bt_scan.c
index 9d55e4fe..a87c1990 100644
--- a/device/src/bt_scan.c
+++ b/device/src/bt_scan.c
@@ -1,6 +1,8 @@
#include
#include "bt_conn.h"
+#include "bt_pair.h"
#include "device.h"
+#include "legacy/host_connection.h"
static void scan_filter_match(struct bt_scan_device_info *device_info,
struct bt_scan_filter_match *filter_match, bool connectable)
@@ -19,7 +21,60 @@ static void scan_connecting(struct bt_scan_device_info *device_info, struct bt_c
BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL, scan_connecting_error, scan_connecting);
-int scan_init(void) {
+static void addAddress(int* err, bt_addr_le_t* addr) {
+ if (*err) {
+ return;
+ }
+
+ *err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_ADDR, addr);
+}
+
+static int scan_fill() {
+ int err = 0;
+
+ if (DEVICE_IS_UHK80_RIGHT) {
+ if (!BtPair_OobPairingInProgress) {
+ // iterate host connections and add all that are of type dongle
+ for (uint8_t i = 0; i < HOST_CONNECTION_COUNT_MAX; i++) {
+ if (HostConnections[i].type == HostConnectionType_Dongle) {
+ addAddress(&err, &HostConnections[i].bleAddress);
+ }
+ }
+ }
+
+ addAddress(&err, &Peers[PeerIdLeft].addr);
+ }
+ if (DEVICE_IS_UHK_DONGLE) {
+ addAddress(&err, &Peers[PeerIdRight].addr);
+ }
+
+ if (err) {
+ printk("Scanning filters cannot be set (err %d)\n", err);
+ return err;
+ }
+ return err;
+}
+
+int BtScan_Stop(void) {
+ int err;
+
+ bt_scan_stop();
+ bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
+ err = bt_scan_stop();
+ if (err) {
+ printk("Stop LE scan failed (err %d)\n", err);
+ } else {
+ printk("Scanning successfully stopped.\n");
+ }
+
+ bt_scan_filter_disable();
+
+ bt_scan_filter_remove_all();
+
+ return err;
+}
+
+int BtScan_Init(void) {
struct bt_scan_init_param scan_init = {
.connect_if_match = 1,
};
@@ -27,21 +82,14 @@ int scan_init(void) {
bt_scan_init(&scan_init);
bt_scan_cb_register(&scan_cb);
+ printk("Scan module initialized\n");
+ return 0;
+}
+
+int BtScan_Start(void) {
int err;
- if (DEVICE_IS_UHK80_RIGHT) {
- err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_ADDR, &Peers[PeerIdLeft].addr);
- if (err) {
- printk("Scanning filters cannot be set (err %d)\n", err);
- return err;
- }
- }
- if (DEVICE_IS_UHK_DONGLE) {
- err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_ADDR, &Peers[PeerIdRight].addr);
- if (err) {
- printk("Scanning filters cannot be set (err %d)\n", err);
- return err;
- }
- }
+
+ scan_fill();
err = bt_scan_filter_enable(BT_SCAN_ADDR_FILTER, false);
if (err) {
@@ -49,6 +97,12 @@ int scan_init(void) {
return err;
}
- printk("Scan module initialized\n");
+ err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
+ if (err) {
+ printk("Scanning failed to start (err %d)\n", err);
+ } else {
+ printk("Scanning successfully started\n");
+ }
+
return err;
}
diff --git a/device/src/bt_scan.h b/device/src/bt_scan.h
index 5cdd0627..f09172cc 100644
--- a/device/src/bt_scan.h
+++ b/device/src/bt_scan.h
@@ -3,6 +3,8 @@
// Functions:
- extern int scan_init(void);
+ int BtScan_Init(void);
+ int BtScan_Start(void);
+ int BtScan_Stop(void);
#endif // __BT_SCAN_H__
diff --git a/device/src/keyboard/key_scanner.c b/device/src/keyboard/key_scanner.c
index 65d61487..5b222d72 100644
--- a/device/src/keyboard/key_scanner.c
+++ b/device/src/keyboard/key_scanner.c
@@ -65,9 +65,9 @@ ATTR_UNUSED static void reportChange(uint8_t sourceIndex, bool active) {
uint8_t keyId = KeyLayout_Uhk80_to_Uhk60[slotId][sourceIndex];
const char* abbrev = MacroKeyIdParser_KeyIdToAbbreviation(slotId*64 + keyId);
if (active) {
- LogRight(LogTarget_Uart, "%s down\n", abbrev);
+ Log("%s down\n", abbrev);
} else {
- LogRight(LogTarget_Uart, " %s up\n", abbrev);
+ Log(" %s up\n", abbrev);
}
}
diff --git a/device/src/keyboard/uart.c b/device/src/keyboard/uart.c
index 8c234630..a6a7f362 100644
--- a/device/src/keyboard/uart.c
+++ b/device/src/keyboard/uart.c
@@ -176,6 +176,11 @@ void Uart_SendPacket(const uint8_t* data, uint16_t len) {
txPosition = 0;
+ if (len > 0) {
+ processOutgoingByte(DEVICE_ID);
+ processOutgoingByte(DEVICE_ID == DeviceId_Uhk80_Right ? DeviceId_Uhk80_Left : DeviceId_Uhk80_Right);
+ }
+
for (uint16_t i = 0; i < len; i++) {
processOutgoingByte(data[i]);
}
@@ -190,6 +195,9 @@ void Uart_SendMessage(message_t msg) {
txPosition = 0;
+ processOutgoingByte(msg.src);
+ processOutgoingByte(msg.dst);
+
for (uint8_t id = 0; id < msg.idsUsed; id++) {
processOutgoingByte(msg.messageId[id]);
}
diff --git a/device/src/legacy/host_connection.c b/device/src/legacy/host_connection.c
new file mode 120000
index 00000000..94690908
--- /dev/null
+++ b/device/src/legacy/host_connection.c
@@ -0,0 +1 @@
+../../../right/src/host_connection.c
\ No newline at end of file
diff --git a/device/src/legacy/usb_commands/usb_command_get_new_pairings.c b/device/src/legacy/usb_commands/usb_command_get_new_pairings.c
new file mode 120000
index 00000000..6fa51561
--- /dev/null
+++ b/device/src/legacy/usb_commands/usb_command_get_new_pairings.c
@@ -0,0 +1 @@
+../../../../right/src/usb_commands/usb_command_get_new_pairings.c
\ No newline at end of file
diff --git a/device/src/legacy/usb_commands/usb_command_get_new_pairings.h b/device/src/legacy/usb_commands/usb_command_get_new_pairings.h
new file mode 120000
index 00000000..f2611136
--- /dev/null
+++ b/device/src/legacy/usb_commands/usb_command_get_new_pairings.h
@@ -0,0 +1 @@
+../../../../right/src/usb_commands/usb_command_get_new_pairings.h
\ No newline at end of file
diff --git a/device/src/legacy/usb_commands/usb_command_pairing.c b/device/src/legacy/usb_commands/usb_command_pairing.c
new file mode 120000
index 00000000..15aceaa2
--- /dev/null
+++ b/device/src/legacy/usb_commands/usb_command_pairing.c
@@ -0,0 +1 @@
+../../../../right/src/usb_commands/usb_command_pairing.c
\ No newline at end of file
diff --git a/device/src/legacy/usb_commands/usb_command_pairing.h b/device/src/legacy/usb_commands/usb_command_pairing.h
new file mode 120000
index 00000000..d87599a7
--- /dev/null
+++ b/device/src/legacy/usb_commands/usb_command_pairing.h
@@ -0,0 +1 @@
+../../../../right/src/usb_commands/usb_command_pairing.h
\ No newline at end of file
diff --git a/device/src/logger.c b/device/src/logger.c
index 56d4c7fd..01dc4d22 100644
--- a/device/src/logger.c
+++ b/device/src/logger.c
@@ -9,46 +9,41 @@
#include "device.h"
#include "messenger.h"
#include "legacy/macros/status_buffer.h"
+#include "zephyr/device.h"
#ifdef DEVICE_HAS_OLED
#include "keyboard/oled/widgets/console_widget.h"
#endif
+#define MAX_LOG_LENGTH 64
+
+#define EXPAND_STRING(BUFFER) \
+char BUFFER[MAX_LOG_LENGTH]; \
+{ \
+ va_list myargs; \
+ va_start(myargs, fmt); \
+ BUFFER[MAX_LOG_LENGTH-1] = '\0'; \
+ vsnprintf(BUFFER, MAX_LOG_LENGTH-1, fmt, myargs); \
+}
+
void Uart_LogConstant(const char* buffer) {
printk("%s", buffer);
}
void Uart_Log(const char *fmt, ...) {
- va_list myargs;
- va_start(myargs, fmt);
- char buffer[256];
- vsprintf(buffer, fmt, myargs);
+ EXPAND_STRING(buffer);
Uart_LogConstant(buffer);
}
void Log(const char *fmt, ...) {
- va_list myargs;
- va_start(myargs, fmt);
- char buffer[256];
- vsprintf(buffer, fmt, myargs);
+ EXPAND_STRING(buffer);
- Uart_LogConstant(buffer);
-#if DEVICE_HAS_OLED
- Oled_LogConstant(buffer);
-#endif
+ LogConstantTo(DeviceId_Uhk_Dongle, LogTarget_Uart, buffer);
}
-
-void LogRight(log_target_t logMask, const char *fmt, ...) {
- va_list myargs;
- va_start(myargs, fmt);
- static char buffer[64];
- vsprintf(buffer, fmt, myargs);
- buffer[63]=0;
-
- // on right, log according to logMask
- if (DEVICE_ID == DeviceId_Uhk80_Right) {
+void LogConstantTo(device_id_t deviceId, log_target_t logMask, const char* buffer) {
+ if (DEVICE_ID == deviceId) {
if (logMask & LogTarget_Oled) {
Oled_LogConstant(buffer);
}
@@ -58,10 +53,14 @@ void LogRight(log_target_t logMask, const char *fmt, ...) {
if (logMask & LogTarget_ErrorBuffer) {
Macros_ReportPrintf(NULL, "%s", buffer);
}
+ } else {
+ Messenger_Send2(deviceId, MessageId_Log, logMask, buffer, strlen(buffer)+1);
}
+}
- if (DEVICE_ID == DeviceId_Uhk80_Left) {
- Messenger_Send2(DeviceId_Uhk80_Right, MessageId_Log, logMask, buffer, strlen(buffer)+1);
- }
+void LogTo(device_id_t deviceId, log_target_t logMask, const char *fmt, ...) {
+ EXPAND_STRING(buffer);
+
+ LogConstantTo(deviceId, logMask, buffer);
}
diff --git a/device/src/logger.h b/device/src/logger.h
index 32e71cd0..681d4d19 100644
--- a/device/src/logger.h
+++ b/device/src/logger.h
@@ -21,6 +21,7 @@ typedef enum {
void Uart_LogConstant(const char* buffer);
void Uart_Log(const char *fmt, ...);
void Log(const char *fmt, ...);
- void LogRight(log_target_t logMask, const char *fmt, ...);
+ void LogTo(device_id_t deviceId, log_target_t logMask, const char *fmt, ...);
+ void LogConstantTo(device_id_t deviceId, log_target_t logMask, const char* buffer);
#endif // __LOGGER_H__
diff --git a/device/src/main.c b/device/src/main.c
index 20d765f6..0a86aa42 100644
--- a/device/src/main.c
+++ b/device/src/main.c
@@ -1,4 +1,8 @@
#include "main.h"
+#include "bt_advertise.h"
+#include "nus_client.h"
+#include "nus_server.h"
+#include "bt_manager.h"
#include "legacy/config_parser/config_globals.h"
#include "legacy/ledmap.h"
#include "shared/attributes.h"
@@ -10,15 +14,12 @@
#include "keyboard/charger.h"
#include "keyboard/spi.h"
#include "keyboard/uart.h"
-#include "nus_client.h"
-#include "nus_server.h"
#include "keyboard/i2c.h"
#include "peripherals/merge_sensor.h"
#include "shell.h"
#include "device.h"
#include "usb/usb.h"
#include "bt_conn.h"
-#include "bt_advertise.h"
#include "settings.h"
#include "flash.h"
#include "usb_commands/usb_command_apply_config.h"
@@ -150,27 +151,14 @@ int main(void) {
USB_EnableHid(); // has to be after USB_SetSerialNumber
- bt_init();
- InitSettings();
+ bt_enable(NULL);
- if (DEVICE_IS_UHK80_RIGHT) {
- HOGP_Enable();
- }
-
- if (DEVICE_IS_UHK80_LEFT || DEVICE_IS_UHK80_RIGHT) {
- int err = NusServer_Init();
- if (!err) {
- uint8_t advType = ADVERTISE_NUS;
- if (DEVICE_IS_UHK80_RIGHT) {
- advType |= ADVERTISE_HID;
- }
- Advertise(advType);
- }
- }
+ // has to be after bt_enable
+ InitSettings();
- if (DEVICE_IS_UHK80_RIGHT || DEVICE_IS_UHK_DONGLE) {
- NusClient_Init();
- }
+ // has to be after InitSettings
+ BtManager_InitBt();
+ BtManager_StartBt();
if (!DEVICE_IS_UHK_DONGLE) {
InitCharger(); // has to be after usb initialization
diff --git a/device/src/messenger.c b/device/src/messenger.c
index 9ac09faa..b2bf2110 100644
--- a/device/src/messenger.c
+++ b/device/src/messenger.c
@@ -33,50 +33,105 @@ typedef enum {
static messenger_channel_t determineChannel(device_id_t dst) {
#if DEVICE_IS_KEYBOARD
- if (Uart_IsConnected() && (dst == DeviceId_Uhk80_Left || dst == DeviceId_Uhk80_Right)) {
- return MessengerChannel_Uart;
- }
-#endif
-
- if (Bt_DeviceIsConnected(dst)) {
+ if (Uart_IsConnected()) {
if (DEVICE_IS_UHK80_LEFT) {
switch (dst) {
+ case DeviceId_Uhk_Dongle:
case DeviceId_Uhk80_Right:
- return MessengerChannel_NusServer;
+ return MessengerChannel_Uart;
default:
- return MessengerChannel_None;
+ break;
}
}
if (DEVICE_IS_UHK80_RIGHT) {
switch (dst) {
case DeviceId_Uhk_Dongle:
- return MessengerChannel_NusServer;
+ break;
case DeviceId_Uhk80_Left:
- return MessengerChannel_NusClient;
+ return MessengerChannel_Uart;
default:
- return MessengerChannel_None;
+ break;
}
}
+ }
+#endif
- if (DEVICE_IS_UHK_DONGLE) {
- switch (dst) {
- case DeviceId_Uhk80_Right:
+ if (DEVICE_IS_UHK80_LEFT && Bt_DeviceIsConnected(DeviceId_Uhk80_Right)) {
+ switch (dst) {
+ case DeviceId_Uhk_Dongle:
+ case DeviceId_Uhk80_Right:
+ if (Bt_DeviceIsConnected(DeviceId_Uhk80_Right)) {
+ return MessengerChannel_NusServer;
+ }
+ default:
+ return MessengerChannel_None;
+ }
+ }
+
+ if (DEVICE_IS_UHK80_RIGHT) {
+ switch (dst) {
+ case DeviceId_Uhk_Dongle:
+ if (Bt_DeviceIsConnected(DeviceId_Uhk_Dongle)) {
+ return MessengerChannel_NusServer;
+ }
+ break;
+ case DeviceId_Uhk80_Left:
+ if (Bt_DeviceIsConnected(DeviceId_Uhk80_Left)) {
return MessengerChannel_NusClient;
- default:
- return MessengerChannel_None;
- }
+ }
+ break;
+ default:
+ return MessengerChannel_None;
+ }
+ }
+
+ if (DEVICE_IS_UHK_DONGLE) {
+ switch (dst) {
+ case DeviceId_Uhk80_Right:
+ case DeviceId_Uhk80_Left:
+ if (Bt_DeviceIsConnected(DeviceId_Uhk80_Right)) {
+ return MessengerChannel_NusClient;
+ }
+ break;
+ default:
+ return MessengerChannel_None;
}
}
return MessengerChannel_None;
}
+static void receiveLog(device_id_t src, const uint8_t* data, uint16_t len) {
+ uint8_t ATTR_UNUSED messageId = *(data++);
+ uint8_t logmask = *(data++);
+ char deviceAbbrev;
+ switch (src) {
+ case DeviceId_Uhk80_Left:
+ deviceAbbrev = 'L';
+ break;
+ case DeviceId_Uhk80_Right:
+ deviceAbbrev = 'R';
+ break;
+ case DeviceId_Uhk_Dongle:
+ deviceAbbrev = 'D';
+ break;
+ default:
+ deviceAbbrev = '?';
+ break;
+ }
+ LogTo(DEVICE_ID, logmask, "%c>>> %s", deviceAbbrev, data);
+}
+
+
static void receiveLeft(device_id_t src, const uint8_t* data, uint16_t len) {
switch (data[0]) {
case MessageId_StateSync:
StateSync_ReceiveStateUpdate(src, data, len);
break;
+ case MessageId_Log:
+ receiveLog(src, data, len);
+ break;
default:
printk("Didn't expect to receive message %i %i\n", data[0], data[1]);
break;
@@ -108,27 +163,6 @@ static void processSyncablePropertyRight(device_id_t src, const uint8_t* data, u
}
}
-static void receiveLog(device_id_t src, const uint8_t* data, uint16_t len) {
- uint8_t ATTR_UNUSED messageId = *(data++);
- uint8_t logmask = *(data++);
- char deviceAbbrev;
- switch (src) {
- case DeviceId_Uhk80_Left:
- deviceAbbrev = 'L';
- break;
- case DeviceId_Uhk80_Right:
- deviceAbbrev = 'R';
- break;
- case DeviceId_Uhk_Dongle:
- deviceAbbrev = 'D';
- break;
- default:
- deviceAbbrev = '?';
- break;
- }
- LogRight(logmask, "%c %s", deviceAbbrev, data);
-}
-
static void receiveRight(device_id_t src, const uint8_t* data, uint16_t len) {
switch (data[0]) {
case MessageId_StateSync:
@@ -174,28 +208,47 @@ static void receiveDongle(device_id_t src, const uint8_t* data, uint16_t len) {
case MessageId_StateSync:
StateSync_ReceiveStateUpdate(src, data, len);
break;
+ case MessageId_Log:
+ receiveLog(src, data, len);
+ break;
default:
printk("Unrecognized or unexpected message [%i, %i, ...]\n", data[0], data[1]);
break;
}
}
-static void receive(device_id_t src, const uint8_t* data, uint16_t len) {
- switch (DEVICE_ID) {
- case DeviceId_Uhk80_Left:
- receiveLeft(src, data, len);
- break;
- case DeviceId_Uhk80_Right:
- receiveRight(src, data, len);
- break;
- case DeviceId_Uhk_Dongle:
- receiveDongle(src, data, len);
- break;
+static void receive(const uint8_t* data, uint16_t len) {
+ device_id_t src = *data++;
+ device_id_t dst = *data++;
+ len-= 2;
+
+ if (dst != DEVICE_ID) {
+ message_t msg = {
+ .data = data,
+ .len = len,
+ .idsUsed = 0,
+ .src = src,
+ .dst = dst,
+ };
+ printk("Forwarding message from %d to %d\n", msg.src, msg.dst);
+ Messenger_SendMessage(msg);
+ } else {
+ switch (DEVICE_ID) {
+ case DeviceId_Uhk80_Left:
+ receiveLeft(src, data, len);
+ break;
+ case DeviceId_Uhk80_Right:
+ receiveRight(src, data, len);
+ break;
+ case DeviceId_Uhk_Dongle:
+ receiveDongle(src, data, len);
+ break;
+ }
}
}
void Messenger_Enqueue(uint8_t src, const uint8_t* data, uint16_t len) {
- if (data[0] != MessageId_Ping) {
+ if (data[2] != MessageId_Ping) {
MessengerQueue_Put(src, data, len);
EventVector_Set(EventVector_NewMessage);
Main_Wake();
@@ -206,7 +259,7 @@ void Messenger_ProcessQueue() {
EventVector_Unset(EventVector_NewMessage);
messenger_queue_record_t rec = MessengerQueue_Take();
while (rec.data != NULL) {
- receive(rec.src, rec.data, rec.len);
+ receive(rec.data, rec.len);
MessengerQueue_FreeMemory(rec.data);
rec = MessengerQueue_Take();
@@ -231,8 +284,9 @@ bool Messenger_Availability(device_id_t dst, messenger_availability_op_t operati
}
}
-void Messenger_SendMessage(device_id_t dst, message_t message) {
- messenger_channel_t channel = determineChannel(dst);
+void Messenger_SendMessage(message_t message) {
+ messenger_channel_t channel = determineChannel(message.dst);
+ device_id_t dst = message.dst;
switch (channel) {
case MessengerChannel_Uart:
@@ -253,13 +307,28 @@ void Messenger_SendMessage(device_id_t dst, message_t message) {
}
void Messenger_Send(device_id_t dst, uint8_t messageId, const uint8_t* data, uint16_t len) {
- message_t msg = { .data = data, .len = len, .messageId[0] = messageId, .idsUsed = 1 };
- Messenger_SendMessage(dst, msg);
+ message_t msg = {
+ .data = data,
+ .len = len,
+ .messageId[0] = messageId,
+ .idsUsed = 1,
+ .src = DEVICE_ID,
+ .dst = dst,
+ };
+ Messenger_SendMessage(msg);
}
void Messenger_Send2(device_id_t dst, uint8_t messageId, uint8_t messageId2, const uint8_t* data, uint16_t len) {
- message_t msg = { .data = data, .len = len, .messageId[0] = messageId, .messageId[1] = messageId2, .idsUsed = 2 };
- Messenger_SendMessage(dst, msg);
+ message_t msg = {
+ .data = data,
+ .len = len,
+ .messageId[0] = messageId,
+ .messageId[1] = messageId2,
+ .idsUsed = 2,
+ .src = DEVICE_ID,
+ .dst = dst,
+ };
+ Messenger_SendMessage(msg);
}
void Messenger_Init() {
diff --git a/device/src/messenger.h b/device/src/messenger.h
index ed400076..c792fe27 100644
--- a/device/src/messenger.h
+++ b/device/src/messenger.h
@@ -28,12 +28,14 @@
uint16_t len;
uint8_t messageId[2];
uint8_t idsUsed;
+ uint8_t src;
+ uint8_t dst;
} ATTR_PACKED message_t;
// Functions:
void Messenger_Receive(uint8_t src, const uint8_t* data, uint16_t len);
- void Messenger_SendMessage(uint8_t dst, message_t message);
+ void Messenger_SendMessage(message_t message);
void Messenger_Send(uint8_t dst, uint8_t messageId, const uint8_t* data, uint16_t len);
void Messenger_Send2(uint8_t dst, uint8_t messageId, uint8_t messageId2, const uint8_t* data, uint16_t len);
bool Messenger_Availability(uint8_t dst, messenger_availability_op_t operation);
diff --git a/device/src/nus_client.c b/device/src/nus_client.c
index 1a2e974a..7f438928 100644
--- a/device/src/nus_client.c
+++ b/device/src/nus_client.c
@@ -14,10 +14,12 @@
#include "legacy/module.h"
#include "legacy/key_states.h"
#include "keyboard/oled/widgets/console_widget.h"
+#include "state_sync.h"
#include "usb/usb_compatibility.h"
#include "link_protocol.h"
#include "messenger_queue.h"
#include "legacy/debug.h"
+#include
static struct bt_nus_client nus_client;
@@ -51,14 +53,32 @@ static uint8_t ble_data_received(struct bt_nus_client *nus, const uint8_t *data,
static void discovery_complete(struct bt_gatt_dm *dm, void *context) {
struct bt_nus_client *nus = context;
- printk("Service discovery completed\n");
+ int err = 0;
bt_gatt_dm_data_print(dm);
- bt_nus_handles_assign(dm, nus);
- bt_nus_subscribe_receive(nus);
+ err = bt_nus_handles_assign(dm, nus);
- bt_gatt_dm_data_release(dm);
+ if (err) {
+ printk("Could not assign NUS handles (err %d)\n", err);
+ return;
+ }
+
+ err = bt_nus_subscribe_receive(nus);
+
+ if (err) {
+ printk("Could not subscribe to NUS notifications (err %d)\n", err);
+ return;
+ }
+
+ err = bt_gatt_dm_data_release(dm);
+
+ if (err) {
+ printk("Could not release the discovery data (err %d)\n", err);
+ return;
+ }
+
+ printk("NUS connection with %s successfully established\n", GetPeerStringByConn(nus->conn));
if (DEVICE_ID == DeviceId_Uhk80_Right) {
Bt_SetDeviceConnected(DeviceId_Uhk80_Left);
@@ -82,7 +102,7 @@ struct bt_gatt_dm_cb discovery_cb = {
.error_found = discovery_error,
};
-void gatt_discover(struct bt_conn *conn) {
+static void gatt_discover(struct bt_conn *conn) {
int err = bt_gatt_dm_start(conn, BT_UUID_NUS_SERVICE, &discovery_cb, &nus_client);
if (err) {
printk("could not start the discovery procedure, error code: %d\n", err);
@@ -97,7 +117,7 @@ static void exchange_func(struct bt_conn *conn, uint8_t err, struct bt_gatt_exch
}
}
-void NusClient_Setup(struct bt_conn *conn) {
+void NusClient_Connect(struct bt_conn *conn) {
static struct bt_gatt_exchange_params exchange_params;
exchange_params.func = exchange_func;
@@ -106,15 +126,10 @@ void NusClient_Setup(struct bt_conn *conn) {
printk("MTU exchange failed with %s, err %d\n", GetPeerStringByConn(conn), err);
}
- err = bt_conn_set_security(conn, BT_SECURITY_L2);
- if (err) {
- printk("Failed to set security for %s: %d\n", GetPeerStringByConn(conn), err);
- }
-
gatt_discover(conn);
err = bt_scan_stop();
- if ((!err) && (err != -EALREADY)) {
+ if (err && (err != -EALREADY)) {
printk("Stop LE scan failed (err %d)\n", err);
}
}
@@ -125,11 +140,7 @@ void NusClient_Disconnected() {
}
void NusClient_Init(void) {
- int err = scan_init();
- if (err != 0) {
- printk("scan_init failed (err %d)\n", err);
- return;
- }
+ int err;
struct bt_nus_client_init_param init = {
.cb = {
@@ -145,14 +156,6 @@ void NusClient_Init(void) {
}
printk("NUS Client module initialized\n");
-
- err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
- if (err) {
- printk("Scanning failed to start (err %d)\n", err);
- return;
- }
-
- printk("Scanning successfully started\n");
}
bool NusClient_Availability(messenger_availability_op_t operation) {
@@ -170,7 +173,7 @@ bool NusClient_Availability(messenger_availability_op_t operation) {
}
}
-void NusClient_Send(const uint8_t *data, uint16_t len) {
+static void send_raw_buffer(const uint8_t *data, uint16_t len) {
SEM_TAKE(&nusBusy);
int err = bt_nus_client_send(&nus_client, data, len);
if (err) {
@@ -181,17 +184,21 @@ void NusClient_Send(const uint8_t *data, uint16_t len) {
void NusClient_SendMessage(message_t msg) {
uint8_t buffer[MAX_LINK_PACKET_LENGTH];
+ uint8_t bufferIdx = 0;
+
+ buffer[bufferIdx++] = msg.src;
+ buffer[bufferIdx++] = msg.dst;
for (uint8_t id = 0; id < msg.idsUsed; id++) {
- buffer[id] = msg.messageId[id];
+ buffer[bufferIdx++] = msg.messageId[id];
}
- if (msg.len + msg.idsUsed > MAX_LINK_PACKET_LENGTH) {
+ if (msg.len + msg.idsUsed + 2 > MAX_LINK_PACKET_LENGTH) {
printk("Message is too long for NUS packets! [%i, %i, ...]\n", buffer[0], buffer[1]);
return;
}
- memcpy(&buffer[msg.idsUsed], msg.data, msg.len);
+ memcpy(&buffer[bufferIdx], msg.data, msg.len);
- NusClient_Send(buffer, msg.len+msg.idsUsed);
+ send_raw_buffer(buffer, msg.len+msg.idsUsed+2);
}
diff --git a/device/src/nus_client.h b/device/src/nus_client.h
index 9b07f9a4..7d0d71b5 100644
--- a/device/src/nus_client.h
+++ b/device/src/nus_client.h
@@ -8,12 +8,10 @@
// Functions:
- extern void NusClient_Init(void);
+ void NusClient_Init(void);
void NusClient_Disconnected();
- extern void gatt_discover(struct bt_conn *conn);
- extern void NusClient_Setup(struct bt_conn *conn);
- extern void NusClient_Send(const uint8_t *data, uint16_t len);
- extern void NusClient_SendMessage(message_t msg);
- extern bool NusClient_Availability(messenger_availability_op_t operation);
+ void NusClient_Connect(struct bt_conn *conn);
+ void NusClient_SendMessage(message_t msg);
+ bool NusClient_Availability(messenger_availability_op_t operation);
#endif // __NUS_CLIENT_H__
diff --git a/device/src/nus_server.c b/device/src/nus_server.c
index 2aab3896..19f9485c 100644
--- a/device/src/nus_server.c
+++ b/device/src/nus_server.c
@@ -7,15 +7,32 @@
#include "device.h"
#include "messenger_queue.h"
#include "legacy/debug.h"
+#include "zephyr/bluetooth/addr.h"
#define NUS_SLOTS 2
static K_SEM_DEFINE(nusBusy, NUS_SLOTS, NUS_SLOTS);
+static void setPeerConnected(uint8_t peerId, device_id_t peerDeviceId, struct bt_conn *conn) {
+ const bt_addr_le_t *addr = bt_conn_get_dst(conn);
+ if (!Peers[peerId].isConnected || bt_addr_le_eq(&Peers[peerId].addr, addr) != 0) {
+ Peers[peerId].addr = *addr;
+ Bt_SetDeviceConnected(peerDeviceId);
+ }
+}
+
static void received(struct bt_conn *conn, const uint8_t *const data, uint16_t len) {
uint8_t* copy = MessengerQueue_AllocateMemory();
memcpy(copy, data, len);
+ if (DEVICE_ID == DeviceId_Uhk80_Left) {
+ setPeerConnected(PeerIdRight, DeviceId_Uhk80_Right, conn);
+ }
+
+ if (DEVICE_ID == DeviceId_Uhk80_Right) {
+ setPeerConnected(PeerIdDongle, DeviceId_Uhk_Dongle, conn);
+ }
+
switch (DEVICE_ID) {
case DeviceId_Uhk80_Left:
Messenger_Enqueue(DeviceId_Uhk80_Right, copy, len);
@@ -38,12 +55,8 @@ static void sent(struct bt_conn *conn) {
static void send_enabled(enum bt_nus_send_status status)
{
if (status == BT_NUS_SEND_STATUS_ENABLED) {
- if (DEVICE_ID == DeviceId_Uhk80_Left) {
- Bt_SetDeviceConnected(DeviceId_Uhk80_Right);
- }
- if (DEVICE_ID == DeviceId_Uhk80_Right) {
- Bt_SetDeviceConnected(DeviceId_Uhk_Dongle);
- }
+ // in theory, NUS is ready. In practice, it is once we receive a message from the client.
+ printk("NUS peripheral connection is ready.\n");
}
}
@@ -57,9 +70,12 @@ int NusServer_Init(void) {
int err = bt_nus_init(&nus_cb);
if (err) {
printk("Failed to initialize UART service (err: %d)\n", err);
+ return err;
}
- return err;
+ printk("NUS Server module initialized.\n");
+
+ return 0;
}
void NusServer_Disconnected() {
@@ -67,7 +83,7 @@ void NusServer_Disconnected() {
k_sem_init(&nusBusy, NUS_SLOTS, NUS_SLOTS);
}
-void NusServer_Send(const uint8_t *data, uint16_t len) {
+static void send_raw_buffer(const uint8_t *data, uint16_t len) {
SEM_TAKE(&nusBusy);
int err = bt_nus_send(NULL, data, len);
if (err) {
@@ -93,17 +109,21 @@ bool NusServer_Availability(messenger_availability_op_t operation) {
void NusServer_SendMessage(message_t msg) {
uint8_t buffer[MAX_LINK_PACKET_LENGTH];
+ uint8_t bufferIdx = 0;
+
+ buffer[bufferIdx++] = msg.src;
+ buffer[bufferIdx++] = msg.dst;
for (uint8_t id = 0; id < msg.idsUsed; id++) {
- buffer[id] = msg.messageId[id];
+ buffer[bufferIdx++] = msg.messageId[id];
}
- if (msg.len + msg.idsUsed > MAX_LINK_PACKET_LENGTH) {
+ if (msg.len + msg.idsUsed + 2 > MAX_LINK_PACKET_LENGTH) {
printk("Message is too long for NUS packets! [%i, %i, ...]\n", buffer[0], buffer[1]);
return;
}
- memcpy(&buffer[msg.idsUsed], msg.data, msg.len);
+ memcpy(&buffer[bufferIdx], msg.data, msg.len);
- NusServer_Send(buffer, msg.len+msg.idsUsed);
+ send_raw_buffer(buffer, msg.len+msg.idsUsed+2);
}
diff --git a/device/src/nus_server.h b/device/src/nus_server.h
index 4491062d..8e2cc45f 100644
--- a/device/src/nus_server.h
+++ b/device/src/nus_server.h
@@ -10,7 +10,6 @@
extern int NusServer_Init(void);
extern void NusServer_Disconnected();
- extern void NusServer_Send(const uint8_t *data, uint16_t len);
extern void NusServer_SendMessage(message_t msg);
extern bool NusServer_Availability(messenger_availability_op_t operation);
diff --git a/device/src/stack_trace.c b/device/src/stack_trace.c
new file mode 100644
index 00000000..d58c7883
--- /dev/null
+++ b/device/src/stack_trace.c
@@ -0,0 +1,65 @@
+#include "stack_trace.h"
+#include "shared/attributes.h"
+#include "shared/atomicity.h"
+#include
+#include
+#include
+#include
+
+// With this config, zephyr defines its own handler, leading to multiple definition error
+#ifndef CONFIG_RESET_ON_FATAL_ERROR
+
+#define MAX_STACK_DEPTH 32
+#define RAW_STACK_DUMP_SIZE 64
+
+static bool is_valid_code_address(uint32_t addr) {
+ return (addr >= (uint32_t)__rom_region_start && addr < (uint32_t)__rom_region_end);
+}
+
+static bool is_valid_ram_address(uint32_t addr) {
+ extern char _image_ram_start[];
+ extern char _image_ram_end[];
+ return (addr >= (uint32_t)_image_ram_start && addr < (uint32_t)_image_ram_end);
+}
+
+void print_stack_trace(const z_arch_esf_t *esf) {
+ uint32_t *sp = (uint32_t *)esf;
+ uint32_t lr = esf->basic.lr;
+ uint32_t pc = esf->basic.pc;
+
+ printk("Stack trace:\n");
+ printk(" 0x%08x (PC)\n", pc);
+
+ if (is_valid_code_address(lr & ~1)) {
+ printk(" 0x%08x (LR)\n", lr & ~1);
+ }
+
+ // Walk up the stack
+ for (int i = 0; i < MAX_STACK_DEPTH && is_valid_ram_address((uint32_t)sp); i++) {
+ uint32_t value = *sp;
+ if (is_valid_code_address(value & ~1)) {
+ printk(" 0x%08x\n", value & ~1);
+ }
+ sp++;
+ }
+ printk("To translate to code, you can use:\n ./build.sh right addrline 0x1234\n arm-none-eabi-addr2line -e device/build/$device/zephyr/zephyr.elf $ADDR\n");
+}
+
+void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *esf)
+{
+ // Disable interrupts to prevent re-entrance
+ ATTR_UNUSED DISABLE_IRQ();
+
+ printk("*** Kernel Fatal Error %d ***\n", reason);
+ printk("Current thread: %p\n", k_current_get());
+
+ print_stack_trace(esf);
+
+ // Halt the system
+ printk("System halted\n");
+ while (1) {
+ k_cpu_idle();
+ }
+}
+
+#endif
diff --git a/device/src/stack_trace.h b/device/src/stack_trace.h
new file mode 100644
index 00000000..f9c62bd1
--- /dev/null
+++ b/device/src/stack_trace.h
@@ -0,0 +1,18 @@
+#ifndef __STACK_TRACE_H__
+#define __STACK_TRACE_H__
+
+// Following kconfig is needed for the custom handler:
+// CONFIG_RESET_ON_FATAL_ERROR=n
+
+// Includes:
+
+// Macros:
+
+// Typedefs:
+
+// Variables:
+
+// Functions:
+
+#endif // __MAIN_H__
+
diff --git a/device/src/state_sync.c b/device/src/state_sync.c
index 927a2042..be866605 100644
--- a/device/src/state_sync.c
+++ b/device/src/state_sync.c
@@ -25,6 +25,8 @@
#include "legacy/peripherals/merge_sensor.h"
#include "power_mode.h"
+#define STATE_SYNC_SEND_DELAY 2
+
#define THREAD_STACK_SIZE 2000
#define THREAD_PRIORITY 5
static K_THREAD_STACK_DEFINE(stack_area_left, THREAD_STACK_SIZE);
@@ -581,7 +583,7 @@ static void updateLoopRightLeft() {
if (!isConnected || handlePropertyUpdateLeftToRight()) {
k_sleep(K_FOREVER);
} else {
- k_sleep(K_MSEC(1));
+ k_sleep(K_MSEC(STATE_SYNC_SEND_DELAY));
}
}
}
@@ -593,7 +595,7 @@ static void updateLoopRightLeft() {
if (!isConnected || handlePropertyUpdateRightToLeft()) {
k_sleep(K_FOREVER);
} else {
- k_sleep(K_MSEC(1));
+ k_sleep(K_MSEC(STATE_SYNC_SEND_DELAY));
}
}
}
@@ -607,7 +609,7 @@ static void updateLoopRightDongle() {
if (!isConnected || handlePropertyUpdateRightToDongle()) {
k_sleep(K_FOREVER);
} else {
- k_sleep(K_MSEC(1));
+ k_sleep(K_MSEC(STATE_SYNC_SEND_DELAY));
}
}
}
@@ -619,7 +621,7 @@ static void updateLoopRightDongle() {
if (!isConnected || handlePropertyUpdateDongleToRight()) {
k_sleep(K_FOREVER);
} else {
- k_sleep(K_MSEC(1));
+ k_sleep(K_MSEC(STATE_SYNC_SEND_DELAY));
}
}
}
diff --git a/device/src/state_sync.h b/device/src/state_sync.h
index cda8280a..2fda7730 100644
--- a/device/src/state_sync.h
+++ b/device/src/state_sync.h
@@ -66,34 +66,34 @@
// Draft for generic properties
typedef enum {
StateSyncPropertyId_LayerActionsLayer1 = 1,
- StateSyncPropertyId_LayerActionsLayer2,
- StateSyncPropertyId_LayerActionsLayer3,
- StateSyncPropertyId_LayerActionsLayer4,
- StateSyncPropertyId_LayerActionsLayer5,
- StateSyncPropertyId_LayerActionsLayer6,
- StateSyncPropertyId_LayerActionsLayer7,
- StateSyncPropertyId_LayerActionsLayer8,
- StateSyncPropertyId_LayerActionsLayer9,
- StateSyncPropertyId_LayerActionsLayer10,
- StateSyncPropertyId_LayerActionsLayer11,
- StateSyncPropertyId_LayerActionsLayer12,
+ StateSyncPropertyId_LayerActionsLayer2 = 2,
+ StateSyncPropertyId_LayerActionsLayer3 = 3,
+ StateSyncPropertyId_LayerActionsLayer4 = 4,
+ StateSyncPropertyId_LayerActionsLayer5 = 5,
+ StateSyncPropertyId_LayerActionsLayer6 = 6,
+ StateSyncPropertyId_LayerActionsLayer7 = 7,
+ StateSyncPropertyId_LayerActionsLayer8 = 8,
+ StateSyncPropertyId_LayerActionsLayer9 = 9,
+ StateSyncPropertyId_LayerActionsLayer10 = 10,
+ StateSyncPropertyId_LayerActionsLayer11 = 11,
+ StateSyncPropertyId_LayerActionsLayer12 = 12,
StateSyncPropertyId_LayerActionFirst = StateSyncPropertyId_LayerActionsLayer1,
StateSyncPropertyId_LayerActionLast = StateSyncPropertyId_LayerActionsLayer12,
- StateSyncPropertyId_LayerActionsClear,
- StateSyncPropertyId_ActiveLayer,
- StateSyncPropertyId_Backlight,
- StateSyncPropertyId_ActiveKeymap,
- StateSyncPropertyId_Battery,
- StateSyncPropertyId_KeyboardLedsState,
- StateSyncPropertyId_ResetRightLeftLink,
- StateSyncPropertyId_ResetRightDongleLink,
- StateSyncPropertyId_ModuleStateLeftHalf,
- StateSyncPropertyId_ModuleStateLeftModule,
- StateSyncPropertyId_LeftModuleDisconnected,
- StateSyncPropertyId_MergeSensor,
- StateSyncPropertyId_FunctionalColors,
- StateSyncPropertyId_PowerMode,
- StateSyncPropertyId_Config,
+ StateSyncPropertyId_LayerActionsClear = 13,
+ StateSyncPropertyId_ActiveLayer = 14,
+ StateSyncPropertyId_Backlight = 15,
+ StateSyncPropertyId_ActiveKeymap = 16,
+ StateSyncPropertyId_Battery = 17,
+ StateSyncPropertyId_KeyboardLedsState = 18,
+ StateSyncPropertyId_ResetRightLeftLink = 19,
+ StateSyncPropertyId_ResetRightDongleLink = 20,
+ StateSyncPropertyId_ModuleStateLeftHalf = 21,
+ StateSyncPropertyId_ModuleStateLeftModule = 22,
+ StateSyncPropertyId_LeftModuleDisconnected = 23,
+ StateSyncPropertyId_MergeSensor = 24,
+ StateSyncPropertyId_FunctionalColors = 25,
+ StateSyncPropertyId_PowerMode = 26,
+ StateSyncPropertyId_Config = 27,
StateSyncPropertyId_Count,
} state_sync_prop_id_t;
diff --git a/doc-dev/other/pairing/README.md b/doc-dev/other/pairing/README.md
new file mode 100644
index 00000000..9f2c8b4b
--- /dev/null
+++ b/doc-dev/other/pairing/README.md
@@ -0,0 +1,8 @@
+These scripts serve as a proof of concept of oob pairing. For simplicity, we exchange keys in both directions, although carrying peripheral (NUS server) oob to central (NUS client) is necessary. However, we still need the address, which we currently take from the oob.
+
+- cmd.sh encapsulates byte communication with UHK
+- pair.sh does the pairing.
+
+These scritps are to be placed in the agent/packages/usb directory.
+
+
diff --git a/doc-dev/other/pairing/cmd.sh b/doc-dev/other/pairing/cmd.sh
new file mode 100755
index 00000000..8fc3072e
--- /dev/null
+++ b/doc-dev/other/pairing/cmd.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+file=send-command.ts
+pwd=`pwd`
+
+
+function determineUsbDeviceArg() {
+ DEVICE=$1
+ DEVICEUSBID=""
+
+ case $DEVICE in
+ left|uhk-80-left)
+ DEVICEUSBID="--vid=0x37a8 --pid=7 --usb-interface=2"
+ ;;
+ right|uhk-80-right)
+ DEVICEUSBID="--vid=0x37a8 --pid=9 --usb-interface=2"
+ ;;
+ dongle|uhk-dongle)
+ DEVICEUSBID="--vid=0x37a8 --pid=5 --usb-interface=2"
+ ;;
+ uhk-60)
+ ;;
+ esac
+
+ echo $DEVICEUSBID
+}
+
+ADDR=$(determineUsbDeviceArg $1)
+shift
+
+#ARGS=--log=usb
+
+echo "executing" $pwd/$file $ADDR $ARGS $@
+$pwd/$file $ADDR $ARGS $@
+
diff --git a/doc-dev/other/pairing/pair.sh b/doc-dev/other/pairing/pair.sh
new file mode 100755
index 00000000..7b0caebf
--- /dev/null
+++ b/doc-dev/other/pairing/pair.sh
@@ -0,0 +1,103 @@
+#!/bin/bash +x
+
+# I am somewhat confused about ble address endianity. If you feel something is wrong, please let me know...
+
+# Pairing process:
+# - Enter pairing mode
+# - (Optional) delete some or all bonds. If bonds are deleted outside of pairing mode, the device may try to reconnect and be treated as HID device, which urrently results in loosing usb connection.
+# - Retrieve pairing data for both devices
+# - Set pairing data for both devices
+# - Start pairing for both devices. (They will automatically exit pairing mode after success or timeout.)
+
+function extractData() {
+ cat | grep '^[0-9].*' | sed 's/^ *[0-9]* *//;s/0 *$//'
+}
+
+dongleAddress=`./cmd.sh dongle 0 9 | extractData`
+donglesPairedKeyboardAddress=`./cmd.sh dongle 0 10 | extractData`
+
+echo "dongleAddress: $dongleAddress"
+echo "donglesPairedKeyboardAddress: $donglesPairedKeyboardAddress"
+
+#enter pairing mode
+./cmd.sh dongle 0x1c > /dev/null
+./cmd.sh right 0x1c > /dev/null
+
+#delete all bonds
+./cmd.sh dongle 0x1a 0 0 0 0 0 0 > /dev/null
+./cmd.sh right 0x1a 0 0 0 0 0 0 > /dev/null
+
+echo "All bonds deleted"
+
+#(sed strips status code and removes one trailing 0 byte)
+# the payload is:
+# 6 bytes address
+# 16 bytes r key
+# 16 bytes c key
+
+rightKey=`./cmd.sh right 0x16 | extractData`
+dongleKey=`./cmd.sh dongle 0x16 | extractData`
+
+echo "rightKey: $rightKey"
+echo "dongleKey: $dongleKey"
+
+pairingStatus=`./cmd.sh dongle 0 11 | extractData`
+echo "dongle pairing status: $pairingStatus"
+
+# write the payloads to the other device, and inform it of the peerId
+# left 0
+# right 1
+# dongle 2
+./cmd.sh right 0x17 2 $dongleKey > /dev/null
+./cmd.sh dongle 0x17 1 $rightKey > /dev/null
+
+echo "keys exchanged!"
+
+# tell them to pair
+./cmd.sh right 0x18 > /dev/null
+./cmd.sh dongle 0x19 > /dev/null
+
+echo "Pairing started!"
+
+sleep 1
+
+pairingStatus=`./cmd.sh dongle 0 11 | extractData`
+echo "dongle pairing status: $pairingStatus"
+
+echo "Hopefully, right <--> dongle are paired now; Tap key to continue..."
+read a
+
+#enter pairing mode
+./cmd.sh left 0x1c > /dev/null
+./cmd.sh right 0x1c > /dev/null
+
+# delete left bonds
+./cmd.sh left 0x1a 0 0 0 0 0 0 > /dev/null
+
+# get keys
+leftKey=`./cmd.sh left 0x16 | extractData`
+rightKey=`./cmd.sh right 0x16 | extractData`
+
+echo "leftKey: $leftKey"
+echo "rightKey: $rightKey"
+
+# exchange keys
+./cmd.sh left 0x17 1 $rightKey
+./cmd.sh right 0x17 0 $leftKey
+
+# pair
+./cmd.sh left 0x18
+./cmd.sh right 0x19
+
+sleep 1
+
+echo "Hopefully, right <--> left are paired now"
+
+# check if the devices are paired
+#we care about address only in the key
+rightPairedInDongle=`./cmd.sh dongle 0x1b $rightKey | extractData`
+donglePairedInRight=`./cmd.sh right 0x1b $dongleKey | extractData`
+leftPairedInDongle=`./cmd.sh dongle 0x1b $leftKey | extractData`
+
+echo -e "ring <-> dongle paired: \n $rightPairedInDongle \n $donglePairedInRight \ndongle to left paired: \n $leftPairedInDongle"
+
diff --git a/right/src/config_parser/parse_config.c b/right/src/config_parser/parse_config.c
index 423edc9f..d74b2572 100644
--- a/right/src/config_parser/parse_config.c
+++ b/right/src/config_parser/parse_config.c
@@ -51,6 +51,13 @@ parser_error_t parseConfig(config_buffer_t *buffer)
DataModelVersion.major = ReadUInt16(buffer);
DataModelVersion.minor = ReadUInt16(buffer);
DataModelVersion.patch = ReadUInt16(buffer);
+
+#ifdef __ZEPHYR__
+ if (!ParserRunDry) {
+ printk("Flashed User Config version: %u.%u.%u\n", DataModelVersion.major, DataModelVersion.minor, DataModelVersion.patch);
+ }
+#endif
+
uint32_t userConfigLength = DataModelVersion.major < 6 ? ReadUInt16(buffer) : ReadUInt32(buffer);
const char *deviceName = ReadString(buffer, &len);
uint16_t doubleTapSwitchLayerTimeout = ReadUInt16(buffer);
diff --git a/right/src/config_parser/parse_config.h b/right/src/config_parser/parse_config.h
index b4a6b810..db546787 100644
--- a/right/src/config_parser/parse_config.h
+++ b/right/src/config_parser/parse_config.h
@@ -35,7 +35,8 @@
ParserError_InvalidLayerId = 15,
ParserError_InvalidNavigationMode = 16,
ParserError_InvalidModuleProperty = 17,
- ParserError_InvalidSecondaryRoleActionType = 18,
+ ParserError_InvalidSecondaryRoleActionType = 18,
+ ParserError_InvalidHostType = 19,
} parser_error_t;
typedef enum {
diff --git a/right/src/config_parser/parse_host_connection.c b/right/src/config_parser/parse_host_connection.c
index 9682c746..c033080e 100644
--- a/right/src/config_parser/parse_host_connection.c
+++ b/right/src/config_parser/parse_host_connection.c
@@ -1,29 +1,58 @@
-#include "parse_host_connection.h"
+#include "config_parser/parse_host_connection.h"
+#include "config_parser/config_globals.h"
+#include "config_parser/parse_config.h"
+#include "config_parser/error_reporting.h"
+#include "config_globals.h"
#include "config_manager.h"
#include "config_parser/basic_types.h"
-#include "config_parser/parse_config.h"
#include "host_connection.h"
+#include "parse_config.h"
+
+static parser_error_t parseHostConnection(config_buffer_t* buffer, host_connection_t* hostConnection) {
+ hostConnection->type = ReadUInt8(buffer);
-static void parseHostConnection(config_buffer_t* buffer, host_connection_t* host_connection) {
- host_connection->type = ReadUInt8(buffer);
+ // check validity of the type
+ if (hostConnection->type >= HostConnectionType_Count) {
+ hostConnection->type = HostConnectionType_Empty;
+ ConfigParser_Error(buffer, "Invalid host type: %d\n", hostConnection->type);
+ return ParserError_InvalidHostType;
+ }
- if (host_connection->type == HostConnectionType_Ble || host_connection->type == HostConnectionType_Dongle) {
+ if (hostConnection->type == HostConnectionType_Ble || hostConnection->type == HostConnectionType_Dongle) {
+ hostConnection->bleAddress.type = 1;
for (uint8_t i = 0; i < BLE_ADDRESS_LENGTH; i++) {
- host_connection->bleAddress[i] = ReadUInt8(buffer);
+ hostConnection->bleAddress.a.val[i] = ReadUInt8(buffer);
}
}
- if (host_connection->type != HostConnectionType_Empty) {
+ if (hostConnection->type != HostConnectionType_Empty) {
+ if (VERSION_AT_LEAST(DataModelVersion, 8, 3, 0)) {
+ hostConnection->switchover = ReadUInt8(buffer);
+ }
+
uint16_t len;
- host_connection->name.start = ReadString(buffer, &len);
- host_connection->name.end = host_connection->name.start + len;
+ hostConnection->name.start = ReadString(buffer, &len);
+ hostConnection->name.end = hostConnection->name.start + len;
}
+
+ return ParserError_Success;
}
parser_error_t ParseHostConnections(config_buffer_t *buffer) {
- for (uint8_t host_connectionId = 0; host_connectionId < HOST_CONNECTION_COUNT_MAX; host_connectionId++) {
+ int errorCode;
+
+ for (uint8_t hostConnectionId = 0; hostConnectionId < HOST_CONNECTION_COUNT_MAX; hostConnectionId++) {
host_connection_t dummy;
- parseHostConnection(buffer, &dummy);
+
+ host_connection_t* hostConnection = &dummy;
+
+#ifdef __ZEPHYR__
+ hostConnection = ParserRunDry ? &dummy : &HostConnections[hostConnectionId];
+#endif
+
+ RETURN_ON_ERROR(
+ parseHostConnection(buffer, hostConnection);
+ );
}
return ParserError_Success;
diff --git a/right/src/event_scheduler.c b/right/src/event_scheduler.c
index 52ebdcf3..68b1706f 100644
--- a/right/src/event_scheduler.c
+++ b/right/src/event_scheduler.c
@@ -97,6 +97,12 @@ static void processEvt(event_scheduler_event_t evt)
case EventSchedulerEvent_PowerMode:
PowerMode_Update();
break;
+ case EventSchedulerEvent_EndBtPairing:
+ BtPair_EndPairing(false, "Pairing timeout");
+ break;
+ case EventSchedulerEvent_RestartBt:
+ BtManager_RestartBt();
+ break;
default:
return;
}
diff --git a/right/src/event_scheduler.h b/right/src/event_scheduler.h
index 8fa6953c..3cf8a16f 100644
--- a/right/src/event_scheduler.h
+++ b/right/src/event_scheduler.h
@@ -33,6 +33,8 @@
EventSchedulerEvent_ReenableUart,
EventSchedulerEvent_UpdateMergeSensor,
EventSchedulerEvent_PowerMode,
+ EventSchedulerEvent_EndBtPairing,
+ EventSchedulerEvent_RestartBt,
EventSchedulerEvent_Count
} event_scheduler_event_t;
diff --git a/right/src/host_connection.c b/right/src/host_connection.c
new file mode 100644
index 00000000..f5a9ef84
--- /dev/null
+++ b/right/src/host_connection.c
@@ -0,0 +1,29 @@
+#include "host_connection.h"
+
+#ifdef __ZEPHYR__
+
+host_connection_t HostConnections[HOST_CONNECTION_COUNT_MAX] = {};
+
+bool HostConnections_IsKnownBleAddress(const bt_addr_le_t *address) {
+ for (int i = 0; i < HOST_CONNECTION_COUNT_MAX; i++) {
+ switch (HostConnections[i].type) {
+ case HostConnectionType_Empty:
+ case HostConnectionType_UsbRight:
+ case HostConnectionType_UsbLeft:
+ break;
+ case HostConnectionType_Dongle:
+ case HostConnectionType_Ble:
+ if (bt_addr_le_cmp(address, &HostConnections[i].bleAddress) == 0) {
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+#endif
+
+
diff --git a/right/src/host_connection.h b/right/src/host_connection.h
index 54ad8793..04bae7ff 100644
--- a/right/src/host_connection.h
+++ b/right/src/host_connection.h
@@ -7,9 +7,29 @@
#include
#include "str_utils.h"
+#ifdef __ZEPHYR__
+
+ #include
+ #include
+ #include
+
+#else
+ typedef struct {
+ uint8_t val[6];
+ } bt_addr_t;
+
+ struct bt_addr_le {
+ uint8_t type;
+ bt_addr_t a;
+ };
+
+ typedef struct bt_addr_le bt_addr_le_t;
+#endif
+
// Macros:
#define HOST_CONNECTION_COUNT_MAX 22
+
#define BLE_ADDRESS_LENGTH 6
// Typedefs:
@@ -20,25 +40,22 @@
HostConnectionType_UsbLeft,
HostConnectionType_Ble,
HostConnectionType_Dongle,
+ HostConnectionType_Count,
} host_connection_type_t;
- struct host_connection_t {
- host_connection_type_t type;
- uint8_t usb_id;
- uint8_t ble_id;
- uint8_t dongle_id;
- };
-
typedef struct {
host_connection_type_t type;
- uint8_t bleAddress[6];
+ bt_addr_le_t bleAddress;
string_segment_t name;
+ bool switchover;
} ATTR_PACKED host_connection_t;
-
// Variables:
+ extern host_connection_t HostConnections[HOST_CONNECTION_COUNT_MAX];
// Functions:
+ bool HostConnections_IsKnownBleAddress(const bt_addr_le_t *address);
+
#endif
diff --git a/right/src/led_manager.c b/right/src/led_manager.c
index fb898252..b1b284ea 100644
--- a/right/src/led_manager.c
+++ b/right/src/led_manager.c
@@ -47,6 +47,11 @@ void LedManager_FullUpdate()
EventVector_Unset(EventVector_LedManagerFullUpdateNeeded);
EventVector_Unset(EventVector_LedMapUpdateNeeded);
+ if (DEVICE_IS_UHK80_LEFT) {
+ Ledmap_UpdateBacklightLeds();
+ return;
+ }
+
LedManager_UpdateSleepModes();
recalculateLedBrightness();
Ledmap_UpdateBacklightLeds();
diff --git a/right/src/macros/scancode_commands.c b/right/src/macros/scancode_commands.c
index 2b6ce6ac..7569b737 100644
--- a/right/src/macros/scancode_commands.c
+++ b/right/src/macros/scancode_commands.c
@@ -293,6 +293,8 @@ static void clearScancodes()
macro_result_t Macros_DispatchText(const char* text, uint16_t textLen, bool rawString)
{
+ const uint8_t maxGroupSize=3;
+ static uint8_t currentReportSize=0;
S->ms.reportsUsed = true;
static macro_state_t* dispatchMutex = NULL;
if (dispatchMutex != S && dispatchMutex != NULL) {
@@ -339,6 +341,7 @@ macro_result_t Macros_DispatchText(const char* text, uint16_t textLen, bool rawS
if (S->as.dispatchData.reportState != REPORT_EMPTY) {
S->as.dispatchData.reportState = REPORT_EMPTY;
clearScancodes();
+ currentReportSize = 0;
return MacroResult_Blocking;
} else {
S->ms.macroBasicKeyboardReport.modifiers = mods;
@@ -349,6 +352,7 @@ macro_result_t Macros_DispatchText(const char* text, uint16_t textLen, bool rawS
// If all characters have been sent, finish.
if (S->as.dispatchData.textIdx == textLen) {
if (S->as.dispatchData.reportState != REPORT_EMPTY) {
+ currentReportSize = 0;
S->as.dispatchData.reportState = REPORT_EMPTY;
memset(&S->ms.macroBasicKeyboardReport, 0, sizeof S->ms.macroBasicKeyboardReport);
return MacroResult_Blocking;
@@ -356,12 +360,14 @@ macro_result_t Macros_DispatchText(const char* text, uint16_t textLen, bool rawS
S->as.dispatchData.textIdx = 0;
S->as.dispatchData.subIndex = 0;
dispatchMutex = NULL;
+
return MacroResult_Finished;
}
}
// Whenever the report is full, we clear the report and send it empty before continuing.
if (S->as.dispatchData.reportState == REPORT_FULL) {
+ currentReportSize = 0;
S->as.dispatchData.reportState = REPORT_EMPTY;
memset(&S->ms.macroBasicKeyboardReport, 0, sizeof S->ms.macroBasicKeyboardReport);
return MacroResult_Blocking;
@@ -377,8 +383,7 @@ macro_result_t Macros_DispatchText(const char* text, uint16_t textLen, bool rawS
// Send the scancode.
UsbBasicKeyboard_AddScancode(&S->ms.macroBasicKeyboardReport, scancode);
- S->as.dispatchData.reportState = UsbBasicKeyboard_IsFullScancodes(&S->ms.macroBasicKeyboardReport) ?
- REPORT_FULL : REPORT_PARTIAL;
+ S->as.dispatchData.reportState = ++currentReportSize >= maxGroupSize ? REPORT_FULL : REPORT_PARTIAL;
if (rawString) {
++S->as.dispatchData.textIdx;
} else {
diff --git a/right/src/stubs.h b/right/src/stubs.h
index 55132486..31fec529 100644
--- a/right/src/stubs.h
+++ b/right/src/stubs.h
@@ -41,6 +41,8 @@
ATTRS void Uart_Log(const char *fmt, ...) {};
ATTRS void Log(const char *fmt, ...) {};
ATTRS void LogBt(const char *fmt, ...) {};
+ ATTRS void BtPair_EndPairing(bool success, const char* msg) {};
+ ATTRS void BtManager_RestartBt() {};
ATTRS void DongleLeds_Update() {};
#if DEVICE_HAS_OLED
diff --git a/right/src/usb_commands/usb_command_get_device_property.c b/right/src/usb_commands/usb_command_get_device_property.c
index be460109..efd76ae3 100644
--- a/right/src/usb_commands/usb_command_get_device_property.c
+++ b/right/src/usb_commands/usb_command_get_device_property.c
@@ -3,6 +3,9 @@
#ifdef __ZEPHYR__
#include "device.h"
#include "flash.h"
+ #include
+ #include "bt_conn.h"
+ #include "bt_pair.h"
#else
#include "eeprom.h"
#include "fsl_common.h"
@@ -14,6 +17,7 @@
#include "slave_protocol.h"
#include "timer.h"
+#include "usb_commands/usb_command_get_new_pairings.h"
#include "usb_commands/usb_command_get_device_property.h"
#include "usb_protocol_handler.h"
#include "utils.h"
@@ -77,6 +81,33 @@ void UsbCommand_GetDeviceProperty(void)
MD5_CHECKSUM_LENGTH + 1);
}
} break;
+ case DevicePropertyId_BleAddress: {
+#ifdef __ZEPHYR__
+ bt_addr_le_t addr;
+ size_t count = 1;
+ bt_id_get(&addr, &count);
+ memcpy(GenericHidInBuffer + 1, addr.a.val, sizeof(addr.a.val));
+#endif
+ } break;
+ case DevicePropertyId_PairedRightPeerBleAddress: {
+#ifdef __ZEPHYR__
+ memcpy(GenericHidInBuffer + 1, Peers[PeerIdRight].addr.a.val, sizeof(Peers[PeerIdRight].addr.a.val));
+#endif
+ } break;
+ case DevicePropertyId_PairingStatus: {
+#ifdef __ZEPHYR__
+ if (BtPair_OobPairingInProgress) {
+ SetUsbTxBufferUint8(1, PairingStatus_InProgress);
+ } else {
+ SetUsbTxBufferUint8(1, BtPair_LastPairingSucceeded ? PairingStatus_Success : PairingStatus_Failed);
+ }
+#endif
+ } break;
+ case DevicePropertyId_NewPairings:
+#ifdef __ZEPHYR__
+ UsbCommand_GetNewPairings();
+#endif
+ break;
default:
SetUsbTxBufferUint8(0, UsbStatusCode_GetDeviceProperty_InvalidProperty);
break;
diff --git a/right/src/usb_commands/usb_command_get_device_property.h b/right/src/usb_commands/usb_command_get_device_property.h
index f8923d14..cce6ca49 100644
--- a/right/src/usb_commands/usb_command_get_device_property.h
+++ b/right/src/usb_commands/usb_command_get_device_property.h
@@ -13,12 +13,22 @@
DevicePropertyId_GitTag = 6,
DevicePropertyId_GitRepo = 7,
DevicePropertyId_FirmwareChecksum = 8,
+ DevicePropertyId_BleAddress = 9,
+ DevicePropertyId_PairedRightPeerBleAddress = 10,
+ DevicePropertyId_PairingStatus = 11,
+ DevicePropertyId_NewPairings = 12,
} device_property_t;
typedef enum {
UsbStatusCode_GetDeviceProperty_InvalidProperty = 2,
} usb_status_code_get_device_property_t;
+ typedef enum {
+ PairingStatus_InProgress = 0,
+ PairingStatus_Success = 1,
+ PairingStatus_Failed = 2,
+ } usb_command_pairing_status_t;
+
// Functions:
void UsbCommand_GetDeviceProperty(void);
diff --git a/right/src/usb_commands/usb_command_get_device_state.c b/right/src/usb_commands/usb_command_get_device_state.c
index 1112ddba..63ab15f1 100644
--- a/right/src/usb_commands/usb_command_get_device_state.c
+++ b/right/src/usb_commands/usb_command_get_device_state.c
@@ -20,9 +20,13 @@
#include "device_state.h"
#include "usb_report_updater.h"
#include "slave_scheduler.h"
+ #include "bt_pair.h"
+ #include "bt_conn.h"
#else
#include "usb_report_updater.h"
#include "slave_scheduler.h"
+ #define BtPair_OobPairingInProgress 0
+ #define Bt_NewPairedDevice 0
#endif
void UsbCommand_GetKeyboardState(void)
@@ -34,7 +38,11 @@ void UsbCommand_GetKeyboardState(void)
SetUsbTxBufferUint8(1, IsStorageBusy);
#endif
- SetUsbTxBufferUint8(2, MergeSensor_IsMerged());
+ uint8_t byte2 = 0
+ | (MergeSensor_IsMerged() ? GetDeviceStateByte2_HalvesMerged : 0)
+ | (BtPair_OobPairingInProgress ? GetDeviceStateByte2_PairingInProgress : 0)
+ | (Bt_NewPairedDevice ? GetDeviceStateByte2_NewPairedDevice : 0);
+ SetUsbTxBufferUint8(2, byte2);
SetUsbTxBufferUint8(3, ModuleConnectionStates[UhkModuleDriverId_LeftKeyboardHalf].moduleId);
SetUsbTxBufferUint8(4, ModuleConnectionStates[UhkModuleDriverId_LeftModule].moduleId);
SetUsbTxBufferUint8(5, ModuleConnectionStates[UhkModuleDriverId_RightModule].moduleId);
diff --git a/right/src/usb_commands/usb_command_get_device_state.h b/right/src/usb_commands/usb_command_get_device_state.h
index 5030de87..4b14970e 100644
--- a/right/src/usb_commands/usb_command_get_device_state.h
+++ b/right/src/usb_commands/usb_command_get_device_state.h
@@ -3,6 +3,13 @@
// Typedefs:
+typedef enum {
+ GetDeviceStateByte2_HalvesMerged = 1 << 0,
+ GetDeviceStateByte2_PairingInProgress = 1 << 1,
+ GetDeviceStateByte2_NewPairedDevice = 1 << 2,
+
+} usb_command_get_device_state_byte2_mask_t;
+
typedef enum {
UhkErrorState_Fine = 0,
UhkErrorState_Warn = 1,
diff --git a/right/src/usb_commands/usb_command_get_new_pairings.c b/right/src/usb_commands/usb_command_get_new_pairings.c
new file mode 100644
index 00000000..d86d030d
--- /dev/null
+++ b/right/src/usb_commands/usb_command_get_new_pairings.c
@@ -0,0 +1,44 @@
+#include "usb_command_get_new_pairings.h"
+#include "usb_protocol_handler.h"
+
+#ifdef __ZEPHYR__
+
+#include "bt_conn.h"
+#include
+#include "host_connection.h"
+
+static uint8_t idx;
+static uint8_t count;
+
+static void bt_foreach_bond_cb(const struct bt_bond_info *info, void *user_data)
+{
+ if (idx + BLE_ADDR_LEN+1 >= USB_GENERIC_HID_IN_BUFFER_LENGTH) {
+ return;
+ }
+
+ if (HostConnections_IsKnownBleAddress(&info->addr)) {
+ return;
+ }
+
+ count++;
+
+ SetUsbTxBufferBleAddress(idx, &info->addr);
+ idx += BLE_ADDR_LEN;
+
+ // Name placeholder
+ SetUsbTxBufferUint8(idx++, 0);
+}
+
+void UsbCommand_GetNewPairings(void) {
+ count = 0;
+ idx = 2;
+
+ bt_foreach_bond(BT_ID_DEFAULT, bt_foreach_bond_cb, NULL);
+
+ SetUsbTxBufferUint8(1, count);
+
+ Bt_NewPairedDevice = false;
+}
+
+#endif
+
diff --git a/right/src/usb_commands/usb_command_get_new_pairings.h b/right/src/usb_commands/usb_command_get_new_pairings.h
new file mode 100644
index 00000000..a62b0cb4
--- /dev/null
+++ b/right/src/usb_commands/usb_command_get_new_pairings.h
@@ -0,0 +1,14 @@
+#ifndef __USB_COMMAND_GET_NEW_PAIRINGS_H__
+#define __USB_COMMAND_GET_NEW_PAIRINGS_H__
+
+#ifdef __ZEPHYR__
+
+// Typedefs:
+
+// Functions:
+
+ void UsbCommand_GetNewPairings(void);
+
+#endif
+
+#endif
diff --git a/right/src/usb_commands/usb_command_pairing.c b/right/src/usb_commands/usb_command_pairing.c
new file mode 100644
index 00000000..2cb92fe1
--- /dev/null
+++ b/right/src/usb_commands/usb_command_pairing.c
@@ -0,0 +1,80 @@
+#include "usb_command_pairing.h"
+#include "usb_protocol_handler.h"
+#include "device.h"
+
+#ifdef __ZEPHYR__
+#include
+#include
+#include
+#include "bt_pair.h"
+#include "bt_conn.h"
+#include "bt_manager.h"
+
+#define BUF_PEER_POS 1
+#define BUF_ADR_POS 1
+#define BUF_KEY_R_POS 7
+#define BUF_KEY_C_POS 23
+
+void UsbCommand_GetPairingData(void) {
+ struct bt_le_oob* oob = BtPair_GetLocalOob();
+
+ SetUsbTxBufferBleAddress(BUF_ADR_POS, &oob->addr);
+ memcpy(GenericHidInBuffer + BUF_KEY_R_POS, oob->le_sc_data.r, BLE_KEY_LEN);
+ memcpy(GenericHidInBuffer + BUF_KEY_C_POS, oob->le_sc_data.c, BLE_KEY_LEN);
+}
+
+void UsbCommand_SetPairingData(void) {
+ struct bt_le_oob oob;
+ uint8_t peerId = GenericHidOutBuffer[BUF_PEER_POS];
+
+ oob.addr = GetUsbRxBufferBleAddress(1 + BUF_ADR_POS);
+ memcpy(oob.le_sc_data.r, GenericHidOutBuffer + 1 + BUF_KEY_R_POS, BLE_KEY_LEN);
+ memcpy(oob.le_sc_data.c, GenericHidOutBuffer + 1 + BUF_KEY_C_POS, BLE_KEY_LEN);
+
+ BtPair_SetRemoteOob(&oob);
+
+ //copy addres backwards to fix endianity
+ uint8_t addr[BLE_ADDR_LEN];
+ for (uint8_t i = 0; i < BLE_ADDR_LEN; i++) {
+ addr[i] = oob.addr.a.val[BLE_ADDR_LEN - i - 1];
+ }
+
+ switch (peerId) {
+ case PeerIdLeft:
+ settings_save_one("uhk/addr/left", addr, BLE_ADDR_LEN);
+ break;
+ case PeerIdRight:
+ settings_save_one("uhk/addr/right", addr, BLE_ADDR_LEN);
+ break;
+ case PeerIdDongle:
+ settings_save_one("uhk/addr/dongle", addr, BLE_ADDR_LEN);
+ break;
+ default:
+ }
+}
+
+void UsbCommand_PairCentral(void) {
+ BtPair_PairCentral();
+}
+
+void UsbCommand_PairPeripheral(void) {
+ BtPair_PairPeripheral();
+}
+
+// If zero address is provided, all existing bonds will be deleted
+void UsbCommand_Unpair(void) {
+ bt_addr_le_t addr = GetUsbRxBufferBleAddress(1);
+ BtPair_Unpair(addr);
+}
+
+void UsbCommand_IsPaired(void) {
+ bt_addr_le_t addr = GetUsbRxBufferBleAddress(1);
+ bool isPaired = BtPair_IsDeviceBonded(&addr);
+ SetUsbTxBufferUint8(1, isPaired);
+}
+
+void UsbCommand_EnterPairingMode(void) {
+ BtManager_EnterPairingMode();
+}
+
+#endif
diff --git a/right/src/usb_commands/usb_command_pairing.h b/right/src/usb_commands/usb_command_pairing.h
new file mode 100644
index 00000000..b6312f0d
--- /dev/null
+++ b/right/src/usb_commands/usb_command_pairing.h
@@ -0,0 +1,16 @@
+#ifndef __USB_COMMAND_PAIRING_H__
+#define __USB_COMMAND_PAIRING_H__
+
+// Functions:
+
+ void UsbCommand_GetPairingData(void);
+ void UsbCommand_SetPairingData(void);
+ void UsbCommand_PairCentral(void);
+ void UsbCommand_PairPeripheral(void);
+ void UsbCommand_Unpair(void);
+ void UsbCommand_IsPaired(void);
+ void UsbCommand_EnterPairingMode(void);
+
+// Typedefs:
+
+#endif
diff --git a/right/src/usb_protocol_handler.c b/right/src/usb_protocol_handler.c
index a554dd39..37de9288 100644
--- a/right/src/usb_protocol_handler.c
+++ b/right/src/usb_protocol_handler.c
@@ -18,6 +18,8 @@
#ifdef __ZEPHYR__
#include "usb_commands/usb_command_draw_oled.h"
+#include "usb_commands/usb_command_pairing.h"
+#include "bt_conn.h"
#else
#include "usb_commands/usb_command_set_test_led.h"
#include "usb_commands/usb_command_set_led_pwm_brightness.h"
@@ -94,6 +96,27 @@ void UsbProtocolHandler(void)
case UsbCommandId_DrawOled:
UsbCommand_DrawOled();
break;
+ case UsbCommandId_GetPairingData:
+ UsbCommand_GetPairingData();
+ break;
+ case UsbCommandId_SetPairingData:
+ UsbCommand_SetPairingData();
+ break;
+ case UsbCommandId_PairCentral:
+ UsbCommand_PairCentral();
+ break;
+ case UsbCommandId_PairPeripheral:
+ UsbCommand_PairPeripheral();
+ break;
+ case UsbCommandId_UnpairAll:
+ UsbCommand_Unpair();
+ break;
+ case UsbCommandId_IsPaired:
+ UsbCommand_IsPaired();
+ break;
+ case UsbCommandId_EnterPairingMode:
+ UsbCommand_EnterPairingMode();
+ break;
#else
case UsbCommandId_JumpToModuleBootloader:
UsbCommand_JumpToModuleBootloader();
@@ -155,3 +178,20 @@ void SetUsbTxBufferUint32(uint32_t offset, uint32_t value)
{
SetBufferUint32(GenericHidInBuffer, offset, value);
}
+
+#ifdef __ZEPHYR__
+bt_addr_le_t GetUsbRxBufferBleAddress(uint32_t offset) {
+ bt_addr_le_t addr;
+ addr.type = 1;
+ for (uint8_t i = 0; i < BLE_ADDR_LEN; i++) {
+ addr.a.val[i] = GenericHidOutBuffer[offset + i];
+ }
+ return addr;
+}
+
+void SetUsbTxBufferBleAddress(uint32_t offset, const bt_addr_le_t* addr) {
+ for (uint8_t i = 0; i < BLE_ADDR_LEN; i++) {
+ GenericHidInBuffer[offset + i] = addr->a.val[i];
+ }
+}
+#endif
diff --git a/right/src/usb_protocol_handler.h b/right/src/usb_protocol_handler.h
index ecf5a701..e8cacfc9 100644
--- a/right/src/usb_protocol_handler.h
+++ b/right/src/usb_protocol_handler.h
@@ -7,7 +7,9 @@
#include
#include
#include "usb_interfaces/usb_interface_generic_hid.h"
-#ifndef __ZEPHYR__
+#ifdef __ZEPHYR__
+ #include
+#else
#include "fsl_common.h"
#endif
@@ -44,6 +46,14 @@
UsbCommandId_ExecMacroCommand = 0x14,
UsbCommandId_DrawOled = 0x15,
+
+ UsbCommandId_GetPairingData = 0x16,
+ UsbCommandId_SetPairingData = 0x17,
+ UsbCommandId_PairPeripheral = 0x18,
+ UsbCommandId_PairCentral = 0x19,
+ UsbCommandId_UnpairAll = 0x1a,
+ UsbCommandId_IsPaired = 0x1b,
+ UsbCommandId_EnterPairingMode = 0x1c,
} usb_command_id_t;
typedef enum {
@@ -68,6 +78,9 @@
#ifdef __ZEPHYR__
extern bool CommandProtocolTx(const uint8_t* data, size_t size);
+
+ void SetUsbTxBufferBleAddress(uint32_t offset, const bt_addr_le_t* addr);
+ extern bt_addr_le_t GetUsbRxBufferBleAddress(uint32_t offset);
#endif
void UsbProtocolHandler(void);
diff --git a/right/src/usb_report_updater.c b/right/src/usb_report_updater.c
index 8f6fa0b8..8e35970e 100644
--- a/right/src/usb_report_updater.c
+++ b/right/src/usb_report_updater.c
@@ -465,14 +465,16 @@ static void commitKeyState(key_state_t *keyState, bool active)
static inline void preprocessKeyState(key_state_t *keyState)
{
uint8_t debounceTime = keyState->previous ? Cfg.DebounceTimePress : Cfg.DebounceTimeRelease;
- if (keyState->debouncing && (uint8_t)(CurrentTime - keyState->timestamp) > debounceTime) {
+ if (keyState->debouncing && (uint8_t)(CurrentTime - keyState->timestamp) >= debounceTime) {
keyState->debouncing = false;
}
- if (!keyState->debouncing && keyState->debouncedSwitchState != keyState->hardwareSwitchState) {
+ // read just once! Otherwise the key might get stuck
+ bool hardwareState = keyState->hardwareSwitchState;
+ if (!keyState->debouncing && keyState->debouncedSwitchState != hardwareState) {
keyState->timestamp = CurrentTime;
keyState->debouncing = true;
- keyState->debouncedSwitchState = keyState->hardwareSwitchState;
+ keyState->debouncedSwitchState = hardwareState;
commitKeyState(keyState, keyState->debouncedSwitchState);
}
diff --git a/scripts/package.json b/scripts/package.json
index a645ed08..aee76e0b 100644
--- a/scripts/package.json
+++ b/scripts/package.json
@@ -22,7 +22,7 @@
"firmwareVersion": "11.2.0",
"deviceProtocolVersion": "4.10.0",
"moduleProtocolVersion": "4.3.0",
- "userConfigVersion": "8.2.0",
+ "userConfigVersion": "8.3.0",
"hardwareConfigVersion": "1.0.0",
"smartMacrosVersion": "2.5.0",
"devices": [
diff --git a/shared/device.h b/shared/device.h
index fb162f63..b0fd275c 100644
--- a/shared/device.h
+++ b/shared/device.h
@@ -103,6 +103,7 @@
DeviceId_Uhk80_Right = DEVICE_ID_UHK80_RIGHT,
DeviceId_Uhk80_Left = DEVICE_ID_UHK80_LEFT,
DeviceId_Uhk_Dongle = DEVICE_ID_UHK_DONGLE,
+ DeviceId_Uhk80_Dongle = DeviceId_Uhk_Dongle,
DeviceId_Count = DEVICE_ID_UHK_DONGLE + 1,
} device_id_t;