/** @file * @brief HoG Service sample */ /* * Copyright (c) 2016 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #include #include #include #include #include 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, }; enum { HIDS_INPUT = 0x01, HIDS_OUTPUT = 0x02, HIDS_FEATURE = 0x03, }; static struct hids_report input = { .id = 0x01, .type = HIDS_INPUT, }; static struct bt_gatt_ccc_cfg input_ccc_cfg[BT_GATT_CCC_MAX] = {}; static u8_t simulate_input; static u8_t ctrl_point; static u8_t report_map[] = { 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ 0x09, 0x02, /* Usage (Mouse) */ 0xA1, 0x01, /* Collection (Application) */ 0x09, 0x01, /* Usage (Pointer) */ 0xA1, 0x00, /* Collection (Physical) */ 0x05, 0x09, /* Usage Page (Button) */ 0x19, 0x01, /* Usage Minimum (0x01) */ 0x29, 0x03, /* Usage Maximum (0x03) */ 0x15, 0x00, /* Logical Minimum (0) */ 0x25, 0x01, /* Logical Maximum (1) */ 0x95, 0x03, /* Report Count (3) */ 0x75, 0x01, /* Report Size (1) */ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,...) */ 0x95, 0x01, /* Report Count (1) */ 0x75, 0x05, /* Report Size (5) */ 0x81, 0x03, /* Input (Const,Var,Abs,No Wrap,Linear,...) */ 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ 0x09, 0x30, /* Usage (X) */ 0x09, 0x31, /* Usage (Y) */ 0x15, 0x81, /* Logical Minimum (129) */ 0x25, 0x7F, /* Logical Maximum (127) */ 0x75, 0x08, /* Report Size (8) */ 0x95, 0x02, /* Report Count (2) */ 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,...) */ 0xC0, /* End Collection */ 0xC0, /* End Collection */ }; static ssize_t read_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_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, report_map, sizeof(report_map)); } static ssize_t read_report(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 void input_ccc_changed(const struct bt_gatt_attr *attr, u16_t value) { simulate_input = (value == BT_GATT_CCC_NOTIFY) ? 1 : 0; } static ssize_t read_input_report(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, NULL, 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 */ static struct bt_gatt_attr attrs[] = { BT_GATT_PRIMARY_SERVICE(BT_UUID_HIDS), BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_INFO, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, read_info, NULL, &info), BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT_MAP, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, read_report_map, NULL, NULL), BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_AUTHEN, read_input_report, NULL, NULL), BT_GATT_CCC(input_ccc_cfg, input_ccc_changed), BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ, read_report, 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), }; static struct bt_gatt_service hog_svc = BT_GATT_SERVICE(attrs); void hog_init(void) { bt_gatt_service_register(&hog_svc); }