Initial commit
This commit is contained in:
commit
bb0d3f5335
4
CMakeLists.txt
Executable file
4
CMakeLists.txt
Executable file
@ -0,0 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.16.0)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(BLE_Button_Matrix)
|
||||
7
include/ble_stream_deck.h
Executable file
7
include/ble_stream_deck.h
Executable file
@ -0,0 +1,7 @@
|
||||
#define TAG "NimBLE HID Keyboard"
|
||||
|
||||
int init_nvs(void);
|
||||
int init_gatt_server(void);
|
||||
void host_task(void *param);
|
||||
void on_sync(void);
|
||||
void on_reset(int reason);
|
||||
3
include/gap.h
Executable file
3
include/gap.h
Executable file
@ -0,0 +1,3 @@
|
||||
struct gap_advertise_fields {
|
||||
|
||||
} gap_advertise_fields;
|
||||
20
include/gatt_server.h
Executable file
20
include/gatt_server.h
Executable file
@ -0,0 +1,20 @@
|
||||
#include <esp_log.h>
|
||||
#include <nimble/nimble_port.h>
|
||||
#include <services/gap/ble_svc_gap.h>
|
||||
#include <services/gatt/ble_svc_gatt.h>
|
||||
#include <host/ble_hs.h>
|
||||
|
||||
#include "hid_keyboard.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define GATT_DEVICE_INFO_UUID 0x180A
|
||||
#define GATT_MANUFACTURER_NAME_UUID 0x2A29
|
||||
#define GAP_DEVICE_NAME "Stream Deck Lookalike"
|
||||
#define GAP_ADV_APPAREANCE 0x03C1
|
||||
#define ADV_DEVICE_NAME "Stream Deck"
|
||||
#define MANUFACTURER_NAME "Sobralia's lab"
|
||||
|
||||
int init_gatt_server(void);
|
||||
void gatt_advertise(void);
|
||||
int gatt_device_info_access_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg);
|
||||
int gatt_battery_level_access_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg);
|
||||
41
include/hid_descriptor.h
Executable file
41
include/hid_descriptor.h
Executable file
@ -0,0 +1,41 @@
|
||||
#ifndef HID_DESCRIPTOR_H
|
||||
#define HID_DESCRIPTOR_H
|
||||
|
||||
/* Main Items Datatype flag */
|
||||
#define HID_DATA 0x00
|
||||
#define HID_CONSTANT 0x01
|
||||
#define HID_ARRAY 0x00
|
||||
#define HID_VARIABLE 0x02
|
||||
#define HID_ABSOLUTE 0x00
|
||||
#define HID_RELATIVE 0x04
|
||||
#define HID_NO_WRAP 0x00
|
||||
#define HID_WRAP 0x08
|
||||
#define HID_LINEAR 0x00
|
||||
#define HID_NON_LINEAR 0x10
|
||||
#define HID_PREFERRED_STATE 0x00
|
||||
#define HID_NO_PREFERRED_STATE 0x20
|
||||
#define HID_NO_NULL_POSITION 0x00
|
||||
#define HID_NULL_STATE 0x40
|
||||
#define HID_BIT_FIELD 0x00
|
||||
#define HID_BUFFERED_BYTE 0x100
|
||||
|
||||
#define HID_USAGE_PAGE 0x05
|
||||
#define HID_USAGE 0x09
|
||||
#define HID_COLLECTION_APPLICATION 0xA1
|
||||
#define HID_USAGE_MINIMUM 0x19
|
||||
#define HID_USAGE_MAXIMUM 0x29
|
||||
#define HID_LOGICAL_MINIMUM 0x15
|
||||
#define HID_LOGICAL_MAXIMUM 0x25
|
||||
#define HID_REPORT_SIZE 0x75
|
||||
#define HID_REPORT_COUNT 0x95
|
||||
#define HID_INPUT 0x81
|
||||
#define HID_OUTPUT 0x91
|
||||
#define HID_FEATURE 0xB1
|
||||
#define HID_END_COLLECTION 0xC0
|
||||
|
||||
#define HID_USAGE_PAGE_GENERIC_DESKTOP 0x01
|
||||
#define HID_USAGE_KEYBOARD 0x06
|
||||
#define HID_USAGE_KEYPAD 0x07
|
||||
#define HID_USAGE_PAGE_LED 0x08
|
||||
|
||||
#endif
|
||||
96
include/hid_keyboard.h
Executable file
96
include/hid_keyboard.h
Executable file
@ -0,0 +1,96 @@
|
||||
#ifndef HID_KEYBOARD_H
|
||||
#define HID_KEYBOARD_H
|
||||
|
||||
#include <nimble/nimble_port.h>
|
||||
#include <services/gap/ble_svc_gap.h>
|
||||
#include <services/gatt/ble_svc_gatt.h>
|
||||
#include <host/ble_hs.h>
|
||||
#include "hid_descriptor.h"
|
||||
#include "hid_keyboard_callbacks.h"
|
||||
#include "utils.h"
|
||||
|
||||
/* UUID for services, characteristics and descriptors */
|
||||
#define HID_SERVICE_UUID 0x1812
|
||||
#define HID_REPORT_REFERENCE_UUID 0x2908
|
||||
#define HID_DESCR_EXTERNAL_REPORT_REFERENCE 0x2907
|
||||
#define HID_BOOT_KEYBOARD_INPUT_REPORT_UUID 0x2A22
|
||||
#define HID_BOOT_KEYBOARD_OUTPUT_REPORT_UUID 0x2A32
|
||||
#define HID_INFORMATION_UUID 0x2A4A
|
||||
#define HID_REPORT_MAP_UUID 0x2A4B
|
||||
#define HID_CONTROL_POINT_UUID 0x2A4C
|
||||
#define HID_REPORT_UUID 0x2A4D
|
||||
#define HID_PROTOCOL_MODE_UUID 0x2A4E
|
||||
|
||||
#define HID_BOOT_PROTOCOL 0x00
|
||||
#define HID_REPORT_PROTOCOL 0x01
|
||||
|
||||
/* handles index for characteristics */
|
||||
#define PROTOCOL_MODE_HANDLE_INDEX 0
|
||||
#define REPORT_MAP_HANDLE_INDEX 1
|
||||
#define REPORT_HANDLE_INDEX 2
|
||||
#define BOOT_KEYBOARD_INPUT_HANDLE_INDEX 3
|
||||
#define BOOT_KEYBOARD_OUTPUT_REPORT 4
|
||||
#define HID_INFORMATION_HANDLE_INDEX 5
|
||||
#define HID_CONTROL_POINT_HANDLE_INDEX 6
|
||||
#define HANDLE_INDEX_LENGTH 7
|
||||
|
||||
#define REPORT_DESCRIPTOR_INPUT 0x01
|
||||
#define REPORT_DESCRIPTOR_OUTPUT 0x02
|
||||
#define REPORT_DESCRIPTOR_FEATURE 0x03
|
||||
|
||||
int init_keyboard_service(void);
|
||||
void keyboard_subscribe_event(struct ble_gap_event *event, void *arg);
|
||||
void set_connection_handle(uint16_t connection_handle);
|
||||
void send_key(TimerHandle_t ev);
|
||||
|
||||
|
||||
typedef struct s_boot_input_report
|
||||
{
|
||||
uint8_t modifiers_keycode_mask;
|
||||
uint8_t reserved_byte;
|
||||
uint8_t key_list[6];
|
||||
} t_boot_input_report;
|
||||
|
||||
typedef struct s_boot_output_report
|
||||
{
|
||||
uint8_t num_lock : 1;
|
||||
uint8_t caps_lock : 1;
|
||||
uint8_t scroll_lock : 1;
|
||||
uint8_t compose : 1;
|
||||
uint8_t kana : 1;
|
||||
uint8_t constant : 3;
|
||||
} t_boot_output_report;
|
||||
|
||||
typedef struct s_input_report
|
||||
{
|
||||
uint8_t modifiers_keycode_mask;
|
||||
uint8_t reserved_byte;
|
||||
uint8_t key_list[6];
|
||||
} t_input_report;
|
||||
|
||||
typedef struct s_report_descriptor
|
||||
{
|
||||
uint8_t id;
|
||||
uint8_t type;
|
||||
} t_report_descriptor;
|
||||
|
||||
typedef struct s_hid_info
|
||||
{
|
||||
uint16_t bcdHID;
|
||||
uint8_t bCountryCode;
|
||||
uint8_t flags;
|
||||
} t_hid_info;
|
||||
|
||||
typedef struct s_keyboard
|
||||
{
|
||||
t_boot_input_report boot_input_report;
|
||||
t_boot_output_report boot_output_report;
|
||||
uint8_t *report_map;
|
||||
t_report_descriptor report_descriptor;
|
||||
t_input_report input_report;
|
||||
t_hid_info hid_info;
|
||||
uint8_t *control_point;
|
||||
} t_keyboard;
|
||||
|
||||
extern t_keyboard keyboard;
|
||||
#endif
|
||||
15
include/hid_keyboard_callbacks.h
Executable file
15
include/hid_keyboard_callbacks.h
Executable file
@ -0,0 +1,15 @@
|
||||
#ifndef HID_KEYBOARD_CALLBACKS_H
|
||||
#define HID_KEYBOARD_CALLBACKS_H
|
||||
|
||||
#include "hid_keyboard.h"
|
||||
|
||||
int hid_keyboard_protocol_mode_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg);
|
||||
int hid_keyboard_report_map_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg);
|
||||
int hid_keyboard_report_map_descr_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg);
|
||||
int hid_keyboard_input_report_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg);
|
||||
int hid_keyboard_boot_input_report_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg);
|
||||
int hid_keyboard_boot_output_report_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg);
|
||||
int hid_keyboard_information_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg);
|
||||
int hid_keyboard_control_point_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg);
|
||||
|
||||
#endif
|
||||
11
include/utils.h
Executable file
11
include/utils.h
Executable file
@ -0,0 +1,11 @@
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#include <freertos/FreeRTOSConfig.h>
|
||||
#include <host/ble_hs.h>
|
||||
|
||||
void print_uint8(void *pointer);
|
||||
void printf_uint16_t_array(uint16_t *array,uint16_t length);
|
||||
void printf_keyboard_report_map(const uint8_t *report_map);
|
||||
|
||||
#endif
|
||||
17
readme.md
Executable file
17
readme.md
Executable file
@ -0,0 +1,17 @@
|
||||
# Guide BLE with NimBLE on esp32 with esp-idf in C
|
||||
|
||||
## BLE principles
|
||||
|
||||
### General
|
||||
### GAP
|
||||
### GATT
|
||||
|
||||
## References documents
|
||||
### ESP-IDF
|
||||
[Official documentation]()
|
||||
[Github]()
|
||||
### NimBLE
|
||||
[Official documentation]()
|
||||
[Github]()
|
||||
### Bluetooth
|
||||
### USB
|
||||
6
src/CMakeLists.txt
Executable file
6
src/CMakeLists.txt
Executable file
@ -0,0 +1,6 @@
|
||||
# This file was automatically generated for projects
|
||||
# without default 'CMakeLists.txt' file.
|
||||
|
||||
FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources})
|
||||
191
src/gatt_server.c
Executable file
191
src/gatt_server.c
Executable file
@ -0,0 +1,191 @@
|
||||
#include "gatt_server.h"
|
||||
|
||||
/* DEV test */
|
||||
static TimerHandle_t send_key_timer;
|
||||
uint16_t conn_handle;
|
||||
|
||||
const struct ble_gatt_svc_def gatt_service_list[] =
|
||||
{
|
||||
{
|
||||
/* Device Information */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_DEVICE_INFO_UUID),
|
||||
.characteristics = (struct ble_gatt_chr_def[])
|
||||
{
|
||||
{
|
||||
/* Manufacturer */
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_MANUFACTURER_NAME_UUID),
|
||||
.access_cb = gatt_device_info_access_callback,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
0, /* No more characteristics */
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Battery service */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(0x180F),
|
||||
.characteristics = (struct ble_gatt_chr_def[])
|
||||
{
|
||||
{
|
||||
/* Battery level */
|
||||
.uuid = BLE_UUID16_DECLARE(0x2A19),
|
||||
.access_cb = gatt_battery_level_access_callback,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
0,
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
0,
|
||||
},
|
||||
};
|
||||
|
||||
int init_gatt_server(void)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
|
||||
result = ble_gatts_count_cfg(gatt_service_list);
|
||||
if (result == 0)
|
||||
{
|
||||
result = ble_gatts_add_svcs(gatt_service_list);
|
||||
}
|
||||
|
||||
/* Press a key every second - test purpose */
|
||||
send_key_timer = xTimerCreate("send_key_timer", pdMS_TO_TICKS(1000), pdTRUE, (void *)0, send_key);
|
||||
xTimerStart(send_key_timer, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int blehr_gap_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_LINK_ESTAB:
|
||||
/* A new connection was established or a connection attempt failed */
|
||||
MODLOG_DFLT(INFO, "connection %s; status=%d\n",
|
||||
event->connect.status == 0 ? "established" : "failed",
|
||||
event->connect.status);
|
||||
|
||||
if (event->connect.status != 0) {
|
||||
/* Connection failed; resume advertising */
|
||||
gatt_advertise();
|
||||
}
|
||||
conn_handle = event->connect.conn_handle;
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
MODLOG_DFLT(INFO, "disconnect; reason=%d\n", event->disconnect.reason);
|
||||
|
||||
/* Connection terminated; resume advertising */
|
||||
gatt_advertise();
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||
MODLOG_DFLT(INFO, "adv complete\n");
|
||||
gatt_advertise();
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_SUBSCRIBE:
|
||||
keyboard_subscribe_event(event, arg);
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d mtu=%d\n",
|
||||
event->mtu.conn_handle,
|
||||
event->mtu.value);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gatt_advertise(void)
|
||||
{
|
||||
struct ble_gap_adv_params adv_params;
|
||||
struct ble_hs_adv_fields fields;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Set the advertisement data included in our advertisements:
|
||||
* o Flags (indicates advertisement type and other general info)
|
||||
* o Advertising tx power
|
||||
* o Device name
|
||||
*/
|
||||
memset(&fields, 0, sizeof(fields));
|
||||
|
||||
/*
|
||||
* Advertise two flags:
|
||||
* o Discoverability in forthcoming advertisement (general)
|
||||
* o BLE-only (BR/EDR unsupported)
|
||||
*/
|
||||
fields.flags = BLE_HS_ADV_F_DISC_GEN |
|
||||
BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
|
||||
/*
|
||||
* Indicate that the TX power level field should be included; have the
|
||||
* stack fill this value automatically. This is done by assigning the
|
||||
* special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
|
||||
*/
|
||||
fields.tx_pwr_lvl_is_present = 1;
|
||||
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
|
||||
|
||||
fields.name = (uint8_t *)ADV_DEVICE_NAME;
|
||||
fields.name_len = strlen(ADV_DEVICE_NAME);
|
||||
fields.name_is_complete = 1;
|
||||
|
||||
fields.appearance = GAP_ADV_APPAREANCE;
|
||||
fields.appearance_is_present = 1;
|
||||
|
||||
rc = ble_gap_adv_set_fields(&fields);
|
||||
//ble_gap_adv_set_data((uint8_t *)&fields, sizeof(fields));
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Begin advertising */
|
||||
memset(&adv_params, 0, sizeof(adv_params));
|
||||
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
|
||||
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||
rc = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER,
|
||||
&adv_params, blehr_gap_event, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int gatt_device_info_access_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg)
|
||||
{
|
||||
uint16_t uuid = ble_uuid_u16(context->chr->uuid);
|
||||
int result;
|
||||
|
||||
result = 0;
|
||||
|
||||
if (uuid == GATT_MANUFACTURER_NAME_UUID)
|
||||
{
|
||||
result = os_mbuf_append(context->om, MANUFACTURER_NAME, strlen(MANUFACTURER_NAME));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int gatt_battery_level_access_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg)
|
||||
{
|
||||
int result;
|
||||
uint8_t battery_level = 90;
|
||||
|
||||
result = 0;
|
||||
|
||||
result = os_mbuf_append(context->om, (const void *)&battery_level, sizeof battery_level);
|
||||
|
||||
return result;
|
||||
}
|
||||
148
src/hid_keyboard_callbacks.c
Executable file
148
src/hid_keyboard_callbacks.c
Executable file
@ -0,0 +1,148 @@
|
||||
#include "hid_keyboard_callbacks.h"
|
||||
|
||||
int hid_keyboard_protocol_mode_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg)
|
||||
{
|
||||
int result = 0;
|
||||
uint8_t protocol = HID_REPORT_PROTOCOL;
|
||||
|
||||
if (context->op == BLE_GATT_ACCESS_OP_READ_CHR)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_protocol_mode_callback READ CHR");
|
||||
result = os_mbuf_append(context->om, &protocol, sizeof protocol);
|
||||
}
|
||||
|
||||
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_protocol_mode_callback WRITE CHR");
|
||||
// TODO
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int hid_keyboard_report_map_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_report_map_callback");
|
||||
if (context->op == BLE_GATT_ACCESS_OP_READ_CHR)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_report_map_callback READ CHR");
|
||||
result = os_mbuf_append(context->om, &keyboard.report_map, sizeof keyboard.report_map);
|
||||
}
|
||||
|
||||
if (context->op == BLE_GATT_ACCESS_OP_READ_DSC)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_report_map_callback READ DSC");
|
||||
//result = os_mbuf_append(context->om, &keyboard_hid_report_description, sizeof keyboard_hid_report_description);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int hid_keyboard_report_map_descr_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg)
|
||||
{
|
||||
int result = 0;
|
||||
uint16_t external_reference;
|
||||
|
||||
external_reference = 0x2A19; /* Battery level characteristc UUID */
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_report_map_descr_callback");
|
||||
result = os_mbuf_append(context->om, &external_reference, sizeof external_reference);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int hid_keyboard_input_report_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = 0;
|
||||
keyboard.report_descriptor.id = 0;
|
||||
keyboard.report_descriptor.type = REPORT_DESCRIPTOR_INPUT;
|
||||
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_keyboard_input_report_callback");
|
||||
|
||||
/* Report */
|
||||
if (context->op == BLE_GATT_ACCESS_OP_READ_CHR)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_keyboard_input_report_callback READ CHR");
|
||||
result = os_mbuf_append(context->om, &keyboard.input_report, sizeof keyboard.input_report);
|
||||
}
|
||||
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_keyboard_input_report_callback WRITE CHR");
|
||||
}
|
||||
|
||||
/* Descriptor */
|
||||
if (context->op == BLE_GATT_ACCESS_OP_READ_DSC)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_keyboard_input_report_callback READ DESC");
|
||||
result = os_mbuf_append(context->om, &keyboard.report_descriptor, sizeof keyboard.report_descriptor);
|
||||
}
|
||||
if (context->op == BLE_GATT_ACCESS_OP_WRITE_DSC)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_keyboard_input_report_callback WRITE DESC");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int hid_keyboard_boot_input_report_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_boot_keyboard_input_report_callback");
|
||||
if (context->op == BLE_GATT_ACCESS_OP_READ_CHR)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_boot_keyboard_input_report_callback READ CHR");
|
||||
result = os_mbuf_append(context->om, &keyboard.boot_input_report, sizeof keyboard.boot_input_report);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int hid_keyboard_boot_output_report_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_boot_keyboard_output_report_callback");
|
||||
if (context->op == BLE_GATT_ACCESS_OP_READ_CHR)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_boot_keyboard_output_report_callback READ CHR");
|
||||
}
|
||||
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_boot_keyboard_output_report_callback WRITE CHR");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int hid_keyboard_information_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_information_callback");
|
||||
if (context->op == BLE_GATT_ACCESS_OP_READ_CHR)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_information_callback READ CHR");
|
||||
os_mbuf_append(context->om, &keyboard.hid_info, sizeof keyboard.hid_info);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int hid_keyboard_control_point_callback(uint16_t connection, uint16_t attribute, struct ble_gatt_access_ctxt *context, void *arg)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_control_point_callback");
|
||||
if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR)
|
||||
{
|
||||
MODLOG_DFLT(INFO, "hid_keyboard_control_point_callback WRITE CHR");
|
||||
keyboard.control_point = (uint8_t *)context->om;
|
||||
context->om = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
185
src/keyboard.c
Executable file
185
src/keyboard.c
Executable file
@ -0,0 +1,185 @@
|
||||
#include "hid_keyboard.h"
|
||||
|
||||
static uint16_t characteristics_handle[HANDLE_INDEX_LENGTH];
|
||||
t_keyboard keyboard;
|
||||
|
||||
/* Dev */
|
||||
static uint16_t connection;
|
||||
|
||||
static const uint8_t report_map[] =
|
||||
{
|
||||
HID_USAGE_PAGE, HID_USAGE_PAGE_GENERIC_DESKTOP,
|
||||
HID_USAGE, HID_USAGE_KEYBOARD,
|
||||
HID_COLLECTION_APPLICATION, 1,
|
||||
HID_USAGE_PAGE, HID_USAGE_KEYPAD,
|
||||
HID_USAGE_MINIMUM, 224,
|
||||
HID_USAGE_MAXIMUM, 231,
|
||||
HID_LOGICAL_MINIMUM,0,
|
||||
HID_LOGICAL_MAXIMUM,1,
|
||||
HID_REPORT_SIZE, 1,
|
||||
HID_REPORT_COUNT, 8,
|
||||
HID_INPUT, HID_DATA | HID_VARIABLE | HID_ABSOLUTE, /* Modifier */
|
||||
|
||||
HID_REPORT_SIZE, 8,
|
||||
HID_REPORT_COUNT, 1,
|
||||
HID_INPUT, HID_CONSTANT, /* Reserved byte */
|
||||
|
||||
HID_REPORT_SIZE, 1,
|
||||
HID_REPORT_COUNT, 5,
|
||||
HID_USAGE_PAGE, HID_USAGE_PAGE_LED,
|
||||
HID_USAGE_MINIMUM, 1,
|
||||
HID_USAGE_MAXIMUM, 5,
|
||||
HID_OUTPUT, HID_DATA | HID_VARIABLE | HID_ABSOLUTE, /* LED */
|
||||
HID_REPORT_SIZE, 3,
|
||||
HID_REPORT_COUNT, 1,
|
||||
HID_OUTPUT, HID_CONSTANT, /* LED report padding */
|
||||
|
||||
HID_REPORT_SIZE, 8,
|
||||
HID_REPORT_COUNT, 6,
|
||||
HID_LOGICAL_MINIMUM, 0,
|
||||
HID_LOGICAL_MAXIMUM, 101,
|
||||
HID_USAGE_PAGE, HID_USAGE_KEYPAD,
|
||||
HID_USAGE_MINIMUM, 0,
|
||||
HID_USAGE_MAXIMUM, 101,
|
||||
HID_INPUT, HID_DATA | HID_ARRAY, /* Array of 6 keys */
|
||||
|
||||
HID_END_COLLECTION
|
||||
};
|
||||
|
||||
static const struct ble_gatt_svc_def keyboard_services[10] =
|
||||
{
|
||||
{
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(HID_SERVICE_UUID),
|
||||
.characteristics = (struct ble_gatt_chr_def[])
|
||||
{
|
||||
{
|
||||
/* Protocol mode */
|
||||
.uuid = BLE_UUID16_DECLARE(HID_PROTOCOL_MODE_UUID),
|
||||
.access_cb = hid_keyboard_protocol_mode_callback,
|
||||
.val_handle = &characteristics_handle[PROTOCOL_MODE_HANDLE_INDEX],
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
},
|
||||
{
|
||||
/* Report map */
|
||||
.uuid = BLE_UUID16_DECLARE(HID_REPORT_MAP_UUID),
|
||||
.access_cb = hid_keyboard_report_map_callback,
|
||||
.val_handle = &characteristics_handle[REPORT_MAP_HANDLE_INDEX],
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
.descriptors = (struct ble_gatt_dsc_def[])
|
||||
{
|
||||
{
|
||||
.uuid = BLE_UUID16_DECLARE(HID_DESCR_EXTERNAL_REPORT_REFERENCE),
|
||||
.access_cb = hid_keyboard_report_map_descr_callback,
|
||||
.att_flags = BLE_ATT_F_READ,
|
||||
},
|
||||
{
|
||||
0,
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Report */
|
||||
.uuid = BLE_UUID16_DECLARE(HID_REPORT_UUID),
|
||||
.access_cb = hid_keyboard_input_report_callback,
|
||||
.val_handle = &characteristics_handle[REPORT_HANDLE_INDEX],
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY,
|
||||
.descriptors = (struct ble_gatt_dsc_def[])
|
||||
{
|
||||
{
|
||||
/* Report reference */
|
||||
.uuid = BLE_UUID16_DECLARE(HID_REPORT_REFERENCE_UUID),
|
||||
.access_cb = hid_keyboard_input_report_callback,
|
||||
.att_flags = BLE_ATT_F_READ,
|
||||
},
|
||||
{
|
||||
0,
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Boot Keyboard Input Report */
|
||||
.uuid = BLE_UUID16_DECLARE(HID_BOOT_KEYBOARD_INPUT_REPORT_UUID),
|
||||
.access_cb = hid_keyboard_boot_input_report_callback,
|
||||
.val_handle = &characteristics_handle[BOOT_KEYBOARD_INPUT_HANDLE_INDEX],
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
|
||||
},
|
||||
{
|
||||
/* Boot Keyboard Output Report */
|
||||
.uuid = BLE_UUID16_DECLARE(HID_BOOT_KEYBOARD_OUTPUT_REPORT_UUID),
|
||||
.access_cb = hid_keyboard_boot_output_report_callback,
|
||||
.val_handle = &characteristics_handle[BOOT_KEYBOARD_OUTPUT_REPORT],
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
},
|
||||
{
|
||||
/* HID Information */
|
||||
.uuid = BLE_UUID16_DECLARE(HID_INFORMATION_UUID),
|
||||
.access_cb = hid_keyboard_information_callback,
|
||||
.val_handle = &characteristics_handle[HID_INFORMATION_HANDLE_INDEX],
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
},
|
||||
{
|
||||
/* HID Control Point */
|
||||
.uuid = BLE_UUID16_DECLARE(HID_CONTROL_POINT_UUID),
|
||||
.access_cb = hid_keyboard_control_point_callback,
|
||||
.val_handle = &characteristics_handle[HID_CONTROL_POINT_HANDLE_INDEX],
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
},
|
||||
{
|
||||
0,
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
0,
|
||||
},
|
||||
};
|
||||
|
||||
int init_keyboard_service(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
memset(&characteristics_handle, 0, sizeof characteristics_handle);
|
||||
memset(&keyboard, 0, sizeof keyboard);
|
||||
|
||||
keyboard.report_map = (uint8_t *)&report_map;
|
||||
|
||||
/*
|
||||
** 0x0111 USB HID specs 1.11
|
||||
** 0x08 FR
|
||||
** 0x00 ???
|
||||
*/
|
||||
keyboard.hid_info.bcdHID = 0x0111;
|
||||
keyboard.hid_info.bCountryCode = 0x08;
|
||||
keyboard.hid_info.flags = 0x00;
|
||||
|
||||
result = ble_gatts_count_cfg(keyboard_services);
|
||||
if (result == 0)
|
||||
{
|
||||
result = ble_gatts_add_svcs(keyboard_services);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void keyboard_subscribe_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
/*MODLOG_DFLT(INFO, "subscribe event; cur_notify=%d cur_indicate=%d \n value handle; "
|
||||
"val_handle=%d\n",
|
||||
event->subscribe.cur_notify, event->subscribe.cur_indicate, event->subscribe.attr_handle);*/
|
||||
connection = event->connect.conn_handle;
|
||||
printf_uint16_t_array(characteristics_handle, sizeof HANDLE_INDEX_LENGTH);
|
||||
}
|
||||
|
||||
void set_connection_handle(uint16_t connection_handle)
|
||||
{
|
||||
connection = connection_handle;
|
||||
}
|
||||
|
||||
void send_key(TimerHandle_t ev)
|
||||
{
|
||||
keyboard.input_report.key_list[0] = keyboard.input_report.key_list[0] == 0xE3 ? 0 : 0xE3;
|
||||
struct os_mbuf *om = ble_hs_mbuf_from_flat(&keyboard.input_report, sizeof keyboard.input_report);
|
||||
ble_gatts_notify_custom(connection, characteristics_handle[REPORT_HANDLE_INDEX], om);
|
||||
//ble_gatts_notify(connection, characteristics_handle[REPORT_HANDLE_INDEX]);
|
||||
}
|
||||
102
src/main .c
Executable file
102
src/main .c
Executable file
@ -0,0 +1,102 @@
|
||||
#include <esp_log.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <freertos/FreeRTOSConfig.h>
|
||||
|
||||
/* BLE */
|
||||
#include <nimble/nimble_port.h>
|
||||
#include <nimble/nimble_port_freertos.h>
|
||||
|
||||
/* Pas bien clair encore */
|
||||
#include <host/ble_hs.h> // Host Event
|
||||
#include <services/gap/ble_svc_gap.h> // Device macros/functions
|
||||
|
||||
#include "utils.h"
|
||||
#include "hid_keyboard.h"
|
||||
#include "ble_stream_deck.h"
|
||||
#include "gatt_server.h"
|
||||
|
||||
void ble_store_config_init(void);
|
||||
static uint8_t blehr_addr_type;
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
result = init_nvs();
|
||||
ESP_ERROR_CHECK(result);
|
||||
|
||||
result = nimble_port_init();
|
||||
ESP_ERROR_CHECK(result);
|
||||
|
||||
/* NimBLE host config */
|
||||
ble_hs_cfg.sync_cb = on_sync;
|
||||
ble_hs_cfg.reset_cb = on_reset;
|
||||
ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_NO_IO;
|
||||
|
||||
result = ble_att_set_preferred_mtu(23);
|
||||
ESP_ERROR_CHECK(result);
|
||||
|
||||
result = init_gatt_server();
|
||||
ESP_ERROR_CHECK(result);
|
||||
|
||||
result = init_keyboard_service();
|
||||
ESP_ERROR_CHECK(result);
|
||||
|
||||
result = ble_svc_gap_device_name_set(GAP_DEVICE_NAME);
|
||||
ESP_ERROR_CHECK(result);
|
||||
|
||||
result = ble_svc_gap_device_appearance_set(GAP_ADV_APPAREANCE);
|
||||
ESP_ERROR_CHECK(result);
|
||||
|
||||
ble_store_config_init();
|
||||
|
||||
nimble_port_freertos_init(host_task);
|
||||
|
||||
//ble_gatts_show_local();
|
||||
}
|
||||
|
||||
int init_nvs()
|
||||
{
|
||||
int result;
|
||||
|
||||
/* Init NVS */
|
||||
result = nvs_flash_init();
|
||||
if (result == ESP_ERR_NVS_NO_FREE_PAGES || result == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
result = nvs_flash_init();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void host_task(void *param)
|
||||
{
|
||||
ESP_LOGI(TAG, "BLE Host Task Started");
|
||||
nimble_port_run();
|
||||
|
||||
nimble_port_freertos_deinit();
|
||||
}
|
||||
|
||||
void on_sync(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ble_hs_id_infer_auto(0, &blehr_addr_type);
|
||||
assert(rc == 0);
|
||||
|
||||
uint8_t addr_val[7] = {0};
|
||||
rc = ble_hs_id_copy_addr(blehr_addr_type, addr_val, NULL);
|
||||
|
||||
ESP_LOGI(TAG, "Device Address: ");
|
||||
print_uint8(addr_val);
|
||||
ESP_LOGI(TAG, "\n");
|
||||
|
||||
/* Begin advertising */
|
||||
gatt_advertise();
|
||||
}
|
||||
|
||||
void on_reset(int reason)
|
||||
{
|
||||
MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
37
src/utils.c
Executable file
37
src/utils.c
Executable file
@ -0,0 +1,37 @@
|
||||
#include "utils.h"
|
||||
|
||||
void print_uint8(void *pointer)
|
||||
{
|
||||
const uint8_t *u8p;
|
||||
|
||||
u8p = pointer;
|
||||
MODLOG_DFLT(INFO, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]);
|
||||
}
|
||||
|
||||
void printf_uint16_t_array(uint16_t *array, uint16_t length)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
while (i < length)
|
||||
{
|
||||
printf("array[%i] = %i\n", i, array[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void printf_keyboard_report_map(const uint8_t *report_map)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
|
||||
while (i < sizeof report_map - 1)
|
||||
{
|
||||
printf("0x%X, 0x%X\n", report_map[i], report_map[i + 1]);
|
||||
i += 2;
|
||||
}
|
||||
printf("0x%X\n", report_map[sizeof(report_map) - 1]);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user