Skip to content

Commit

Permalink
first release
Browse files Browse the repository at this point in the history
  • Loading branch information
zzeneg committed Dec 23, 2024
1 parent f2a5418 commit 9058c00
Show file tree
Hide file tree
Showing 11 changed files with 259 additions and 35 deletions.
13 changes: 13 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
zephyr_library()

if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
zephyr_library_sources_ifdef(CONFIG_ZMK_RAW_HID src/raw-hid/raw_hid.c)
zephyr_library_sources_ifdef(CONFIG_ZMK_RAW_HID src/raw-hid/usb_hid.c)

if (CONFIG_ZMK_BLE)
zephyr_library_sources_ifdef(CONFIG_ZMK_RAW_HID src/raw-hid/hog.c)
endif()

zephyr_include_directories(include)
zephyr_include_directories(${APPLICATION_SOURCE_DIR}/include)
endif()
19 changes: 19 additions & 0 deletions Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
config ZMK_RAW_HID
bool "Enable Raw HID"
default n

config ZMK_RAW_HID_USAGE_PAGE
hex "Raw HID Usage Page"
default 0xFF60

config ZMK_RAW_HID_USAGE
hex "Raw HID Usage"
default 0x61

config ZMK_RAW_HID_DEVICE
string "Raw HID Device"
default HID_1

module = ZMK_RAW_HID
module-str = ZMK_RAW_HID
source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config"
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Raw HID Module for ZMK

This module enables Raw HID functionality for ZMK.
Empty file removed boards/shields/.gitkeep
Empty file.
20 changes: 0 additions & 20 deletions build.yaml

This file was deleted.

13 changes: 0 additions & 13 deletions config/west.yml

This file was deleted.

33 changes: 33 additions & 0 deletions include/zmk/raw-hid/raw_hid.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#pragma once

#include <zmk/hid.h>
#include <zephyr/usb/class/hid.h>
#include <zephyr/usb/class/usb_hid.h>

#define HID_USAGE_PAGE16(page, page2) \
HID_ITEM(HID_ITEM_TAG_USAGE_PAGE, HID_ITEM_TYPE_GLOBAL, 2), page, page2

#define HID_USAGE_PAGE16_SINGLE(a) HID_USAGE_PAGE16((a & 0xFF), ((a >> 8) & 0xFF))

static const uint8_t raw_hid_report_desc[] = {
HID_USAGE_PAGE16_SINGLE(CONFIG_ZMK_RAW_HID_USAGE_PAGE),
HID_USAGE(CONFIG_ZMK_RAW_HID_USAGE),

HID_COLLECTION(0x01),

HID_LOGICAL_MIN8(0x00),
HID_LOGICAL_MAX16(0xFF, 0x00),
HID_REPORT_SIZE(0x08),
HID_REPORT_COUNT(32),

HID_USAGE(0x01),
HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS),

HID_USAGE(0x02),
HID_OUTPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS |
ZMK_HID_MAIN_VAL_NON_VOL),

HID_END_COLLECTION,
};

void process_raw_hid_data(uint8_t *data, uint8_t length);
121 changes: 121 additions & 0 deletions src/raw-hid/hog.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#include <zmk/raw-hid/raw_hid.h>

#include <zephyr/bluetooth/gatt.h>

#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(raw_hid, CONFIG_ZMK_RAW_HID_LOG_LEVEL);

enum {
HIDS_REMOTE_WAKE = BIT(0),
HIDS_NORMALLY_CONNECTABLE = BIT(1),
};

struct hids_info {
uint16_t version; /* version number of base USB HID Specification */
uint8_t code; /* country HID Device hardware is localized for. */
uint8_t flags;
} __packed;

struct hids_report {
uint8_t id; /* report id */
uint8_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 raw_hid_report = {
.id = 0x00,
.type = HIDS_OUTPUT,
};

static uint8_t ctrl_point;

static ssize_t read_hids_info(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
uint16_t len, uint16_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, uint16_t len, uint16_t offset) {
return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data,
sizeof(struct hids_report));
}

static ssize_t read_hids_raw_hid_report_map(struct bt_conn *conn, const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset) {
return bt_gatt_attr_read(conn, attr, buf, len, offset, raw_hid_report_desc,
sizeof(raw_hid_report_desc));
}

