Pete Johanson
5 years ago
13 changed files with 523 additions and 160 deletions
@ -1,9 +1,29 @@
@@ -1,9 +1,29 @@
|
||||
CONFIG_KSCAN=y |
||||
CONFIG_KSCAN_GPIO=y |
||||
# CONFIG_LOG=y |
||||
# CONFIG_ZMK_KSCAN_LOG_LEVEL_DBG=y |
||||
# CONFIG_ZMK_USB_HID_LOG_LEVEL_DBG=y |
||||
CONFIG_USB=y |
||||
CONFIG_USB_DEVICE_STACK=y |
||||
CONFIG_USB_DEVICE_HID=y |
||||
CONFIG_USB_DEVICE_PRODUCT="ZMK Firmware" |
||||
CONFIG_BT=y |
||||
CONFIG_BT_SMP=y |
||||
CONFIG_BT_PERIPHERAL=y |
||||
CONFIG_BT_GATT_DIS=y |
||||
# HID GATT notifications sent this way are *not* picked up by Linux, and possibly others. |
||||
CONFIG_BT_GATT_NOTIFY_MULTIPLE=n |
||||
CONFIG_BT_GATT_BAS=y |
||||
CONFIG_BT_DEVICE_NAME="ZMK Keyboard" |
||||
CONFIG_BT_DEVICE_APPEARANCE=961 |
||||
CONFIG_BT_FIXED_PASSKEY=y |
||||
|
||||
# Incresed stack due to settings API usage |
||||
# CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 |
||||
# |
||||
# CONFIG_BT_SETTINGS=y |
||||
# CONFIG_FLASH=y |
||||
# CONFIG_FLASH_PAGE_LAYOUT=y |
||||
# CONFIG_FLASH_MAP=y |
||||
# CONFIG_NVS=y |
||||
# CONFIG_SETTINGS=y |
||||
# CONFIG_SETTINGS_NONE=n |
||||
|
@ -0,0 +1,136 @@
@@ -0,0 +1,136 @@
|
||||
|
||||
#include <settings/settings.h> |
||||
#include <bluetooth/bluetooth.h> |
||||
#include <bluetooth/conn.h> |
||||
#include <bluetooth/hci.h> |
||||
#include <bluetooth/uuid.h> |
||||
#include <bluetooth/gatt.h> |
||||
|
||||
static void connected(struct bt_conn *conn, u8_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); |
||||
|
||||
// if (bt_conn_set_security(conn, BT_SECURITY_L0))
|
||||
// {
|
||||
// printk("Failed to set security\n");
|
||||
// }
|
||||
} |
||||
|
||||
static void disconnected(struct bt_conn *conn, u8_t reason) |
||||
{ |
||||
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 0x%02x)\n", addr, reason); |
||||
} |
||||
|
||||
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); |
||||
} |
||||
} |
||||
|
||||
static struct bt_conn_cb conn_callbacks = { |
||||
.connected = connected, |
||||
.disconnected = disconnected, |
||||
.security_changed = security_changed, |
||||
}; |
||||
|
||||
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_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); |
||||
} |
||||
|
||||
static struct bt_conn_auth_cb zmk_ble_auth_cb_display = { |
||||
.passkey_display = auth_passkey_display, |
||||
.passkey_entry = NULL, |
||||
.cancel = auth_cancel, |
||||
}; |
||||
|
||||
static const struct bt_data zmk_ble_ad[] = { |
||||
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), |
||||
BT_DATA_BYTES(BT_DATA_UUID16_ALL, |
||||
0x12, 0x18, /* HID Service */ |
||||
0x0f, 0x18), /* Battery Service */ |
||||
}; |
||||
|
||||
static void zmk_ble_ready(int err) |
||||
{ |
||||
if (err) |
||||
{ |
||||
printk("Bluetooth init failed (err %d)\n", err); |
||||
return; |
||||
} |
||||
|
||||
printk("Bluetooth initialized\n"); |
||||
|
||||
err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); |
||||
if (err) |
||||
{ |
||||
printk("Advertising failed to start (err %d)\n", err); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
int zmk_ble_init() |
||||
{ |
||||
if (IS_ENABLED(CONFIG_SETTINGS)) |
||||
{ |
||||
settings_load(); |
||||
} |
||||
int err = bt_enable(zmk_ble_ready); |
||||
|
||||
if (err) |
||||
{ |
||||
printk("BLUETOOTH FAILED"); |
||||
return err; |
||||
} |
||||
|
||||
// err = bt_passkey_set(1234);
|
||||
if (err) |
||||
{ |
||||
printk("Set passkey failed: %d\n", err); |
||||
return err; |
||||
} |
||||
|
||||
bt_conn_cb_register(&conn_callbacks); |
||||
bt_conn_auth_cb_register(&zmk_ble_auth_cb_display); |
||||
|
||||
return 0; |
||||
} |
@ -1,16 +1,52 @@
@@ -1,16 +1,52 @@
|
||||
|
||||
#include "endpoints.h" |
||||
#include "hid.h" |
||||
#include "usb_hid.h" |
||||
#include "hog.h" |
||||
|
||||
int zmk_endpoints_init() |
||||
{ |
||||
int err; |
||||
|
||||
err = zmk_usb_hid_init(); |
||||
if (err) |
||||
{ |
||||
printk("USB HID Init Failed\n"); |
||||
return err; |
||||
} |
||||
|
||||
err = zmk_hog_init(); |
||||
if (err) |
||||
{ |
||||
printk("HOG Init Failed\n"); |
||||
return err; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int zmk_endpoints_send_key_event(struct zmk_key_event key_event) |
||||
{ |
||||
struct zmk_hid_report *report; |
||||
if (key_event.pressed) |
||||
{ |
||||
zmk_usb_hid_press_key(key_event.key); |
||||
zmk_hid_press_key(key_event.key); |
||||
} |
||||
else |
||||
{ |
||||
zmk_usb_hid_release_key(key_event.key); |
||||
zmk_hid_release_key(key_event.key); |
||||
} |
||||
|
||||
report = zmk_hid_get_report(); |
||||
|
||||
// if (zmk_usb_hid_send_report(report) != 0)
|
||||
// {
|
||||
// // LOG_DBG("USB Send Failed");
|
||||
// }
|
||||
|
||||
if (zmk_hog_send_report(report) != 0) |
||||
{ |
||||
// LOG_DBG("HID Over GATTP Send Failed");
|
||||
} |
||||
|
||||
return 0; |
||||
|
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
#include "hid.h" |
||||
|
||||
static struct zmk_hid_report report = { |
||||
.modifiers = 0, |
||||
.keys = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; |
||||
|
||||
#define KEY_OFFSET 0x02 |
||||
#define MAX_KEYS 6 |
||||
|
||||
/*
|
||||
#define TOGGLE_BOOT_KEY(match, val) \ |
||||
for (int idx = 0; idx < MAX_KEYS; idx++) \
|
||||
{ \
|
||||
if (report.boot.keys[idx + KEY_OFFSET] != match) \
|
||||
{ \
|
||||
continue; \
|
||||
} \
|
||||
report.boot.keys[idx + KEY_OFFSET] = val; \
|
||||
break; \
|
||||
} |
||||
*/ |
||||
|
||||
#define TOGGLE_KEY(code, val) WRITE_BIT(report.keys[code / 8], code % 8, val) |
||||
|
||||
int zmk_hid_press_key(zmk_key code) |
||||
{ |
||||
if (code > ZMK_HID_MAX_KEYCODE) |
||||
{ |
||||
return -EINVAL; |
||||
} |
||||
|
||||
// TOGGLE_BOOT_KEY(0U, code);
|
||||
|
||||
TOGGLE_KEY(code, true); |
||||
|
||||
return 0; |
||||
}; |
||||
|
||||
int zmk_hid_release_key(zmk_key code) |
||||
{ |
||||
if (code > ZMK_HID_MAX_KEYCODE) |
||||
{ |
||||
return -EINVAL; |
||||
} |
||||
|
||||
// TOGGLE_BOOT_KEY(code, 0U);
|
||||
|
||||
TOGGLE_KEY(code, false); |
||||
|
||||
return 0; |
||||
}; |
||||
|
||||
struct zmk_hid_report *zmk_hid_get_report() |
||||
{ |
||||
return &report; |
||||
} |
@ -0,0 +1,107 @@
@@ -0,0 +1,107 @@
|
||||
#pragma once |
||||
|
||||
#include <usb/usb_device.h> |
||||
#include <usb/class/usb_hid.h> |
||||
|
||||
#include <dt-bindings/zmk/keys.h> |
||||
|
||||
#include "keys.h" |
||||
|
||||
#define ZMK_HID_MAX_KEYCODE KC_APP |
||||
|
||||
static const u8_t zmk_hid_report_desc[] = { |
||||
/* USAGE_PAGE (Generic Desktop) */ |
||||
HID_GI_USAGE_PAGE, |
||||
USAGE_GEN_DESKTOP, |
||||
/* USAGE (Keyboard) */ |
||||
HID_LI_USAGE, |
||||
USAGE_GEN_DESKTOP_KEYBOARD, |
||||
/* COLLECTION (Application) */ |
||||
HID_MI_COLLECTION, |
||||
COLLECTION_APPLICATION, |
||||
/* REPORT ID (1) */ |
||||
HID_GI_REPORT_ID, |
||||
0x01, |
||||
/* USAGE_PAGE (Keypad) */ |
||||
HID_GI_USAGE_PAGE, |
||||
USAGE_GEN_DESKTOP_KEYPAD, |
||||
/* USAGE_MINIMUM (Keyboard LeftControl) */ |
||||
HID_LI_USAGE_MIN(1), |
||||
0xE0, |
||||
/* USAGE_MAXIMUM (Keyboard Right GUI) */ |
||||
HID_LI_USAGE_MAX(1), |
||||
0xE7, |
||||
/* LOGICAL_MINIMUM (0) */ |
||||
HID_GI_LOGICAL_MIN(1), |
||||
0x00, |
||||
/* LOGICAL_MAXIMUM (1) */ |
||||
HID_GI_LOGICAL_MAX(1), |
||||
0x01, |
||||
|
||||
/* REPORT_SIZE (1) */ |
||||
HID_GI_REPORT_SIZE, |
||||
0x01, |
||||
/* REPORT_COUNT (8) */ |
||||
HID_GI_REPORT_COUNT, |
||||
0x08, |
||||
/* INPUT (Data,Var,Abs) */ |
||||
HID_MI_INPUT, |
||||
0x02, |
||||
|
||||
/* USAGE_PAGE (Keypad) */ |
||||
HID_GI_USAGE_PAGE, |
||||
USAGE_GEN_DESKTOP_KEYPAD, |
||||
/* LOGICAL_MINIMUM (0) */ |
||||
HID_GI_LOGICAL_MIN(1), |
||||
0x00, |
||||
/* LOGICAL_MAXIMUM (101) */ |
||||
HID_GI_LOGICAL_MAX(1), |
||||
0x01, |
||||
/* USAGE_MINIMUM (Reserved) */ |
||||
HID_LI_USAGE_MIN(1), |
||||
0x00, |
||||
/* USAGE_MAXIMUM (Keyboard Application) */ |
||||
HID_LI_USAGE_MAX(1), |
||||
ZMK_HID_MAX_KEYCODE, |
||||
/* REPORT_SIZE (8) */ |
||||
HID_GI_REPORT_SIZE, |
||||
0x01, |
||||
/* REPORT_COUNT (6) */ |
||||
HID_GI_REPORT_COUNT, |
||||
ZMK_HID_MAX_KEYCODE + 1, |
||||
/* INPUT (Data,Ary,Abs) */ |
||||
HID_MI_INPUT, |
||||
0x02, |
||||
/* USAGE_PAGE (Keypad) */ |
||||
HID_GI_USAGE_PAGE, |
||||
USAGE_GEN_DESKTOP_KEYPAD, |
||||
/* REPORT_SIZE (8) */ |
||||
HID_GI_REPORT_SIZE, |
||||
0x02, |
||||
/* REPORT_COUNT (6) */ |
||||
HID_GI_REPORT_COUNT, |
||||
0x01, |
||||
/* INPUT (Cnst,Var,Abs) */ |
||||
HID_MI_INPUT, |
||||
0x03, |
||||
/* END_COLLECTION */ |
||||
HID_MI_COLLECTION_END, |
||||
}; |
||||
|
||||
// struct zmk_hid_boot_report
|
||||
// {
|
||||
// u8_t modifiers;
|
||||
// u8_t _unused;
|
||||
// u8_t keys[6];
|
||||
// } __packed;
|
||||
|
||||
struct zmk_hid_report |
||||
{ |
||||
u8_t modifiers; |
||||
u8_t keys[13]; |
||||
} __packed; |
||||
|
||||
int zmk_hid_press_key(zmk_key key); |
||||
int zmk_hid_release_key(zmk_key key); |
||||
|
||||
struct zmk_hid_report *zmk_hid_get_report(); |
@ -0,0 +1,136 @@
@@ -0,0 +1,136 @@
|
||||
#include <settings/settings.h> |
||||
|
||||
#include <bluetooth/bluetooth.h> |
||||
#include <bluetooth/gatt.h> |
||||
|
||||
#include "ble.h" |
||||
#include "hog.h" |
||||
#include "hid.h" |
||||
|
||||
int zmk_hog_init() |
||||
{ |
||||
return zmk_ble_init(); |
||||
} |
||||
|
||||
enum |
||||
{ |
||||
HIDS_REMOTE_WAKE = BIT(0), |
||||
HIDS_NORMALLY_CONNECTABLE = BIT(1), |
||||
}; |
||||
|
||||
struct hids_info |
||||
{ |
||||
u16_t version; /* version number of base USB HID Specification */ |
||||
u8_t code; /* country HID Device hardware is localized for. */ |
||||
u8_t flags; |
||||
} __packed; |
||||
|
||||
struct hids_report |
||||
{ |
||||
u8_t id; /* report id */ |
||||
u8_t type; /* report type */ |
||||
} __packed; |
||||
|
||||
static struct hids_info info = { |
||||
.version = 0x0000, |
||||
.code = 0x00, |
||||
.flags = HIDS_NORMALLY_CONNECTABLE & HIDS_REMOTE_WAKE, |
||||
}; |
||||
|
||||
enum |
||||
{ |
||||
HIDS_INPUT = 0x01, |
||||
HIDS_OUTPUT = 0x02, |
||||
HIDS_FEATURE = 0x03, |
||||
}; |
||||
|
||||
static struct hids_report input = { |
||||
.id = 0x01, |
||||
.type = HIDS_INPUT, |
||||
}; |
||||
|
||||
static bool host_requests_notification = false; |
||||
static u8_t ctrl_point; |
||||
// static u8_t proto_mode;
|
||||
|
||||
static ssize_t read_hids_info(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset) |
||||
{ |
||||
return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data, sizeof(struct hids_info)); |
||||
} |
||||
|
||||
static ssize_t read_hids_report_ref(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset) |
||||
{ |
||||
return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data, sizeof(struct hids_report)); |
||||
} |
||||
|
||||
static ssize_t read_hids_report_map(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset) |
||||
{ |
||||
return bt_gatt_attr_read(conn, attr, buf, len, offset, zmk_hid_report_desc, sizeof(zmk_hid_report_desc)); |
||||
} |
||||
|
||||
static ssize_t read_hids_input_report(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset) |
||||
{ |
||||
struct zmk_hid_report *report = zmk_hid_get_report(); |
||||
return bt_gatt_attr_read(conn, attr, buf, len, offset, report, sizeof(struct zmk_hid_report)); |
||||
} |
||||
|
||||
// static ssize_t write_proto_mode(struct bt_conn *conn,
|
||||
// const struct bt_gatt_attr *attr,
|
||||
// const void *buf, u16_t len, u16_t offset,
|
||||
// u8_t flags)
|
||||
// {
|
||||
// printk("PROTO CHANGED\n");
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
static void input_ccc_changed(const struct bt_gatt_attr *attr, u16_t value) |
||||
{ |
||||
host_requests_notification = (value == BT_GATT_CCC_NOTIFY) ? 1 : 0; |
||||
} |
||||
|
||||
static ssize_t write_ctrl_point(struct bt_conn *conn, |
||||
const struct bt_gatt_attr *attr, |
||||
const void *buf, u16_t len, u16_t offset, |
||||
u8_t flags) |
||||
{ |
||||
u8_t *value = attr->user_data; |
||||
|
||||
if (offset + len > sizeof(ctrl_point)) |
||||
{ |
||||
return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); |
||||
} |
||||
|
||||
memcpy(value + offset, buf, len); |
||||
|
||||
return len; |
||||
} |
||||
|
||||
/* HID Service Declaration */ |
||||
BT_GATT_SERVICE_DEFINE(hog_svc, |
||||
BT_GATT_PRIMARY_SERVICE(BT_UUID_HIDS), |
||||
// BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_PROTOCOL_MODE, BT_GATT_CHRC_WRITE_WITHOUT_RESP,
|
||||
// BT_GATT_PERM_WRITE, NULL, write_proto_mode, &proto_mode),
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_INFO, BT_GATT_CHRC_READ, |
||||
BT_GATT_PERM_READ, read_hids_info, NULL, &info), |
||||
BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT_MAP, BT_GATT_CHRC_READ, |
||||
BT_GATT_PERM_READ, read_hids_report_map, NULL, NULL), |
||||
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, |
||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, |
||||
BT_GATT_PERM_READ_AUTHEN, |
||||
// BT_GATT_PERM_READ,
|
||||
read_hids_input_report, NULL, NULL), |
||||
BT_GATT_CCC(input_ccc_changed, |
||||
BT_GATT_PERM_READ_AUTHEN | BT_GATT_PERM_WRITE_AUTHEN), |
||||
// BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
|
||||
BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ, |
||||
read_hids_report_ref, NULL, &input), |
||||
BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_CTRL_POINT, |
||||
BT_GATT_CHRC_WRITE_WITHOUT_RESP, |
||||
BT_GATT_PERM_WRITE, |
||||
NULL, write_ctrl_point, &ctrl_point)); |
||||
|
||||
int zmk_hog_send_report(struct zmk_hid_report *report) |
||||
{ |
||||
return bt_gatt_notify(NULL, &hog_svc.attrs[5], report, sizeof(struct zmk_hid_report)); |
||||
}; |
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
|
||||
#pragma once |
||||
|
||||
#include "keys.h" |
||||
#include "hid.h" |
||||
|
||||
int zmk_hog_init(); |
||||
|
||||
int zmk_hog_send_report(struct zmk_hid_report *report); |
Loading…
Reference in new issue