Skip to content

Instantly share code, notes, and snippets.

@mfikes
Last active May 14, 2023 16:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mfikes/57f764fa85d74717a8ac0e5efa333460 to your computer and use it in GitHub Desktop.
Save mfikes/57f764fa85d74717a8ac0e5efa333460 to your computer and use it in GitHub Desktop.
Modified nrf/samples/bluetooth/peripheral_hids_keyboard/main.c
/*
* Copyright (c) 2018 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <soc.h>
#include <assert.h>
#include <zephyr/spinlock.h>
#include <zephyr/settings/settings.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/services/bas.h>
#include <bluetooth/services/hids.h>
#include <zephyr/bluetooth/services/dis.h>
#include <dk_buttons_and_leds.h>
#include "app_nfc.h"
// Disable printk to avoid jitter
#define printk(...) do {} while (0)
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
#define BASE_USB_HID_SPEC_VERSION 0x0101
#define OUTPUT_REPORT_MAX_LEN 1
#define OUTPUT_REPORT_BIT_MASK_CAPS_LOCK 0x02
//#define INPUT_REP_KEYS_REF_ID 1
//#define OUTPUT_REP_KEYS_REF_ID 1
#define MODIFIER_KEY_POS 0
#define SHIFT_KEY_CODE 0x02
#define SCAN_CODE_POS 2
#define KEYS_MAX_LEN (INPUT_REPORT_KEYS_MAX_LEN - \
SCAN_CODE_POS)
#define ADV_LED_BLINK_INTERVAL 1000
#define ADV_STATUS_LED DK_LED1
#define CON_STATUS_LED DK_LED2
#define LED_CAPS_LOCK DK_LED3
#define NFC_LED DK_LED4
#define KEY_TEXT_MASK DK_BTN1_MSK
#define KEY_SHIFT_MASK DK_BTN2_MSK
#define KEY_ADV_MASK DK_BTN4_MSK
/* Key used to accept or reject passkey value */
#define KEY_PAIRING_ACCEPT DK_BTN1_MSK
#define KEY_PAIRING_REJECT DK_BTN2_MSK
/* HIDs queue elements. */
#define HIDS_QUEUE_SIZE 10
/* ********************* */
/* Buttons configuration */
/* Note: The configuration below is the same as BOOT mode configuration
* This simplifies the code as the BOOT mode is the same as REPORT mode.
* Changing this configuration would require separate implementation of
* BOOT mode report generation.
*/
#define KEY_CTRL_CODE_MIN 224 /* Control key codes - required 8 of them */
#define KEY_CTRL_CODE_MAX 231 /* Control key codes - required 8 of them */
#define KEY_CODE_MIN 0 /* Normal key codes */
#define KEY_CODE_MAX 101 /* Normal key codes */
#define KEY_PRESS_MAX 6 /* Maximum number of non-control keys
* pressed simultaneously
*/
/* Number of bytes in key report
*
* 1B - control keys
* 1B - reserved
* rest - non-control keys
*/
#define INPUT_REPORT_KEYS_MAX_LEN (1 + 1 + KEY_PRESS_MAX)
/* Current report map construction requires exactly 8 buttons */
BUILD_ASSERT((KEY_CTRL_CODE_MAX - KEY_CTRL_CODE_MIN) + 1 == 8);
/* OUT report internal indexes.
*
* This is a position in internal report table and is not related to
* report ID.
*/
enum {
OUTPUT_REP_KEYS_IDX = 0
};
/* INPUT report internal indexes.
*
* This is a position in internal report table and is not related to
* report ID.
*/
enum {
INPUT_REP_KEYS_IDX = 0
};
/* HIDS instance. */
BT_HIDS_DEF(hids_obj,
OUTPUT_REPORT_MAX_LEN,
INPUT_REPORT_KEYS_MAX_LEN);
static volatile bool is_adv;
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_GAP_APPEARANCE,
(CONFIG_BT_DEVICE_APPEARANCE >> 0) & 0xff,
(CONFIG_BT_DEVICE_APPEARANCE >> 8) & 0xff),
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_HIDS_VAL),
BT_UUID_16_ENCODE(BT_UUID_BAS_VAL)),
};
static const struct bt_data sd[] = {
BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};
static struct conn_mode {
struct bt_conn *conn;
bool in_boot_mode;
} conn_mode[CONFIG_BT_HIDS_MAX_CLIENT_COUNT];
static const uint8_t space_key[] = { 0x2c };
static const uint8_t shift_key[] = { 225 };
/* Current report status
*/
static struct keyboard_state {
uint8_t ctrl_keys_state; /* Current keys state */
uint8_t keys_state[KEY_PRESS_MAX];
} hid_keyboard_state;
#if CONFIG_NFC_OOB_PAIRING
static struct k_work adv_work;
#endif
static struct k_work pairing_work;
struct pairing_data_mitm {
struct bt_conn *conn;
unsigned int passkey;
};
K_MSGQ_DEFINE(mitm_queue,
sizeof(struct pairing_data_mitm),
CONFIG_BT_HIDS_MAX_CLIENT_COUNT,
4);
static void advertising_start(void)
{
int err;
struct bt_le_adv_param *adv_param = BT_LE_ADV_PARAM(
BT_LE_ADV_OPT_CONNECTABLE |
BT_LE_ADV_OPT_ONE_TIME,
BT_GAP_ADV_FAST_INT_MIN_2,
BT_GAP_ADV_FAST_INT_MAX_2,
NULL);
err = bt_le_adv_start(adv_param, ad, ARRAY_SIZE(ad), sd,
ARRAY_SIZE(sd));
if (err) {
if (err == -EALREADY) {
printk("Advertising continued\n");
} else {
printk("Advertising failed to start (err %d)\n", err);
}
return;
}
is_adv = true;
printk("Advertising successfully started\n");
}
#if CONFIG_NFC_OOB_PAIRING
static void delayed_advertising_start(struct k_work *work)
{
advertising_start();
}
void nfc_field_detected(void)
{
dk_set_led_on(NFC_LED);
for (int i = 0; i < CONFIG_BT_HIDS_MAX_CLIENT_COUNT; i++) {
if (!conn_mode[i].conn) {
k_work_submit(&adv_work);
break;
}
}
}
void nfc_field_lost(void)
{
dk_set_led_off(NFC_LED);
}
#endif
static void pairing_process(struct k_work *work)
{
int err;
struct pairing_data_mitm pairing_data;
char addr[BT_ADDR_LE_STR_LEN];
err = k_msgq_peek(&mitm_queue, &pairing_data);
if (err) {
return;
}
bt_addr_le_to_str(bt_conn_get_dst(pairing_data.conn),
addr, sizeof(addr));
printk("Passkey for %s: %06u\n", addr, pairing_data.passkey);
printk("Press Button 1 to confirm, Button 2 to reject.\n");
}
static struct bt_le_conn_param conn_param = {
.interval_min = 4,
.interval_max = 4,
.latency = 0,
.timeout = 400
};
static void connected(struct bt_conn *conn, uint8_t err)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
if (err) {
printk("Failed to connect to %s (%u)\n", addr, err);
return;
}
printk("Connected %s\n", addr);
dk_set_led_on(CON_STATUS_LED);
err = bt_hids_connected(&hids_obj, conn);
if (err) {
printk("Failed to notify HID service about connection\n");
return;
}
for (size_t i = 0; i < CONFIG_BT_HIDS_MAX_CLIENT_COUNT; i++) {
if (!conn_mode[i].conn) {
conn_mode[i].conn = conn;
conn_mode[i].in_boot_mode = false;
break;
}
}
// Update connection parameters
bt_conn_le_param_update(conn, &conn_param);
#if CONFIG_NFC_OOB_PAIRING == 0
for (size_t i = 0; i < CONFIG_BT_HIDS_MAX_CLIENT_COUNT; i++) {
if (!conn_mode[i].conn) {
advertising_start();
return;
}
}
#endif
is_adv = false;
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
int err;
bool is_any_dev_connected = false;
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Disconnected from %s (reason %u)\n", addr, reason);
err = bt_hids_disconnected(&hids_obj, conn);
if (err) {
printk("Failed to notify HID service about disconnection\n");
}
for (size_t i = 0; i < CONFIG_BT_HIDS_MAX_CLIENT_COUNT; i++) {
if (conn_mode[i].conn == conn) {
conn_mode[i].conn = NULL;
} else {
if (conn_mode[i].conn) {
is_any_dev_connected = true;
}
}
}
if (!is_any_dev_connected) {
dk_set_led_off(CON_STATUS_LED);
}
#if CONFIG_NFC_OOB_PAIRING
if (is_adv) {
printk("Advertising stopped after disconnect\n");
bt_le_adv_stop();
is_adv = false;
}
#else
advertising_start();
#endif
}
static void security_changed(struct bt_conn *conn, bt_security_t level,
enum bt_security_err err)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
if (!err) {
printk("Security changed: %s level %u\n", addr, level);
} else {
printk("Security failed: %s level %u err %d\n", addr, level,
err);
}
}
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
.security_changed = security_changed,
};
static void caps_lock_handler(const struct bt_hids_rep *rep)
{
uint8_t report_val = ((*rep->data) & OUTPUT_REPORT_BIT_MASK_CAPS_LOCK) ?
1 : 0;
dk_set_led(LED_CAPS_LOCK, report_val);
}
static void hids_outp_rep_handler(struct bt_hids_rep *rep,
struct bt_conn *conn,
bool write)
{
char addr[BT_ADDR_LE_STR_LEN];
if (!write) {
printk("Output report read\n");
return;
};
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Output report has been received %s\n", addr);
caps_lock_handler(rep);
}
static void hids_boot_kb_outp_rep_handler(struct bt_hids_rep *rep,
struct bt_conn *conn,
bool write)
{
char addr[BT_ADDR_LE_STR_LEN];
if (!write) {
printk("Output report read\n");
return;
};
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Boot Keyboard Output report has been received %s\n", addr);
caps_lock_handler(rep);
}
static void hids_pm_evt_handler(enum bt_hids_pm_evt evt,
struct bt_conn *conn)
{
char addr[BT_ADDR_LE_STR_LEN];
size_t i;
for (i = 0; i < CONFIG_BT_HIDS_MAX_CLIENT_COUNT; i++) {
if (conn_mode[i].conn == conn) {
break;
}
}
if (i >= CONFIG_BT_HIDS_MAX_CLIENT_COUNT) {
printk("Cannot find connection handle when processing PM");
return;
}
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
switch (evt) {
case BT_HIDS_PM_EVT_BOOT_MODE_ENTERED:
printk("Boot mode entered %s\n", addr);
conn_mode[i].in_boot_mode = true;
break;
case BT_HIDS_PM_EVT_REPORT_MODE_ENTERED:
printk("Report mode entered %s\n", addr);
conn_mode[i].in_boot_mode = false;
break;
default:
break;
}
}
static void hid_init(void)
{
int err;
struct bt_hids_init_param hids_init_obj = { 0 };
struct bt_hids_inp_rep *hids_inp_rep;
struct bt_hids_outp_feat_rep *hids_outp_rep;
static const uint8_t report_map[] = {
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x06, /* Usage (Keyboard) */
0xA1, 0x01, /* Collection (Application) */
/* Keys */
#if INPUT_REP_KEYS_REF_ID
0x85, INPUT_REP_KEYS_REF_ID,
#endif
0x05, 0x07, /* Usage Page (Key Codes) */
0x19, 0xe0, /* Usage Minimum (224) */
0x29, 0xe7, /* Usage Maximum (231) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x75, 0x01, /* Report Size (1) */
0x95, 0x08, /* Report Count (8) */
0x81, 0x02, /* Input (Data, Variable, Absolute) */
0x95, 0x01, /* Report Count (1) */
0x75, 0x08, /* Report Size (8) */
0x81, 0x01, /* Input (Constant) reserved byte(1) */
0x95, 0x06, /* Report Count (6) */
0x75, 0x08, /* Report Size (8) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x65, /* Logical Maximum (101) */
0x05, 0x07, /* Usage Page (Key codes) */
0x19, 0x00, /* Usage Minimum (0) */
0x29, 0x65, /* Usage Maximum (101) */
0x81, 0x00, /* Input (Data, Array) Key array(6 bytes) */
/* LED */
#if OUTPUT_REP_KEYS_REF_ID
0x85, OUTPUT_REP_KEYS_REF_ID,
#endif
0x95, 0x05, /* Report Count (5) */
0x75, 0x01, /* Report Size (1) */
0x05, 0x08, /* Usage Page (Page# for LEDs) */
0x19, 0x01, /* Usage Minimum (1) */
0x29, 0x05, /* Usage Maximum (5) */
0x91, 0x02, /* Output (Data, Variable, Absolute), */
/* Led report */
0x95, 0x01, /* Report Count (1) */
0x75, 0x03, /* Report Size (3) */
0x91, 0x01, /* Output (Data, Variable, Absolute), */
/* Led report padding */
0xC0 /* End Collection (Application) */
};
hids_init_obj.rep_map.data = report_map;
hids_init_obj.rep_map.size = sizeof(report_map);
hids_init_obj.info.bcd_hid = BASE_USB_HID_SPEC_VERSION;
hids_init_obj.info.b_country_code = 0x00;
hids_init_obj.info.flags = (BT_HIDS_REMOTE_WAKE |
BT_HIDS_NORMALLY_CONNECTABLE);
hids_inp_rep =
&hids_init_obj.inp_rep_group_init.reports[INPUT_REP_KEYS_IDX];
hids_inp_rep->size = INPUT_REPORT_KEYS_MAX_LEN;
hids_inp_rep->id = 0; //INPUT_REP_KEYS_REF_ID;
hids_init_obj.inp_rep_group_init.cnt++;
hids_outp_rep =
&hids_init_obj.outp_rep_group_init.reports[OUTPUT_REP_KEYS_IDX];
hids_outp_rep->size = OUTPUT_REPORT_MAX_LEN;
hids_outp_rep->id = 0; //OUTPUT_REP_KEYS_REF_ID;
hids_outp_rep->handler = hids_outp_rep_handler;
hids_init_obj.outp_rep_group_init.cnt++;
hids_init_obj.is_kb = true;
hids_init_obj.boot_kb_outp_rep_handler = hids_boot_kb_outp_rep_handler;
hids_init_obj.pm_evt_handler = hids_pm_evt_handler;
err = bt_hids_init(&hids_obj, &hids_init_obj);
__ASSERT(err == 0, "HIDS initialization failed\n");
}
static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Passkey for %s: %06u\n", addr, passkey);
}
static void auth_passkey_confirm(struct bt_conn *conn, unsigned int passkey)
{
int err;
struct pairing_data_mitm pairing_data;
pairing_data.conn = bt_conn_ref(conn);
pairing_data.passkey = passkey;
err = k_msgq_put(&mitm_queue, &pairing_data, K_NO_WAIT);
if (err) {
printk("Pairing queue is full. Purge previous data.\n");
}
/* In the case of multiple pairing requests, trigger
* pairing confirmation which needed user interaction only
* once to avoid display information about all devices at
* the same time. Passkey confirmation for next devices will
* be proccess from queue after handling the earlier ones.
*/
if (k_msgq_num_used_get(&mitm_queue) == 1) {
k_work_submit(&pairing_work);
}
}
static void auth_cancel(struct bt_conn *conn)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Pairing cancelled: %s\n", addr);
}
#if CONFIG_NFC_OOB_PAIRING
static void auth_oob_data_request(struct bt_conn *conn,
struct bt_conn_oob_info *info)
{
int err;
struct bt_le_oob *oob_local = app_nfc_oob_data_get();
printk("LESC OOB data requested\n");
if (info->type != BT_CONN_OOB_LE_SC) {
printk("Only LESC pairing supported\n");
return;
}
if (info->lesc.oob_config != BT_CONN_OOB_LOCAL_ONLY) {
printk("LESC OOB config not supported\n");
return;
}
/* Pass only local OOB data. */
err = bt_le_oob_set_sc_data(conn, &oob_local->le_sc_data, NULL);
if (err) {
printk("Error while setting OOB data: %d\n", err);
} else {
printk("Successfully provided LESC OOB data\n");
}
}
#endif
static void pairing_complete(struct bt_conn *conn, bool bonded)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Pairing completed: %s, bonded: %d\n", addr, bonded);
}
static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason)
{
char addr[BT_ADDR_LE_STR_LEN];
struct pairing_data_mitm pairing_data;
if (k_msgq_peek(&mitm_queue, &pairing_data) != 0) {
return;
}
if (pairing_data.conn == conn) {
bt_conn_unref(pairing_data.conn);
k_msgq_get(&mitm_queue, &pairing_data, K_NO_WAIT);
}
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Pairing failed conn: %s, reason %d\n", addr, reason);
}
static struct bt_conn_auth_cb conn_auth_callbacks = {
.passkey_display = auth_passkey_display,
.passkey_confirm = auth_passkey_confirm,
.cancel = auth_cancel,
#if CONFIG_NFC_OOB_PAIRING
.oob_data_request = auth_oob_data_request,
#endif
};
static struct bt_conn_auth_info_cb conn_auth_info_callbacks = {
.pairing_complete = pairing_complete,
.pairing_failed = pairing_failed
};
/** @brief Function process keyboard state and sends it
*
* @param pstate The state to be sent
* @param boot_mode Information if boot mode protocol is selected.
* @param conn Connection handler
*
* @return 0 on success or negative error code.
*/
static int key_report_con_send(const struct keyboard_state *state,
bool boot_mode,
struct bt_conn *conn)
{
int err = 0;
uint8_t data[INPUT_REPORT_KEYS_MAX_LEN];
uint8_t *key_data;
const uint8_t *key_state;
size_t n;
data[0] = state->ctrl_keys_state;
data[1] = 0;
key_data = &data[2];
key_state = state->keys_state;
for (n = 0; n < KEY_PRESS_MAX; ++n) {
*key_data++ = *key_state++;
}
if (boot_mode) {
err = bt_hids_boot_kb_inp_rep_send(&hids_obj, conn, data,
sizeof(data), NULL);
} else {
err = bt_hids_inp_rep_send(&hids_obj, conn,
INPUT_REP_KEYS_IDX, data,
sizeof(data), NULL);
}
return err;
}
/** @brief Function process and send keyboard state to all active connections
*
* Function process global keyboard state and send it to all connected
* clients.
*
* @return 0 on success or negative error code.
*/
static int key_report_send(void)
{
for (size_t i = 0; i < CONFIG_BT_HIDS_MAX_CLIENT_COUNT; i++) {
if (conn_mode[i].conn) {
int err;
err = key_report_con_send(&hid_keyboard_state,
conn_mode[i].in_boot_mode,
conn_mode[i].conn);
if (err) {
printk("Key report send error: %d\n", err);
return err;
}
}
}
return 0;
}
/** @brief Change key code to ctrl code mask
*
* Function changes the key code to the mask in the control code
* field inside the raport.
* Returns 0 if key code is not a control key.
*
* @param key Key code
*
* @return Mask of the control key or 0.
*/
static uint8_t button_ctrl_code(uint8_t key)
{
if (KEY_CTRL_CODE_MIN <= key && key <= KEY_CTRL_CODE_MAX) {
return (uint8_t)(1U << (key - KEY_CTRL_CODE_MIN));
}
return 0;
}
static int hid_kbd_state_key_set(uint8_t key)
{
uint8_t ctrl_mask = button_ctrl_code(key);
if (ctrl_mask) {
hid_keyboard_state.ctrl_keys_state |= ctrl_mask;
return 0;
}
for (size_t i = 0; i < KEY_CTRL_CODE_MAX; ++i) {
if (hid_keyboard_state.keys_state[i] == 0) {
hid_keyboard_state.keys_state[i] = key;
return 0;
}
}
/* All slots busy */
return -EBUSY;
}
static int hid_kbd_state_key_clear(uint8_t key)
{
uint8_t ctrl_mask = button_ctrl_code(key);
if (ctrl_mask) {
hid_keyboard_state.ctrl_keys_state &= ~ctrl_mask;
return 0;
}
for (size_t i = 0; i < KEY_CTRL_CODE_MAX; ++i) {
if (hid_keyboard_state.keys_state[i] == key) {
hid_keyboard_state.keys_state[i] = 0;
return 0;
}
}
/* Key not found */
return -EINVAL;
}
/** @brief Press a button and send report
*
* @note Functions to manipulate hid state are not reentrant
* @param keys
* @param cnt
*
* @return 0 on success or negative error code.
*/
static int hid_buttons_press(const uint8_t *keys, size_t cnt)
{
while (cnt--) {
int err;
err = hid_kbd_state_key_set(*keys++);
if (err) {
printk("Cannot set selected key.\n");
return err;
}
}
return key_report_send();
}
/** @brief Release the button and send report
*
* @note Functions to manipulate hid state are not reentrant
* @param keys
* @param cnt
*
* @return 0 on success or negative error code.
*/
static int hid_buttons_release(const uint8_t *keys, size_t cnt)
{
while (cnt--) {
int err;
err = hid_kbd_state_key_clear(*keys++);
if (err) {
printk("Cannot clear selected key.\n");
return err;
}
}
return key_report_send();
}
static void button_text_changed(bool down)
{
if (down) {
hid_buttons_press(space_key, 1);
} else {
hid_buttons_release(space_key, 1);
}
}
static void button_shift_changed(bool down)
{
if (down) {
hid_buttons_press(shift_key, 1);
} else {
hid_buttons_release(shift_key, 1);
}
}
static void num_comp_reply(bool accept)
{
struct pairing_data_mitm pairing_data;
struct bt_conn *conn;
if (k_msgq_get(&mitm_queue, &pairing_data, K_NO_WAIT) != 0) {
return;
}
conn = pairing_data.conn;
if (accept) {
bt_conn_auth_passkey_confirm(conn);
printk("Numeric Match, conn %p\n", conn);
} else {
bt_conn_auth_cancel(conn);
printk("Numeric Reject, conn %p\n", conn);
}
bt_conn_unref(pairing_data.conn);
if (k_msgq_num_used_get(&mitm_queue)) {
k_work_submit(&pairing_work);
}
}
static void button_changed(uint32_t button_state, uint32_t has_changed)
{
static bool pairing_button_pressed;
uint32_t buttons = button_state & has_changed;
if (k_msgq_num_used_get(&mitm_queue)) {
if (buttons & KEY_PAIRING_ACCEPT) {
pairing_button_pressed = true;
num_comp_reply(true);
return;
}
if (buttons & KEY_PAIRING_REJECT) {
pairing_button_pressed = true;
num_comp_reply(false);
return;
}
}
/* Do not take any action if the pairing button is released. */
if (pairing_button_pressed &&
(has_changed & (KEY_PAIRING_ACCEPT | KEY_PAIRING_REJECT))) {
pairing_button_pressed = false;
return;
}
if (has_changed & KEY_TEXT_MASK) {
button_text_changed((button_state & KEY_TEXT_MASK) != 0);
}
if (has_changed & KEY_SHIFT_MASK) {
button_shift_changed((button_state & KEY_SHIFT_MASK) != 0);
}
#if CONFIG_NFC_OOB_PAIRING
if (has_changed & KEY_ADV_MASK) {
size_t i;
for (i = 0; i < CONFIG_BT_HIDS_MAX_CLIENT_COUNT; i++) {
if (!conn_mode[i].conn) {
advertising_start();
return;
}
}
printk("Cannot start advertising, all connections slots are"
" taken\n");
}
#endif
}
static void configure_gpio(void)
{
int err;
err = dk_buttons_init(button_changed);
if (err) {
printk("Cannot init buttons (err: %d)\n", err);
}
err = dk_leds_init();
if (err) {
printk("Cannot init LEDs (err: %d)\n", err);
}
}
static void bas_notify(void)
{
uint8_t battery_level = bt_bas_get_battery_level();
battery_level--;
if (!battery_level) {
battery_level = 100U;
}
bt_bas_set_battery_level(battery_level);
}
void main(void)
{
int err;
int blink_status = 0;
printk("Starting Bluetooth Peripheral HIDS keyboard example\n");
configure_gpio();
err = bt_conn_auth_cb_register(&conn_auth_callbacks);
if (err) {
printk("Failed to register authorization callbacks.\n");
return;
}
err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
if (err) {
printk("Failed to register authorization info callbacks.\n");
return;
}
err = bt_enable(NULL);
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return;
}
printk("Bluetooth initialized\n");
hid_init();
if (IS_ENABLED(CONFIG_SETTINGS)) {
settings_load();
}
#if CONFIG_NFC_OOB_PAIRING
k_work_init(&adv_work, delayed_advertising_start);
app_nfc_init();
#else
advertising_start();
#endif
k_work_init(&pairing_work, pairing_process);
for (;;) {
if (is_adv) {
dk_set_led(ADV_STATUS_LED, (++blink_status) % 2);
} else {
dk_set_led_off(ADV_STATUS_LED);
}
k_sleep(K_MSEC(ADV_LED_BLINK_INTERVAL));
/* Battery level simulation */
//bas_notify();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment