mirror of
https://github.com/espressif/esp-nimble.git
synced 2026-06-05 21:04:49 +00:00
Feature : HID service support
This commit is contained in:
committed by
Rahul Tank
parent
08ac3ca677
commit
34e3842741
@@ -34,14 +34,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define BLE_SVC_DIS_UUID16 0x180A
|
||||
#define BLE_SVC_DIS_CHR_UUID16_SYSTEM_ID 0x2A23
|
||||
#define BLE_SVC_DIS_CHR_UUID16_MODEL_NUMBER 0x2A24
|
||||
#define BLE_SVC_DIS_CHR_UUID16_SERIAL_NUMBER 0x2A25
|
||||
#define BLE_SVC_DIS_CHR_UUID16_FIRMWARE_REVISION 0x2A26
|
||||
#define BLE_SVC_DIS_CHR_UUID16_HARDWARE_REVISION 0x2A27
|
||||
#define BLE_SVC_DIS_CHR_UUID16_SOFTWARE_REVISION 0x2A28
|
||||
#define BLE_SVC_DIS_CHR_UUID16_MANUFACTURER_NAME 0x2A29
|
||||
#define BLE_SVC_DIS_UUID16 0x180A
|
||||
#define BLE_SVC_DIS_CHR_UUID16_SYSTEM_ID 0x2A23
|
||||
#define BLE_SVC_DIS_CHR_UUID16_MODEL_NUMBER 0x2A24
|
||||
#define BLE_SVC_DIS_CHR_UUID16_SERIAL_NUMBER 0x2A25
|
||||
#define BLE_SVC_DIS_CHR_UUID16_FIRMWARE_REVISION 0x2A26
|
||||
#define BLE_SVC_DIS_CHR_UUID16_HARDWARE_REVISION 0x2A27
|
||||
#define BLE_SVC_DIS_CHR_UUID16_SOFTWARE_REVISION 0x2A28
|
||||
#define BLE_SVC_DIS_CHR_UUID16_MANUFACTURER_NAME 0x2A29
|
||||
#define BLE_SVC_DIS_CHR_UUID16_PNP_ID 0x2A50
|
||||
|
||||
/**
|
||||
* Structure holding data for the main characteristics
|
||||
@@ -82,6 +83,12 @@ struct ble_svc_dis_data {
|
||||
* Represent the System Id of the device.
|
||||
*/
|
||||
const char *system_id;
|
||||
|
||||
/**
|
||||
* PNP ID.
|
||||
* Represent the PNP Id of the device.
|
||||
*/
|
||||
const char *pnp_id;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -109,5 +116,7 @@ const char *ble_svc_dis_manufacturer_name(void);
|
||||
int ble_svc_dis_manufacturer_name_set(const char *value);
|
||||
const char *ble_svc_dis_system_id(void);
|
||||
int ble_svc_dis_system_id_set(const char *value);
|
||||
int ble_svc_dis_pnp_id_set(const char *value);
|
||||
const char *ble_svc_dis_pnp_id(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -41,7 +41,8 @@ struct ble_svc_dis_data ble_svc_dis_data = {
|
||||
(MYNEWT_VAL(BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM) >= 0) || \
|
||||
(MYNEWT_VAL(BLE_SVC_DIS_SOFTWARE_REVISION_READ_PERM) >= 0) || \
|
||||
(MYNEWT_VAL(BLE_SVC_DIS_MANUFACTURER_NAME_READ_PERM) >= 0) || \
|
||||
(MYNEWT_VAL(BLE_SVC_DIS_SYSTEM_ID_READ_PERM) >= 0)
|
||||
(MYNEWT_VAL(BLE_SVC_DIS_SYSTEM_ID_READ_PERM) >= 0) || \
|
||||
(MYNEWT_VAL(BLE_SVC_DIS_PNP_ID_READ_PERM) >= 0)
|
||||
static int
|
||||
ble_svc_dis_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
@@ -108,6 +109,14 @@ static const struct ble_gatt_svc_def ble_svc_dis_defs[] = {
|
||||
MYNEWT_VAL(BLE_SVC_DIS_SYSTEM_ID_READ_PERM),
|
||||
}, {
|
||||
#endif
|
||||
#if (MYNEWT_VAL(BLE_SVC_DIS_PNP_ID_READ_PERM) >= 0)
|
||||
/*** Characteristic: PNP Id */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_SVC_DIS_CHR_UUID16_PNP_ID),
|
||||
.access_cb = ble_svc_dis_access,
|
||||
.flags = BLE_GATT_CHR_F_READ |
|
||||
MYNEWT_VAL(BLE_SVC_DIS_PNP_ID_READ_PERM),
|
||||
}, {
|
||||
#endif
|
||||
|
||||
0, /* No more characteristics in this service */
|
||||
}, }
|
||||
@@ -206,6 +215,16 @@ ble_svc_dis_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
#if (MYNEWT_VAL(BLE_SVC_DIS_PNP_ID_READ_PERM) >= 0)
|
||||
case BLE_SVC_DIS_CHR_UUID16_PNP_ID:
|
||||
info = ble_svc_dis_data.pnp_id;
|
||||
#ifdef MYNEWT_VAL_BLE_SVC_PNP_SYSTEM_ID_DEFAULT
|
||||
if (info == NULL) {
|
||||
info = MYNEWT_VAL(BLE_SVC_PNP_SYSTEM_ID_DEFAULT);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
assert(0);
|
||||
@@ -312,6 +331,19 @@ ble_svc_dis_system_id_set(const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
ble_svc_dis_pnp_id(void)
|
||||
{
|
||||
return ble_svc_dis_data.pnp_id;
|
||||
}
|
||||
|
||||
int
|
||||
ble_svc_dis_pnp_id_set(const char *value)
|
||||
{
|
||||
ble_svc_dis_data.pnp_id = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the DIS package.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#if MYNEWT_VAL(BLE_SVC_HID_SERVICE)
|
||||
#ifndef H_BLE_SVC_HID_
|
||||
#define H_BLE_SVC_HID_
|
||||
|
||||
/* 16 Bit Battery Service UUID */
|
||||
#define BLE_SVC_HID_UUID16 0x1812
|
||||
|
||||
/* 16 Bit HID Service Characteristic UUIDs */
|
||||
#define BLE_SVC_HID_CHR_UUID16_REPORT_MAP 0x2A4B
|
||||
#define BLE_SVC_HID_CHR_UUID16_HID_INFO 0x2A4A
|
||||
#define BLE_SVC_HID_CHR_UUID16_HID_CTRL_PT 0x2A4C
|
||||
#define BLE_SVC_HID_DSC_UUID16_EXT_RPT_REF 0x2907
|
||||
#define BLE_SVC_HID_CHR_UUID16_RPT 0x2A4D
|
||||
#define BLE_SVC_HID_DSC_UUID16_RPT_REF 0x2908
|
||||
#define BLE_SVC_HID_CHR_UUID16_PROTOCOL_MODE 0x2A4E
|
||||
#define BLE_SVC_HID_CHR_UUID16_BOOT_KBD_INP 0x2A22
|
||||
#define BLE_SVC_HID_CHR_UUID16_BOOT_KBD_OUT 0x2A32
|
||||
#define BLE_SVC_HID_CHR_UUID16_BOOT_MOUSE_INP 0x2A33
|
||||
|
||||
/* Report type values */
|
||||
#define BLE_SVC_HID_RPT_TYPE_INPUT 0x01
|
||||
#define BLE_SVC_HID_RPT_TYPE_OUTPUT 0x02
|
||||
#define BLE_SVC_HID_RPT_TYPE_FEATURE 0x03
|
||||
|
||||
/* Protocol Mode values */
|
||||
#define BLE_SVC_HID_PROTO_MODE_BOOT 0x00
|
||||
#define BLE_SVC_HID_PROTO_MODE_REPORT 0x01
|
||||
|
||||
#define REPORT_MAP_SIZE 512
|
||||
#define RPT_MAX_LEN 256
|
||||
#define MAX_REPORTS MYNEWT_VAL(BLE_SVC_HID_MAX_RPTS)
|
||||
#define MOUSE_INP_RPT_SIZE 8
|
||||
#define KBD_INP_RPT_SIZE 8
|
||||
|
||||
|
||||
struct report {
|
||||
uint8_t data[RPT_MAX_LEN];
|
||||
uint8_t len;
|
||||
uint8_t type;
|
||||
uint8_t id;
|
||||
uint16_t handle;
|
||||
};
|
||||
|
||||
struct ble_svc_hid_params{
|
||||
unsigned int proto_mode_present : 1;
|
||||
unsigned int kbd_inp_present : 1;
|
||||
unsigned int kbd_out_present : 1;
|
||||
unsigned int mouse_inp_present : 1;
|
||||
/* protocol mode char */
|
||||
uint8_t proto_mode;
|
||||
uint16_t proto_mode_handle;
|
||||
|
||||
/* boot keyboard input char */
|
||||
uint8_t kbd_inp_rpt[KBD_INP_RPT_SIZE];
|
||||
uint16_t kbd_inp_handle;
|
||||
|
||||
/* boot keyboard output char */
|
||||
uint8_t kbd_out_rpt;
|
||||
uint16_t kbd_out_handle;
|
||||
|
||||
/* boot mouse input char */
|
||||
/* NOTE : size of mouse inp report
|
||||
upto byte 2 is mandatory
|
||||
from byte 3 rest is device specific */
|
||||
uint8_t mouse_inp_rpt[MOUSE_INP_RPT_SIZE];
|
||||
uint8_t mouse_inp_rpt_len;
|
||||
uint16_t mouse_inp_handle;
|
||||
|
||||
/* report char */
|
||||
struct report rpts[MAX_REPORTS];
|
||||
uint8_t rpts_len;
|
||||
|
||||
/* report map char */
|
||||
uint8_t report_map[REPORT_MAP_SIZE];
|
||||
uint16_t report_map_handle;
|
||||
uint16_t external_rpt_ref;
|
||||
uint8_t report_map_len;
|
||||
|
||||
/* hid info char */
|
||||
uint32_t hid_info;
|
||||
uint16_t hid_info_handle;
|
||||
|
||||
/* hid control point char */
|
||||
uint8_t ctrl_pt;
|
||||
uint16_t ctrl_pt_handle;
|
||||
};
|
||||
|
||||
void ble_svc_hid_init();
|
||||
int ble_svc_hid_add(struct ble_svc_hid_params params);
|
||||
void ble_svc_hid_reset();
|
||||
|
||||
#endif
|
||||
#endif // CONFIG_BT_NIMBLE_HID_SERVICE
|
||||
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
pkg.name: nimble/host/services/bas
|
||||
pkg.description: Battery Service
|
||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
- ble
|
||||
- bluetooth
|
||||
- hid
|
||||
- nimble
|
||||
|
||||
pkg.deps:
|
||||
- nimble/host
|
||||
|
||||
pkg.init:
|
||||
ble_svc_hid_init: 'MYNEWT_VAL(BLE_SVC_HID_SYSINIT_STAGE)'
|
||||
@@ -0,0 +1,694 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sysinit/sysinit.h"
|
||||
#include "syscfg/syscfg.h"
|
||||
|
||||
#if MYNEWT_VAL(BLE_SVC_HID_SERVICE)
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/ble_gap.h"
|
||||
#include "services/hid/ble_svc_hid.h"
|
||||
|
||||
/* 1 more instance for empty service */
|
||||
#define HID_MAX_SVC_INSTANCES (MYNEWT_VAL(BLE_SVC_HID_MAX_SVC_INSTANCES) + 1)
|
||||
|
||||
/* maximum 7 characteristics except report characteristic */
|
||||
#define HID_MAX_CHRS (HID_MAX_SVC_INSTANCES * \
|
||||
((MYNEWT_VAL(BLE_SVC_HID_MAX_RPTS) + 7)))
|
||||
/* 16 bit UUIDs */
|
||||
static ble_uuid_t *uuid_ext_rpt_ref = BLE_UUID16_DECLARE(BLE_SVC_HID_DSC_UUID16_EXT_RPT_REF);
|
||||
static ble_uuid_t *uuid_report_map = BLE_UUID16_DECLARE(BLE_SVC_HID_CHR_UUID16_REPORT_MAP);
|
||||
static ble_uuid_t *uuid_rpt_ref = BLE_UUID16_DECLARE(BLE_SVC_HID_DSC_UUID16_RPT_REF);
|
||||
static ble_uuid_t *uuid_report = BLE_UUID16_DECLARE(BLE_SVC_HID_CHR_UUID16_RPT);
|
||||
static ble_uuid_t *uuid_hid_info = BLE_UUID16_DECLARE(BLE_SVC_HID_CHR_UUID16_HID_INFO);
|
||||
static ble_uuid_t *uuid_hid_ctrl_pt = BLE_UUID16_DECLARE(BLE_SVC_HID_CHR_UUID16_HID_CTRL_PT);
|
||||
static ble_uuid_t *uuid_proto_mode = BLE_UUID16_DECLARE(BLE_SVC_HID_CHR_UUID16_PROTOCOL_MODE);
|
||||
static ble_uuid_t *uuid_boot_kbd_inp = BLE_UUID16_DECLARE(BLE_SVC_HID_CHR_UUID16_BOOT_KBD_INP);
|
||||
static ble_uuid_t *uuid_boot_kbd_out = BLE_UUID16_DECLARE(BLE_SVC_HID_CHR_UUID16_BOOT_KBD_OUT);
|
||||
static ble_uuid_t *uuid_boot_mouse_inp = BLE_UUID16_DECLARE(BLE_SVC_HID_CHR_UUID16_BOOT_MOUSE_INP);
|
||||
static ble_uuid_t *uuid_hid_svc = BLE_UUID16_DECLARE(BLE_SVC_HID_UUID16);
|
||||
|
||||
uint8_t ble_svc_hid_rpt_val[RPT_MAX_LEN];
|
||||
uint8_t ble_svc_hid_rpt_len;
|
||||
static struct ble_svc_hid_params hid_instances[HID_MAX_SVC_INSTANCES];
|
||||
|
||||
/* Access function */
|
||||
static int
|
||||
ble_svc_hid_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
static struct ble_gatt_dsc_def ble_svc_hid_dscs[HID_MAX_CHRS];
|
||||
static uint8_t ble_svc_hid_dsc_index = 0; // used to store the current index in the dscs array
|
||||
static struct ble_gatt_chr_def ble_svc_hid_chrs[HID_MAX_CHRS];
|
||||
static uint8_t ble_svc_hid_chr_index = 0; // used to store the current index in the chrs array
|
||||
static uint8_t ble_svc_hid_svc_index = 0; // used to store the current index in the svcs array
|
||||
|
||||
static struct ble_gatt_svc_def ble_svc_hid_defs[HID_MAX_SVC_INSTANCES];
|
||||
|
||||
static int
|
||||
ble_svc_hid_chr_write(struct os_mbuf *om, uint16_t min_len,
|
||||
uint16_t max_len, void *dst,
|
||||
uint16_t *len)
|
||||
{
|
||||
uint16_t om_len;
|
||||
int rc;
|
||||
|
||||
om_len = OS_MBUF_PKTLEN(om);
|
||||
if (om_len < min_len || om_len > max_len) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
|
||||
rc = ble_hs_mbuf_to_flat(om, dst, max_len, len);
|
||||
if (rc != 0) {
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ble_gatt_dsc_def*
|
||||
ble_svc_hid_get_dsc(uint8_t num)
|
||||
{
|
||||
if (ble_svc_hid_dsc_index + num - 1 >= HID_MAX_CHRS) {
|
||||
return NULL;
|
||||
}
|
||||
ble_svc_hid_dsc_index = ble_svc_hid_dsc_index + num;
|
||||
return &ble_svc_hid_dscs[ble_svc_hid_dsc_index - num];
|
||||
}
|
||||
|
||||
static struct ble_gatt_chr_def*
|
||||
ble_svc_hid_get_chr_block()
|
||||
{
|
||||
if (ble_svc_hid_chr_index >= HID_MAX_CHRS) {
|
||||
return NULL;
|
||||
}
|
||||
ble_svc_hid_chr_index = ble_svc_hid_chr_index + 1;
|
||||
return &ble_svc_hid_chrs[ble_svc_hid_chr_index - 1];
|
||||
}
|
||||
|
||||
/*returns current chr index */
|
||||
static uint8_t
|
||||
ble_svc_hid_get_curr_chr_idx()
|
||||
{
|
||||
return ble_svc_hid_chr_index;
|
||||
}
|
||||
|
||||
/*returns current svc index */
|
||||
static uint8_t
|
||||
get_curr_svc_idx()
|
||||
{
|
||||
return ble_svc_hid_svc_index;
|
||||
}
|
||||
|
||||
struct report *
|
||||
find_rpt_by_handle(uint16_t handle)
|
||||
{
|
||||
uint8_t instance, instances;
|
||||
int i;
|
||||
|
||||
instances = get_curr_svc_idx();
|
||||
|
||||
for (instance = 0; instance < instances; instance++) {
|
||||
for (i = 0; i < hid_instances[instance].rpts_len; i++) {
|
||||
if (hid_instances[instance].rpts[i].handle == handle) {
|
||||
return &hid_instances[instance].rpts[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
/* return some non-zero value */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ble_gatt_svc_def*
|
||||
ble_svc_get_svc_block()
|
||||
{
|
||||
if (ble_svc_hid_svc_index >= HID_MAX_SVC_INSTANCES) {
|
||||
return NULL;
|
||||
}
|
||||
ble_svc_hid_svc_index = ble_svc_hid_svc_index + 1;
|
||||
return &ble_svc_hid_defs[ble_svc_hid_svc_index - 1];
|
||||
}
|
||||
|
||||
/* fill protocol mode char */
|
||||
static void
|
||||
fill_proto_mode(uint8_t instance)
|
||||
{
|
||||
struct ble_gatt_chr_def *chr, demo_chr;
|
||||
|
||||
if (!hid_instances[instance].proto_mode_present) {
|
||||
return;
|
||||
}
|
||||
demo_chr = (struct ble_gatt_chr_def) {
|
||||
/*** Report Map characteristic */
|
||||
.uuid = uuid_proto_mode,
|
||||
.access_cb = ble_svc_hid_access,
|
||||
.val_handle = &hid_instances[instance].proto_mode_handle,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE_NO_RSP |
|
||||
#if MYNEWT_VAL(BLE_SM_SC_LVL) == 2
|
||||
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC |
|
||||
#elif MYNEWT_VAL(BLE_SM_SC_LVL) == 3
|
||||
BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_WRITE_AUTHEN |
|
||||
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC |
|
||||
#endif
|
||||
0,
|
||||
};
|
||||
|
||||
chr = ble_svc_hid_get_chr_block();
|
||||
memcpy(chr, &demo_chr, sizeof(struct ble_gatt_chr_def));
|
||||
}
|
||||
|
||||
/* fill boot keyboard inp char */
|
||||
void
|
||||
fill_boot_kbd_inp(uint8_t instance)
|
||||
{
|
||||
struct ble_gatt_chr_def *chr, demo_chr;
|
||||
|
||||
if (!hid_instances[instance].kbd_inp_present) {
|
||||
return;
|
||||
}
|
||||
demo_chr = (struct ble_gatt_chr_def) {
|
||||
/*** Report Map characteristic */
|
||||
.uuid = uuid_boot_kbd_inp,
|
||||
.access_cb = ble_svc_hid_access,
|
||||
.val_handle = &hid_instances[instance].kbd_inp_handle,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY |
|
||||
BLE_GATT_CHR_F_WRITE |
|
||||
#if MYNEWT_VAL(BLE_SM_SC_LVL) == 2
|
||||
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC |
|
||||
#elif MYNEWT_VAL(BLE_SM_SC_LVL) == 3
|
||||
BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_WRITE_AUTHEN |
|
||||
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC |
|
||||
#endif
|
||||
0,
|
||||
};
|
||||
|
||||
chr = ble_svc_hid_get_chr_block();
|
||||
memcpy(chr, &demo_chr, sizeof(struct ble_gatt_chr_def));
|
||||
}
|
||||
|
||||
/* fill boot keyboard out char */
|
||||
void
|
||||
fill_boot_kbd_out(uint8_t instance)
|
||||
{
|
||||
struct ble_gatt_chr_def *chr, demo_chr;
|
||||
|
||||
if (!hid_instances[instance].kbd_out_present) {
|
||||
return;
|
||||
}
|
||||
demo_chr = (struct ble_gatt_chr_def) {
|
||||
/*** Report Map characteristic */
|
||||
.uuid = uuid_boot_kbd_out,
|
||||
.access_cb = ble_svc_hid_access,
|
||||
.val_handle = &hid_instances[instance].kbd_out_handle,
|
||||
.flags = BLE_GATT_CHR_F_READ |
|
||||
BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_WRITE |
|
||||
#if MYNEWT_VAL(BLE_SM_SC_LVL) == 2
|
||||
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC |
|
||||
#elif MYNEWT_VAL(BLE_SM_SC_LVL) == 3
|
||||
BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_WRITE_AUTHEN |
|
||||
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC |
|
||||
#endif
|
||||
0,
|
||||
};
|
||||
|
||||
chr = ble_svc_hid_get_chr_block();
|
||||
memcpy(chr, &demo_chr, sizeof(struct ble_gatt_chr_def));
|
||||
}
|
||||
/* fill boot mouse inp char */
|
||||
void
|
||||
fill_boot_mouse_inp(uint8_t instance)
|
||||
{
|
||||
struct ble_gatt_chr_def *chr, demo_chr;
|
||||
|
||||
if (!hid_instances[instance].mouse_inp_present) {
|
||||
return;
|
||||
}
|
||||
demo_chr = (struct ble_gatt_chr_def) {
|
||||
/*** Report Map characteristic */
|
||||
.uuid = uuid_boot_mouse_inp,
|
||||
.access_cb = ble_svc_hid_access,
|
||||
.val_handle = &hid_instances[instance].mouse_inp_handle,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY |
|
||||
BLE_GATT_CHR_F_WRITE |
|
||||
#if MYNEWT_VAL(BLE_SM_SC_LVL) == 2
|
||||
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC |
|
||||
#elif MYNEWT_VAL(BLE_SM_SC_LVL) == 3
|
||||
BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_WRITE_AUTHEN |
|
||||
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC |
|
||||
#endif
|
||||
0,
|
||||
};
|
||||
|
||||
chr = ble_svc_hid_get_chr_block();
|
||||
memcpy(chr, &demo_chr, sizeof(struct ble_gatt_chr_def));
|
||||
}
|
||||
/* create report map char */
|
||||
static void
|
||||
fill_rpt_map(uint8_t instance)
|
||||
{
|
||||
struct ble_gatt_chr_def *chr, demo_chr;
|
||||
struct ble_gatt_dsc_def *dsc;
|
||||
struct ble_gatt_dsc_def *demo_dsc = (struct ble_gatt_dsc_def[]) {
|
||||
{
|
||||
/* External Report Reference descriptor */
|
||||
.uuid = uuid_ext_rpt_ref,
|
||||
.access_cb = ble_svc_hid_access,
|
||||
.att_flags = BLE_ATT_F_READ,
|
||||
.arg = &hid_instances[instance].report_map_handle,
|
||||
}, {
|
||||
0,
|
||||
}
|
||||
};
|
||||
demo_chr = (struct ble_gatt_chr_def) {
|
||||
/*** Report Map characteristic */
|
||||
.uuid = uuid_report_map,
|
||||
.access_cb = ble_svc_hid_access,
|
||||
.val_handle = &hid_instances[instance].report_map_handle,
|
||||
.flags = BLE_GATT_CHR_F_READ |
|
||||
#if MYNEWT_VAL(BLE_SM_SC_LVL) == 2
|
||||
BLE_GATT_CHR_F_READ_ENC |
|
||||
#elif MYNEWT_VAL(BLE_SM_SC_LVL) == 3
|
||||
BLE_GATT_CHR_F_READ_AUTHEN |
|
||||
BLE_GATT_CHR_F_READ_ENC |
|
||||
#endif
|
||||
0,
|
||||
};
|
||||
/* logic : allocate the discriptor needed and then allocate one more and assign 0 to it,
|
||||
this is done to indicate there are no more descriptors */
|
||||
dsc = ble_svc_hid_get_dsc(2);
|
||||
memcpy(dsc, demo_dsc, 2 * sizeof(struct ble_gatt_dsc_def));
|
||||
|
||||
demo_chr.descriptors = dsc,
|
||||
chr = ble_svc_hid_get_chr_block();
|
||||
memcpy(chr, &demo_chr, sizeof(struct ble_gatt_chr_def));
|
||||
}
|
||||
|
||||
/* create report chars */
|
||||
static void
|
||||
fill_reports(uint8_t instance)
|
||||
{
|
||||
struct ble_gatt_chr_def *chr, demo_chr;
|
||||
struct ble_gatt_dsc_def *dsc;
|
||||
int i;
|
||||
struct ble_gatt_dsc_def *demo_dsc = (struct ble_gatt_dsc_def[]) {
|
||||
{
|
||||
/* Report Reference descriptor */
|
||||
.uuid = uuid_rpt_ref,
|
||||
.access_cb = ble_svc_hid_access,
|
||||
.att_flags = BLE_ATT_F_READ
|
||||
}, {
|
||||
0,
|
||||
}
|
||||
};
|
||||
demo_chr = (struct ble_gatt_chr_def) {
|
||||
/*** Report characteristic */
|
||||
.uuid = uuid_report,
|
||||
.access_cb = ble_svc_hid_access,
|
||||
};
|
||||
/* Multiple instances of this characteristic are allowed*/
|
||||
for (i = 0; i < hid_instances[instance].rpts_len; i++) {
|
||||
/* logic : allocate the discriptor needed and then allocate one more and assign 0 to it,
|
||||
this is done to indicate there are no more descriptors */
|
||||
dsc = ble_svc_hid_get_dsc(2);
|
||||
demo_dsc[0].arg = &hid_instances[instance].rpts[i].handle;
|
||||
memcpy(dsc, demo_dsc, 2 * sizeof(struct ble_gatt_dsc_def));
|
||||
|
||||
switch (hid_instances[instance].rpts[i].type) {
|
||||
case BLE_SVC_HID_RPT_TYPE_INPUT:
|
||||
demo_chr.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE;
|
||||
break;
|
||||
case BLE_SVC_HID_RPT_TYPE_OUTPUT:
|
||||
demo_chr.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_NO_RSP | BLE_GATT_CHR_F_WRITE;
|
||||
break;
|
||||
case BLE_SVC_HID_RPT_TYPE_FEATURE:
|
||||
demo_chr.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE;
|
||||
break;
|
||||
default :
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
demo_chr.flags |= (
|
||||
#if MYNEWT_VAL(BLE_SM_SC_LVL) == 2
|
||||
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC |
|
||||
#elif MYNEWT_VAL(BLE_SM_SC_LVL) == 3
|
||||
BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_WRITE_AUTHEN |
|
||||
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC |
|
||||
#endif
|
||||
0);
|
||||
demo_chr.val_handle = &hid_instances[instance].rpts[i].handle;
|
||||
demo_chr.descriptors = dsc;
|
||||
|
||||
chr = ble_svc_hid_get_chr_block();
|
||||
memcpy(chr, &demo_chr, sizeof(struct ble_gatt_chr_def));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fill_hid_info(uint8_t instance)
|
||||
{
|
||||
struct ble_gatt_chr_def *chr, demo_chr;
|
||||
|
||||
demo_chr = (struct ble_gatt_chr_def) {
|
||||
/*** HID Information Characteristic */
|
||||
.uuid = uuid_hid_info,
|
||||
.access_cb = ble_svc_hid_access,
|
||||
.val_handle = &hid_instances[instance].hid_info_handle,
|
||||
.flags = BLE_GATT_CHR_F_READ |
|
||||
#if MYNEWT_VAL(BLE_SM_SC_LVL) == 2
|
||||
BLE_GATT_CHR_F_READ_ENC |
|
||||
#elif MYNEWT_VAL(BLE_SM_SC_LVL) == 3
|
||||
BLE_GATT_CHR_F_READ_AUTHEN |
|
||||
BLE_GATT_CHR_F_READ_ENC |
|
||||
#endif
|
||||
0,
|
||||
};
|
||||
chr = ble_svc_hid_get_chr_block();
|
||||
memcpy(chr, &demo_chr, sizeof(struct ble_gatt_chr_def));
|
||||
}
|
||||
|
||||
static void
|
||||
fill_ctrl_pt(uint8_t instance)
|
||||
{
|
||||
struct ble_gatt_chr_def *chr, demo_chr;
|
||||
|
||||
demo_chr = (struct ble_gatt_chr_def) {
|
||||
/*** HID Control Point Characteristic */
|
||||
.uuid = uuid_hid_ctrl_pt,
|
||||
.access_cb = ble_svc_hid_access,
|
||||
.val_handle = &hid_instances[instance].ctrl_pt_handle,
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP |
|
||||
#if MYNEWT_VAL(BLE_SM_SC_LVL) == 2
|
||||
BLE_GATT_CHR_F_WRITE_ENC |
|
||||
#elif MYNEWT_VAL(BLE_SM_SC_LVL) == 3
|
||||
BLE_GATT_CHR_F_WRITE_AUTHEN |
|
||||
BLE_GATT_CHR_F_WRITE_ENC |
|
||||
#endif
|
||||
0,
|
||||
};
|
||||
chr = ble_svc_hid_get_chr_block();
|
||||
memcpy(chr, &demo_chr, sizeof(struct ble_gatt_chr_def));
|
||||
}
|
||||
|
||||
/**
|
||||
* allocating one more chr block with
|
||||
* value set to zero
|
||||
*/
|
||||
static void
|
||||
ble_svc_hid_end_chrs()
|
||||
{
|
||||
struct ble_gatt_chr_def *chr;
|
||||
chr = ble_svc_hid_get_chr_block();
|
||||
memset(chr, 0, sizeof(struct ble_gatt_chr_def));
|
||||
}
|
||||
/**
|
||||
* HID access function
|
||||
*/
|
||||
static int
|
||||
ble_svc_hid_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg)
|
||||
{
|
||||
uint16_t uuid16 = ble_uuid_u16(ctxt->chr->uuid);
|
||||
int rc;
|
||||
struct report *rpt;
|
||||
uint16_t rpt_ref_val = 0;
|
||||
uint16_t out_rpt_len = 0;
|
||||
uint8_t instances = get_curr_svc_idx();
|
||||
uint16_t handle;
|
||||
uint8_t val;
|
||||
|
||||
for (int instance = 0; instance < instances; instance++) {
|
||||
switch (uuid16) {
|
||||
case BLE_SVC_HID_CHR_UUID16_REPORT_MAP:
|
||||
if (hid_instances[instance].report_map_handle != attr_handle) {
|
||||
continue;
|
||||
}
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
|
||||
rc = os_mbuf_append(ctxt->om, &hid_instances[instance].report_map,
|
||||
hid_instances[instance].report_map_len);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
case BLE_SVC_HID_DSC_UUID16_EXT_RPT_REF:
|
||||
handle = *(uint16_t*)(ctxt->dsc->arg);
|
||||
if (hid_instances[instance].report_map_handle != handle) {
|
||||
continue;
|
||||
}
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC);
|
||||
rc = os_mbuf_append(ctxt->om, &hid_instances[instance].external_rpt_ref,
|
||||
sizeof hid_instances[instance].external_rpt_ref);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
case BLE_SVC_HID_DSC_UUID16_RPT_REF:
|
||||
/* this will work without having any instance check
|
||||
because find_rpt_by_handle already checks for the instance */
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC);
|
||||
rpt = find_rpt_by_handle(*(uint16_t *)ctxt->dsc->arg);
|
||||
rpt_ref_val = (0x00FF & rpt->id) | ((0x00FF & (uint16_t)rpt->type) << 8); /* check if this should be opposite */
|
||||
rc = os_mbuf_append(ctxt->om, &rpt_ref_val,
|
||||
sizeof rpt_ref_val);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
|
||||
case BLE_SVC_HID_CHR_UUID16_HID_INFO:
|
||||
if (hid_instances[instance].hid_info_handle != attr_handle) {
|
||||
continue;
|
||||
}
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
|
||||
rc = os_mbuf_append(ctxt->om, &hid_instances[instance].hid_info,
|
||||
sizeof hid_instances[instance].hid_info);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
|
||||
case BLE_SVC_HID_CHR_UUID16_HID_CTRL_PT:
|
||||
if (hid_instances[instance].ctrl_pt_handle != attr_handle) {
|
||||
continue;
|
||||
}
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR);
|
||||
/* check if the value is correct */
|
||||
rc = ble_hs_mbuf_to_flat(ctxt->om, &val, sizeof(uint8_t), NULL);
|
||||
if(rc != 0) {
|
||||
return BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
if(val == 0 || val == 1) {
|
||||
rc = ble_svc_hid_chr_write(ctxt->om, 0, sizeof hid_instances[instance].ctrl_pt, &hid_instances[instance].ctrl_pt, NULL);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
|
||||
case BLE_SVC_HID_CHR_UUID16_BOOT_KBD_OUT:
|
||||
if (hid_instances[instance].kbd_out_handle != attr_handle) {
|
||||
continue;
|
||||
}
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR || ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
rc = os_mbuf_append(ctxt->om, &hid_instances[instance].kbd_out_rpt,
|
||||
sizeof(hid_instances[instance].kbd_out_rpt));
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
} else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
rc = ble_svc_hid_chr_write(ctxt->om, 0, sizeof(hid_instances[instance].kbd_out_rpt), &hid_instances[instance].kbd_out_rpt, NULL);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
return 0;
|
||||
case BLE_SVC_HID_CHR_UUID16_BOOT_KBD_INP:
|
||||
if (hid_instances[instance].kbd_inp_handle != attr_handle) {
|
||||
continue;
|
||||
}
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR || ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
rc = os_mbuf_append(ctxt->om, &hid_instances[instance].kbd_inp_rpt,
|
||||
sizeof(hid_instances[instance].kbd_inp_rpt));
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
} else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
rc = ble_svc_hid_chr_write(ctxt->om, 0, sizeof(hid_instances[instance].kbd_inp_rpt), hid_instances[instance].kbd_inp_rpt, NULL);
|
||||
if (ctxt->chr->flags & BLE_GATT_CHR_F_NOTIFY) {
|
||||
ble_gatts_chr_updated(*(ctxt->chr->val_handle));
|
||||
}
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
return 0;
|
||||
case BLE_SVC_HID_CHR_UUID16_BOOT_MOUSE_INP:
|
||||
if (hid_instances[instance].mouse_inp_handle != attr_handle) {
|
||||
continue;
|
||||
}
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR || ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
rc = os_mbuf_append(ctxt->om, &hid_instances[instance].mouse_inp_rpt,
|
||||
hid_instances[instance].mouse_inp_rpt_len);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
} else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
rc = ble_svc_hid_chr_write(ctxt->om, 0, sizeof(hid_instances[instance].mouse_inp_rpt), hid_instances[instance].mouse_inp_rpt, &out_rpt_len);
|
||||
if (rc != 0) {
|
||||
return BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
hid_instances[instance].mouse_inp_rpt_len = out_rpt_len;
|
||||
if (ctxt->chr->flags & BLE_GATT_CHR_F_NOTIFY) {
|
||||
ble_gatts_chr_updated(*(ctxt->chr->val_handle));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
case BLE_SVC_HID_CHR_UUID16_PROTOCOL_MODE:
|
||||
if (hid_instances[instance].proto_mode_handle != attr_handle) {
|
||||
continue;
|
||||
}
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR || ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
rc = os_mbuf_append(ctxt->om, &hid_instances[instance].proto_mode,
|
||||
sizeof(hid_instances[instance].proto_mode));
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
} else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
/* check if the value is correct */
|
||||
rc = ble_hs_mbuf_to_flat(ctxt->om, &val, sizeof(uint8_t), NULL);
|
||||
if(rc != 0) {
|
||||
return BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
if(val == 0 || val == 1) {
|
||||
rc = ble_svc_hid_chr_write(ctxt->om, 0, sizeof(hid_instances[instance].proto_mode), &hid_instances[instance].proto_mode, NULL);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
return 0;
|
||||
case BLE_SVC_HID_CHR_UUID16_RPT:
|
||||
/* this will work without any check of instance */
|
||||
rpt = find_rpt_by_handle(*(ctxt->chr->val_handle));
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR || ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR);
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
rc = os_mbuf_append(ctxt->om, rpt->data,
|
||||
rpt->len);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
} else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
rc = ble_svc_hid_chr_write(ctxt->om, 0, RPT_MAX_LEN, &(rpt->data), &out_rpt_len);
|
||||
if (rc != 0) {
|
||||
return BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
rpt->len = out_rpt_len;
|
||||
if (ctxt->chr->flags & BLE_GATT_CHR_F_NOTIFY) {
|
||||
ble_gatts_chr_updated(*(ctxt->chr->val_handle));
|
||||
}
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
return 0;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
}
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
/* can be called multiple times */
|
||||
int
|
||||
ble_svc_hid_add(struct ble_svc_hid_params params)
|
||||
{
|
||||
/* Ensure this function only gets called by sysinit. */
|
||||
SYSINIT_ASSERT_ACTIVE();
|
||||
|
||||
uint8_t svc_idx;
|
||||
int rc = 0;
|
||||
struct ble_gatt_svc_def *svc;
|
||||
uint8_t chr_idx;
|
||||
|
||||
svc_idx = get_curr_svc_idx();
|
||||
/* one instance is required for empty service */
|
||||
if (HID_MAX_SVC_INSTANCES - 1 <= svc_idx) {
|
||||
/* increase instances count */
|
||||
return BLE_HS_ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(&hid_instances[svc_idx], ¶ms, sizeof(struct ble_svc_hid_params));
|
||||
|
||||
/* get the pointer to the first characteristic */
|
||||
chr_idx = ble_svc_hid_get_curr_chr_idx();
|
||||
|
||||
/* Fill protocol mode characteristic */
|
||||
fill_proto_mode(svc_idx);
|
||||
/* Fill report map characteristic */
|
||||
fill_rpt_map(svc_idx);
|
||||
/* Fill report characteristics */
|
||||
fill_reports(svc_idx);
|
||||
/* Fill the boot keyboard input characteristic */
|
||||
fill_boot_kbd_inp(svc_idx);
|
||||
/* Fill the boot keyboard output characteristic */
|
||||
fill_boot_kbd_out(svc_idx);
|
||||
/* Fill the boot mouse input characteristic */
|
||||
fill_boot_mouse_inp(svc_idx);
|
||||
/* Fill the hid info characteristic */
|
||||
fill_hid_info(svc_idx);
|
||||
/* Fill the control point characteristic */
|
||||
fill_ctrl_pt(svc_idx);
|
||||
/* End the characteristics with the characteristic with empty block */
|
||||
ble_svc_hid_end_chrs();
|
||||
|
||||
svc = ble_svc_get_svc_block();
|
||||
svc->type = BLE_GATT_SVC_TYPE_PRIMARY;
|
||||
svc->uuid = uuid_hid_svc;
|
||||
svc->characteristics = ble_svc_hid_chrs + chr_idx;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocating one more svc block
|
||||
* with value set to 0
|
||||
*/
|
||||
static int
|
||||
ble_svc_hid_end()
|
||||
{
|
||||
struct ble_gatt_svc_def *svc;
|
||||
|
||||
svc = ble_svc_get_svc_block();
|
||||
if (svc == NULL) {
|
||||
return BLE_HS_ENOMEM;
|
||||
}
|
||||
memset(svc, 0, sizeof(struct ble_gatt_svc_def));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the ble_gatts_reset() is called after ble_svc_hid_init(),
|
||||
call ble_svc_hid_reset() to reinitialize the service.
|
||||
*/
|
||||
void
|
||||
ble_svc_hid_reset()
|
||||
{
|
||||
ble_svc_hid_dsc_index = 0;
|
||||
ble_svc_hid_chr_index = 0;
|
||||
ble_svc_hid_svc_index = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the HID Service.
|
||||
*/
|
||||
void
|
||||
ble_svc_hid_init()
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Ensure this function only gets called by sysinit. */
|
||||
SYSINIT_ASSERT_ACTIVE();
|
||||
|
||||
rc = ble_svc_hid_end();
|
||||
SYSINIT_PANIC_ASSERT(rc == 0);
|
||||
|
||||
rc = ble_gatts_count_cfg(ble_svc_hid_defs);
|
||||
SYSINIT_PANIC_ASSERT(rc == 0);
|
||||
|
||||
rc = ble_gatts_add_svcs(ble_svc_hid_defs);
|
||||
SYSINIT_PANIC_ASSERT(rc == 0);
|
||||
}
|
||||
#endif // CONFIG_BT_NIMBLE_HID_SERVICE
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/* Scan Parameters Service */
|
||||
|
||||
#ifndef H_BLE_SVC_SPS_
|
||||
#define H_BLE_SVC_SPS_
|
||||
|
||||
|
||||
#define BLE_SVC_SPS_UUID16 0x1813
|
||||
#define BLE_SVC_SPS_CHR_UUID16_SCAN_ITVL_WINDOW 0x2A23
|
||||
#define BLE_SVC_SPS_CHR_UUID16_SCAN_REFRESH 0x2A31
|
||||
|
||||
void ble_svc_sps_scan_refresh(void);
|
||||
void ble_svc_sps_init(uint16_t scan_itvl, uint16_t scan_window);
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
pkg.name: nimble/host/services/dis
|
||||
pkg.description: Device Information Service Implementation.
|
||||
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
|
||||
pkg.homepage: "http://mynewt.apache.org/"
|
||||
pkg.keywords:
|
||||
- ble
|
||||
- bluetooth
|
||||
- sps
|
||||
- nimble
|
||||
|
||||
pkg.deps:
|
||||
- nimble/host
|
||||
|
||||
pkg.init:
|
||||
ble_svc_dis_init: 'MYNEWT_VAL(BLE_SVC_SPS_SYSINIT_STAGE)'
|
||||
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "sysinit/sysinit.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "services/sps/ble_svc_sps.h"
|
||||
|
||||
static uint16_t ble_scan_itvl;
|
||||
static uint16_t ble_scan_window;
|
||||
static uint8_t ble_scan_refresh;
|
||||
static uint16_t ble_scan_itvl_handle;
|
||||
static uint16_t ble_scan_refresh_handle;
|
||||
|
||||
|
||||
/* Access function */
|
||||
static int
|
||||
ble_svc_sps_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
static const struct ble_gatt_svc_def ble_svc_sps_defs[] = {
|
||||
{ /*** Service: Device Information Service (SPS). */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_SVC_SPS_UUID16),
|
||||
.characteristics = (struct ble_gatt_chr_def[]) { {
|
||||
/*** Characteristic: Scan Interval */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_SVC_SPS_CHR_UUID16_SCAN_ITVL_WINDOW),
|
||||
.access_cb = ble_svc_sps_access,
|
||||
.flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
|
||||
.val_handle = &ble_scan_itvl_handle,
|
||||
}, {
|
||||
/*** Characteristic: Scan Refresh */
|
||||
.uuid = BLE_UUID16_DECLARE(BLE_SVC_SPS_CHR_UUID16_SCAN_REFRESH),
|
||||
.access_cb = ble_svc_sps_access,
|
||||
.flags = BLE_GATT_CHR_F_NOTIFY,
|
||||
.val_handle = &ble_scan_refresh_handle,
|
||||
}, {
|
||||
0, /* No more characteristics in this service */
|
||||
}, }
|
||||
},
|
||||
|
||||
{
|
||||
0, /* No more services. */
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
ble_svc_sps_chr_write(struct os_mbuf *om, uint16_t min_len,
|
||||
uint16_t max_len, void *dst,
|
||||
uint16_t *len)
|
||||
{
|
||||
uint16_t om_len;
|
||||
int rc;
|
||||
|
||||
om_len = OS_MBUF_PKTLEN(om);
|
||||
if (om_len < min_len || om_len > max_len) {
|
||||
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
|
||||
}
|
||||
|
||||
rc = ble_hs_mbuf_to_flat(om, dst, max_len, len);
|
||||
if (rc != 0) {
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ble_svc_sps_scan_refresh() {
|
||||
/* spec allows only value 0 to send */
|
||||
ble_scan_refresh = 0;
|
||||
ble_gatts_chr_updated(ble_scan_refresh_handle);
|
||||
}
|
||||
|
||||
static int
|
||||
ble_svc_sps_access(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
uint16_t uuid = ble_uuid_u16(ctxt->chr->uuid);
|
||||
uint32_t write_val;
|
||||
int rc;
|
||||
|
||||
switch(uuid) {
|
||||
case BLE_SVC_SPS_CHR_UUID16_SCAN_ITVL_WINDOW:
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR);
|
||||
rc = ble_svc_sps_chr_write(ctxt->om, 0, sizeof(ble_scan_itvl) + sizeof(ble_scan_window), &write_val, NULL);
|
||||
if(rc != 0) {
|
||||
ble_scan_itvl = (write_val & 0xffff0000) >> 16;
|
||||
ble_scan_window = (write_val && 0x0000ffff);
|
||||
}
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
case BLE_SVC_SPS_CHR_UUID16_SCAN_REFRESH:
|
||||
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR && conn_handle == BLE_HS_CONN_HANDLE_NONE);
|
||||
rc = os_mbuf_append(ctxt->om, &ble_scan_refresh,
|
||||
sizeof ble_scan_refresh);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
default:
|
||||
assert(0);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the SPS package.
|
||||
*/
|
||||
void
|
||||
ble_svc_sps_init(uint16_t scan_itvl, uint16_t scan_window)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Ensure this function only gets called by sysinit. */
|
||||
SYSINIT_ASSERT_ACTIVE();
|
||||
|
||||
ble_scan_itvl = scan_itvl;
|
||||
ble_scan_window = scan_window;
|
||||
rc = ble_gatts_count_cfg(ble_svc_sps_defs);
|
||||
SYSINIT_PANIC_ASSERT(rc == 0);
|
||||
|
||||
rc = ble_gatts_add_svcs(ble_svc_sps_defs);
|
||||
SYSINIT_PANIC_ASSERT(rc == 0);
|
||||
}
|
||||
@@ -29,6 +29,9 @@
|
||||
#if MYNEWT_VAL(BLE_DYNAMIC_SERVICE)
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
#endif
|
||||
#if MYNEWT_VAL(BLE_SVC_HID_SERVICE)
|
||||
#include "services/hid/ble_svc_hid.h"
|
||||
#endif
|
||||
|
||||
#define BLE_GATTS_INCLUDE_SZ 6
|
||||
#define BLE_GATTS_CHR_MAX_SZ 19
|
||||
@@ -2808,6 +2811,9 @@ ble_gatts_reset(void)
|
||||
/* Note: gatts memory gets freed on next call to ble_gatts_start(). */
|
||||
}
|
||||
|
||||
#if MYNEWT_VAL(BLE_SVC_HID_SERVICE)
|
||||
ble_svc_hid_reset();
|
||||
#endif
|
||||
ble_hs_unlock();
|
||||
|
||||
return rc;
|
||||
|
||||
@@ -952,6 +952,15 @@
|
||||
#define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM (-1)
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_DEFAULT
|
||||
#define MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_DEFAULT (NULL)
|
||||
#endif
|
||||
|
||||
/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */
|
||||
#ifndef MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_READ_PERM
|
||||
#define MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_READ_PERM (-1)
|
||||
#endif
|
||||
|
||||
/*** @apache-mynewt-nimble/nimble/host/services/gap */
|
||||
#ifndef MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE
|
||||
#define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE (0)
|
||||
|
||||
@@ -1522,11 +1522,20 @@
|
||||
#define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_DEFAULT (NULL)
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_DEFAULT
|
||||
#define MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_DEFAULT (NULL)
|
||||
#endif
|
||||
|
||||
/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */
|
||||
#ifndef MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM
|
||||
#define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM (-1)
|
||||
#endif
|
||||
|
||||
/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */
|
||||
#ifndef MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_READ_PERM
|
||||
#define MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_READ_PERM (-1)
|
||||
#endif
|
||||
|
||||
/*** @apache-mynewt-nimble/nimble/host/services/gap */
|
||||
#ifndef MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE
|
||||
#define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE (0)
|
||||
|
||||
@@ -949,11 +949,20 @@
|
||||
#define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_DEFAULT (NULL)
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_DEFAULT
|
||||
#define MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_DEFAULT (NULL)
|
||||
#endif
|
||||
|
||||
/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */
|
||||
#ifndef MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM
|
||||
#define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM (-1)
|
||||
#endif
|
||||
|
||||
/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */
|
||||
#ifndef MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_READ_PERM
|
||||
#define MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_READ_PERM (-1)
|
||||
#endif
|
||||
|
||||
/*** @apache-mynewt-nimble/nimble/host/services/gap */
|
||||
#ifndef MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE
|
||||
#define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE (0)
|
||||
|
||||
@@ -1262,11 +1262,20 @@
|
||||
#define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_DEFAULT (NULL)
|
||||
#endif
|
||||
|
||||
#ifndef MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_DEFAULT
|
||||
#define MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_DEFAULT (NULL)
|
||||
#endif
|
||||
|
||||
/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */
|
||||
#ifndef MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM
|
||||
#define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM (-1)
|
||||
#endif
|
||||
|
||||
/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */
|
||||
#ifndef MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_READ_PERM
|
||||
#define MYNEWT_VAL_BLE_SVC_DIS_PNP_ID_READ_PERM (-1)
|
||||
#endif
|
||||
|
||||
/*** @apache-mynewt-nimble/nimble/host/services/gap */
|
||||
#ifndef MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE
|
||||
#define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE (0)
|
||||
|
||||
Reference in New Issue
Block a user