static ssize_t write_hids_raw_hid_report(struct bt_conn *conn, const struct bt_gatt_attr *attr,
const void *buf, uint16_t len, uint16_t offset,
uint8_t flags) {
if (offset != 0) {
return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
}

uint8_t *data = (uint8_t *)buf;
process_raw_hid_data(data, len);

return len;
}

static ssize_t write_ctrl_point(struct bt_conn *conn, const struct bt_gatt_attr *attr,
const void *buf, uint16_t len, uint16_t offset, uint8_t flags) {
uint8_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(
raw_hog_svc, BT_GATT_PRIMARY_SERVICE(BT_UUID_HIDS),

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_ENCRYPT,
read_hids_raw_hid_report_map, NULL, NULL),

BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT,
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP,
BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT, NULL,
write_hids_raw_hid_report, NULL),

BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref,
NULL, &raw_hid_report),

BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_CTRL_POINT, BT_GATT_CHRC_WRITE_WITHOUT_RESP,
BT_GATT_PERM_WRITE, NULL, write_ctrl_point, &ctrl_point));

K_THREAD_STACK_DEFINE(raw_hog_q_stack, CONFIG_ZMK_BLE_THREAD_STACK_SIZE);

struct k_work_q raw_hog_work_q;

static int raw_hog_init(void) {

static const struct k_work_queue_config queue_config = {.name = "HID Over GATT Send Work"};
k_work_queue_start(&raw_hog_work_q, raw_hog_q_stack, K_THREAD_STACK_SIZEOF(raw_hog_q_stack),
CONFIG_ZMK_BLE_THREAD_PRIORITY, &queue_config);

return 0;
}

SYS_INIT(raw_hog_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY);
10 changes: 10 additions & 0 deletions src/raw-hid/raw_hid.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <zmk/raw-hid/raw_hid.h>

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(raw_hid, CONFIG_ZMK_RAW_HID_LOG_LEVEL);

__attribute__((weak)) void process_raw_hid_data(uint8_t *data, uint8_t length) {
LOG_WRN("display_process_raw_hid_data is not overriden");

return;
}
58 changes: 58 additions & 0 deletions src/raw-hid/usb_hid.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include <zmk/raw-hid/raw_hid.h>

#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(raw_hid, CONFIG_ZMK_RAW_HID_LOG_LEVEL);

static const struct device *raw_hid_dev;

static K_SEM_DEFINE(hid_sem, 1, 1);

static void in_ready_cb(const struct device *dev) { k_sem_give(&hid_sem); }

#define HID_GET_REPORT_TYPE_MASK 0xff00
#define HID_GET_REPORT_ID_MASK 0x00ff

#define HID_REPORT_TYPE_INPUT 0x100
#define HID_REPORT_TYPE_OUTPUT 0x200
#define HID_REPORT_TYPE_FEATURE 0x300

static int get_report_cb(const struct device *dev, struct usb_setup_packet *setup, int32_t *len,
uint8_t **data) {
return 0;
}

static int set_report_cb(const struct device *dev, struct usb_setup_packet *setup, int32_t *len,
uint8_t **data) {
if ((setup->wValue & HID_GET_REPORT_TYPE_MASK) != HID_REPORT_TYPE_OUTPUT &&
(setup->wValue & HID_GET_REPORT_TYPE_MASK) != HID_REPORT_TYPE_FEATURE) {
LOG_ERR("[# raw-hid #] Set: Unsupported report type %d requested",
(setup->wValue & HID_GET_REPORT_TYPE_MASK) >> 8);
return -ENOTSUP;
}

process_raw_hid_data(*data, *len);

return 0;
}

static const struct hid_ops ops = {
.int_in_ready = in_ready_cb,
.get_report = get_report_cb,
.set_report = set_report_cb,
};

static int raw_hid_init(void) {
raw_hid_dev = device_get_binding(CONFIG_ZMK_RAW_HID_DEVICE);
if (raw_hid_dev == NULL) {
LOG_ERR("Unable to locate HID device");
return -EINVAL;
}

usb_hid_register_device(raw_hid_dev, raw_hid_report_desc, sizeof(raw_hid_report_desc), &ops);

usb_hid_init(raw_hid_dev);

return 0;
}

SYS_INIT(raw_hid_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
4 changes: 2 additions & 2 deletions zephyr/module.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
build:
settings:
board_root: .
cmake: .
kconfig: Kconfig

0 comments on commit 9058c00

Please sign in to comment.