add more nimble example
1. make heart rate sensor example really work using nRF Toolbox HRM 2. add master device scan example 3. add gatt server example(seems not working)
This commit is contained in:
40
examples/nimble_gatt/blehr_sens.h
Normal file
40
examples/nimble_gatt/blehr_sens.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef H_BLEHR_SENSOR_
|
||||
#define H_BLEHR_SENSOR_
|
||||
|
||||
#include "nimble/ble.h"
|
||||
#include "modlog/modlog.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define GATT_DEVICE_INFO_UUID 0x180A
|
||||
#define GATT_MANUFACTURER_NAME_UUID 0x2A29
|
||||
#define GATT_MODEL_NUMBER_UUID 0x2A24
|
||||
|
||||
int gatt_svr_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
280
examples/nimble_gatt/gatt_svr.c
Normal file
280
examples/nimble_gatt/gatt_svr.c
Normal file
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/ble_uuid.h"
|
||||
#include "blehr_sens.h"
|
||||
|
||||
#include "services/dis/ble_svc_dis.h"
|
||||
#include "services/bas/ble_svc_bas.h"
|
||||
|
||||
/* UUID = 1bce38b3-d137-48ff-a13e-033e14c7a335 */
|
||||
static const ble_uuid128_t gatt_svr_svc_rw_demo_uuid
|
||||
= BLE_UUID128_INIT(0x35, 0xa3, 0xc7, 0x14, 0x3e, 0x03, 0x3e, 0xa1, 0xff,
|
||||
0x48, 0x37, 0xd1, 0xb3, 0x38, 0xce, 0x1b);
|
||||
|
||||
/* UUID = 35f28386-3070-4f3b-ba38-27507e991762 */
|
||||
static const ble_uuid128_t gatt_svr_chr_rw_demo_write_uuid
|
||||
= BLE_UUID128_INIT(0x62, 0x17, 0x99, 0x7e, 0x50, 0x27, 0x38, 0xba, 0x3b,
|
||||
0x4f, 0x70, 0x30, 0x86, 0x83, 0xf2, 0x35);
|
||||
|
||||
/* UUID = ccdd113f-40d5-4d68-86ac-a728dd82f4aa */
|
||||
static const ble_uuid128_t gatt_svr_chr_rw_demo_readonly_uuid
|
||||
= BLE_UUID128_INIT(0xaa, 0xf4, 0x82, 0xdd, 0x28, 0xa7, 0xac, 0x86, 0x68,
|
||||
0x4d, 0xd5, 0x40, 0x3f, 0x11, 0xdd, 0xcc);
|
||||
|
||||
#define REPLY_BUFFER_SIZE 100
|
||||
static char reply[REPLY_BUFFER_SIZE];
|
||||
|
||||
static char rm_demo_write_data[64] = "This characteristic is readable and writeable!";
|
||||
|
||||
static int gatt_svr_chr_access_device_info_manufacturer(
|
||||
uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
static int gatt_svr_chr_access_device_info_model(
|
||||
uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
static int gatt_svr_chr_access_rw_demo(
|
||||
uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg);
|
||||
|
||||
/* define several bluetooth services for our device */
|
||||
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
|
||||
/*
|
||||
* access_cb defines a callback for read and write access events on
|
||||
* given characteristics
|
||||
*/
|
||||
{
|
||||
/* Service: Device Information */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_DEVICE_INFO_UUID),
|
||||
.characteristics = (struct ble_gatt_chr_def[]) { {
|
||||
/* Characteristic: * Manufacturer name */
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_MANUFACTURER_NAME_UUID),
|
||||
.access_cb = gatt_svr_chr_access_device_info_manufacturer,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
}, {
|
||||
/* Characteristic: Model number string */
|
||||
.uuid = BLE_UUID16_DECLARE(GATT_MODEL_NUMBER_UUID),
|
||||
.access_cb = gatt_svr_chr_access_device_info_model,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
}, {
|
||||
0, /* No more characteristics in this service */
|
||||
}, }
|
||||
},
|
||||
{
|
||||
/* Service: Read/Write Demo */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = (ble_uuid_t*) &gatt_svr_svc_rw_demo_uuid.u,
|
||||
.characteristics = (struct ble_gatt_chr_def[]) { {
|
||||
/* Characteristic: Read/Write Demo write */
|
||||
.uuid = (ble_uuid_t*) &gatt_svr_chr_rw_demo_write_uuid.u,
|
||||
.access_cb = gatt_svr_chr_access_rw_demo,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
|
||||
}, {
|
||||
/* Characteristic: Read/Write Demo read only */
|
||||
.uuid = (ble_uuid_t*) &gatt_svr_chr_rw_demo_readonly_uuid.u,
|
||||
.access_cb = gatt_svr_chr_access_rw_demo,
|
||||
.flags = BLE_GATT_CHR_F_READ,
|
||||
}, {
|
||||
0, /* No more characteristics in this service */
|
||||
}, }
|
||||
},
|
||||
{
|
||||
0, /* No more services */
|
||||
},
|
||||
};
|
||||
|
||||
static int gatt_svr_chr_access_device_info_manufacturer(
|
||||
uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
printf("service 'device info: manufacturer' callback triggered\n");
|
||||
|
||||
snprintf(reply, REPLY_BUFFER_SIZE, "This is TencentOS tiny\n");
|
||||
printf("reply: %s\n", reply);
|
||||
|
||||
int rc = os_mbuf_append(ctxt->om, reply, strlen(reply));
|
||||
|
||||
printf("\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int gatt_svr_chr_access_device_info_model(
|
||||
uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
printf("service 'device info: model' callback triggered\n");
|
||||
|
||||
snprintf(reply, REPLY_BUFFER_SIZE, "running TencentOS tiny on nordic ble board");
|
||||
printf("reply: %s\n", reply);
|
||||
|
||||
int rc = os_mbuf_append(ctxt->om, reply, strlen(reply));
|
||||
|
||||
printf("\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int gatt_svr_chr_access_rw_demo(
|
||||
uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
printf("service 'rw demo' callback triggered\n");
|
||||
|
||||
int rc = 0;
|
||||
|
||||
ble_uuid_t* write_uuid = (ble_uuid_t*) &gatt_svr_chr_rw_demo_write_uuid.u;
|
||||
ble_uuid_t* readonly_uuid = (ble_uuid_t*) &gatt_svr_chr_rw_demo_readonly_uuid.u;
|
||||
|
||||
if (ble_uuid_cmp(ctxt->chr->uuid, write_uuid) == 0) {
|
||||
|
||||
printf("access to characteristic 'rw demo (write)'\n");
|
||||
|
||||
switch (ctxt->op) {
|
||||
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR:
|
||||
printf("read from characteristic\n");
|
||||
printf("current value of rm_demo_write_data: '%s'\n",
|
||||
rm_demo_write_data);
|
||||
|
||||
/* send given data to the client */
|
||||
rc = os_mbuf_append(ctxt->om, &rm_demo_write_data, strlen(rm_demo_write_data));
|
||||
|
||||
break;
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR:
|
||||
printf("write to characteristic\n");
|
||||
|
||||
printf("old value of rm_demo_write_data: '%s'\n", rm_demo_write_data);
|
||||
|
||||
uint16_t om_len;
|
||||
om_len = OS_MBUF_PKTLEN(ctxt->om);
|
||||
|
||||
/* read sent data */
|
||||
rc = ble_hs_mbuf_to_flat(ctxt->om, &rm_demo_write_data,
|
||||
sizeof rm_demo_write_data, &om_len);
|
||||
/* we need to null-terminate the received string */
|
||||
rm_demo_write_data[om_len] = '\0';
|
||||
|
||||
printf("new value of rm_demo_write_data: '%s'\n",
|
||||
rm_demo_write_data);
|
||||
|
||||
break;
|
||||
|
||||
case BLE_GATT_ACCESS_OP_READ_DSC:
|
||||
printf("read from descriptor\n");
|
||||
break;
|
||||
|
||||
case BLE_GATT_ACCESS_OP_WRITE_DSC:
|
||||
printf("write to descriptor\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("unhandled operation!\n");
|
||||
rc = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
else if (ble_uuid_cmp(ctxt->chr->uuid, readonly_uuid) == 0) {
|
||||
|
||||
printf("access to characteristic 'rw demo (read-only)'\n");
|
||||
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
char random_digit;
|
||||
/* get random char between '0' and '9' */
|
||||
random_digit = 48 + (rand() % 10);
|
||||
|
||||
snprintf(reply, REPLY_BUFFER_SIZE, "new random number: %c", random_digit);
|
||||
printf("reply: %s\n", reply);
|
||||
|
||||
rc = os_mbuf_append(ctxt->om, &reply, strlen(reply));
|
||||
|
||||
printf("\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("unhandled uuid!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
|
||||
{
|
||||
char buf[BLE_UUID_STR_LEN];
|
||||
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_REGISTER_OP_SVC:
|
||||
MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
|
||||
ctxt->svc.handle);
|
||||
break;
|
||||
|
||||
case BLE_GATT_REGISTER_OP_CHR:
|
||||
MODLOG_DFLT(DEBUG, "registering characteristic %s with "
|
||||
"def_handle=%d val_handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
|
||||
ctxt->chr.def_handle,
|
||||
ctxt->chr.val_handle);
|
||||
break;
|
||||
|
||||
case BLE_GATT_REGISTER_OP_DSC:
|
||||
MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
|
||||
ctxt->dsc.handle);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
gatt_svr_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ble_gatts_count_cfg(gatt_svr_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = ble_gatts_add_svcs(gatt_svr_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
222
examples/nimble_gatt/main.c
Normal file
222
examples/nimble_gatt/main.c
Normal file
@@ -0,0 +1,222 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nimble/nimble_port_tencentos_tiny.h"
|
||||
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "host/ble_gatt.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
|
||||
#include "blehr_sens.h"
|
||||
|
||||
static const char device_name[] = "Nimble Gatt";
|
||||
|
||||
static uint8_t ble_addr_type;
|
||||
|
||||
static void start_advertise(void);
|
||||
|
||||
static int blegatt_gap_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_CONNECT:
|
||||
if (event->connect.status) {
|
||||
start_advertise();
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
start_advertise();
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void start_advertise(void)
|
||||
{
|
||||
int rc;
|
||||
struct ble_gap_adv_params advp;
|
||||
|
||||
memset(&advp, 0, sizeof advp);
|
||||
advp.conn_mode = BLE_GAP_CONN_MODE_UND;
|
||||
advp.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||
rc = ble_gap_adv_start(ble_addr_type, NULL, BLE_HS_FOREVER,
|
||||
&advp, blegatt_gap_event, NULL);
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
put_ad(uint8_t ad_type, uint8_t ad_len, const void *ad, uint8_t *buf,
|
||||
uint8_t *len)
|
||||
{
|
||||
buf[(*len)++] = ad_len + 1;
|
||||
buf[(*len)++] = ad_type;
|
||||
|
||||
memcpy(&buf[*len], ad, ad_len);
|
||||
|
||||
*len += ad_len;
|
||||
}
|
||||
|
||||
static void
|
||||
update_ad(void)
|
||||
{
|
||||
uint8_t ad[BLE_HS_ADV_MAX_SZ];
|
||||
uint8_t ad_len = 0;
|
||||
uint8_t ad_flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
|
||||
put_ad(BLE_HS_ADV_TYPE_FLAGS, 1, &ad_flags, ad, &ad_len);
|
||||
put_ad(BLE_HS_ADV_TYPE_COMP_NAME, sizeof(device_name), device_name, ad, &ad_len);
|
||||
|
||||
ble_gap_adv_set_data(ad, ad_len);
|
||||
}
|
||||
|
||||
#if 1
|
||||
/* UUID = 1bce38b3-d137-48ff-a13e-033e14c7a335 */
|
||||
static const ble_uuid128_t gatt_svr_svc_rw_demo_uuid
|
||||
= BLE_UUID128_INIT(0x35, 0xa3, 0xc7, 0x14, 0x3e, 0x03, 0x3e, 0xa1, 0xff,
|
||||
0x48, 0x37, 0xd1, 0xb3, 0x38, 0xce, 0x1b);
|
||||
|
||||
static ble_uuid128_t svc_adv_uuids_128[] =
|
||||
{
|
||||
{ BLE_UUID_TYPE_128, { 0x35, 0xa3, 0xc7, 0x14, 0x3e, 0x03, 0x3e, 0xa1, 0xff,
|
||||
0x48, 0x37, 0xd1, 0xb3, 0x38, 0xce, 0x1b } },
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static ble_uuid16_t svc_adv_uuids[] =
|
||||
{
|
||||
{ BLE_UUID_TYPE_16, GATT_DEVICE_INFO_UUID },
|
||||
};
|
||||
|
||||
void ble_set_fields(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 *)device_name;
|
||||
fields.name_len = strlen(device_name);
|
||||
fields.name_is_complete = 1;
|
||||
|
||||
/*** 0x02,0x03 - 16-bit service class UUIDs. */
|
||||
#if 1
|
||||
fields.num_uuids16 = 1;
|
||||
fields.uuids16 = svc_adv_uuids;
|
||||
fields.uuids16_is_complete = 1;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
fields.num_uuids128 = 1;
|
||||
fields.uuids128 = svc_adv_uuids_128;
|
||||
fields.uuids128_is_complete = 1;
|
||||
#endif
|
||||
|
||||
rc = ble_gap_adv_set_fields(&fields);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/*** 0xff - Manufacturer specific data. */
|
||||
memset(&fields, 0, sizeof(fields));
|
||||
fields.mfg_data = (uint8_t*)"GZH:Bluetooth-BLE,177341833";
|
||||
fields.mfg_data_len = 27;
|
||||
|
||||
rc = ble_gap_adv_rsp_set_fields(&fields);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int ble_boot(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
extern void nimble_port_run(void);
|
||||
nimble_port_tencentos_tiny_init(nimble_port_run);
|
||||
|
||||
/* make sure synchronization of host and controller is done */
|
||||
while (!ble_hs_synced()) {
|
||||
;
|
||||
}
|
||||
|
||||
rc = ble_hs_util_ensure_addr(0);
|
||||
assert(rc == 0);
|
||||
rc = ble_hs_id_infer_auto(0, &ble_addr_type);
|
||||
assert(rc == 0);
|
||||
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
|
||||
/* verify and add our custom services */
|
||||
rc = gatt_svr_init();
|
||||
assert(rc == 0);
|
||||
|
||||
/* set the device name */
|
||||
rc = ble_svc_gap_device_name_set(device_name);
|
||||
assert(rc == 0);
|
||||
|
||||
/* reload the GATT server to link our added services */
|
||||
ble_gatts_start();
|
||||
|
||||
update_ad();
|
||||
|
||||
ble_set_fields();
|
||||
start_advertise();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
k_task_t ble_boot_task;
|
||||
k_stack_t ble_boot_stack[2048];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
board_init();
|
||||
|
||||
/* Initialize OS */
|
||||
tos_knl_init();
|
||||
|
||||
nimble_port_init();
|
||||
|
||||
/*
|
||||
in this case, ble_boot_task's priority must lower than MYNEWT_VAL_BLE_HOST_TASK_PRIORITY && MYNEWT_VAL_BLE_LL_TASK_PRIORITY,
|
||||
numerically bigger
|
||||
to give the host and ll task a chance to run first just after the nimble_port_tencentos_tiny_init.
|
||||
*/
|
||||
tos_task_create(&ble_boot_task, "boot", ble_boot, NULL,
|
||||
6,
|
||||
ble_boot_stack, sizeof(ble_boot_stack),
|
||||
0);
|
||||
tos_knl_start();
|
||||
}
|
||||
|
Reference in New Issue
Block a user