From 7f2e121158d431034ad4d50465cb7c6f40f3f0da Mon Sep 17 00:00:00 2001 From: Max Kriegleder Date: Thu, 31 Oct 2024 00:00:28 +0100 Subject: [PATCH 1/3] examples: add blecent and bleprph similar to mynewt-nimble apps These example apps create a BLE central and peripheral based on mynewt-nimBLE and work in companion. The apps are mostly based on their equivalents, which can be found at https://github.com/apache/mynewt-nimble/tree/master/apps --- examples/nimble_blecent/CMakeLists.txt | 26 + examples/nimble_blecent/Kconfig | 30 + examples/nimble_blecent/Make.defs | 23 + examples/nimble_blecent/Makefile | 36 + examples/nimble_blecent/blecent.h | 112 +++ examples/nimble_blecent/misc.c | 210 +++++ examples/nimble_blecent/nimble_blecent_main.c | 628 ++++++++++++++ examples/nimble_blecent/peer.c | 808 ++++++++++++++++++ examples/nimble_bleprph/CMakeLists.txt | 26 + examples/nimble_bleprph/Kconfig | 30 + examples/nimble_bleprph/Make.defs | 23 + examples/nimble_bleprph/Makefile | 36 + examples/nimble_bleprph/bleprph.h | 53 ++ examples/nimble_bleprph/gatt_svr.c | 210 +++++ examples/nimble_bleprph/misc.c | 45 + examples/nimble_bleprph/nimble_bleprph_main.c | 421 +++++++++ 16 files changed, 2717 insertions(+) create mode 100644 examples/nimble_blecent/CMakeLists.txt create mode 100644 examples/nimble_blecent/Kconfig create mode 100644 examples/nimble_blecent/Make.defs create mode 100644 examples/nimble_blecent/Makefile create mode 100644 examples/nimble_blecent/blecent.h create mode 100644 examples/nimble_blecent/misc.c create mode 100644 examples/nimble_blecent/nimble_blecent_main.c create mode 100644 examples/nimble_blecent/peer.c create mode 100644 examples/nimble_bleprph/CMakeLists.txt create mode 100644 examples/nimble_bleprph/Kconfig create mode 100644 examples/nimble_bleprph/Make.defs create mode 100644 examples/nimble_bleprph/Makefile create mode 100644 examples/nimble_bleprph/bleprph.h create mode 100644 examples/nimble_bleprph/gatt_svr.c create mode 100644 examples/nimble_bleprph/misc.c create mode 100644 examples/nimble_bleprph/nimble_bleprph_main.c diff --git a/examples/nimble_blecent/CMakeLists.txt b/examples/nimble_blecent/CMakeLists.txt new file mode 100644 index 00000000000..c4c803c1b72 --- /dev/null +++ b/examples/nimble_blecent/CMakeLists.txt @@ -0,0 +1,26 @@ +# ############################################################################## +# apps/examples/nimble_blecent/CMakeLists.txt +# +# 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(CONFIG_EXAMPLES_NIMBLE_BLECENT) + nuttx_add_application( + NAME nimble + SRCS ${CMAKE_CURRENT_LIST_DIR}/nimble_blecent_main.c ${CMAKE_CURRENT_LIST_DIR}/misc.c ${CMAKE_CURRENT_LIST_DIR}/peer.c + DEPENDS nimble) +endif() diff --git a/examples/nimble_blecent/Kconfig b/examples/nimble_blecent/Kconfig new file mode 100644 index 00000000000..edaa65aa50e --- /dev/null +++ b/examples/nimble_blecent/Kconfig @@ -0,0 +1,30 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config EXAMPLES_NIMBLE_BLECENT + tristate "NimBLE peripheral" + default n + ---help--- + Enable the nimble peripheral + +if EXAMPLES_NIMBLE_BLECENT + +config EXAMPLES_NIMBLE_BLECENT_PROGNAME + string "Program name" + default "nimble" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config EXAMPLES_NIMBLE_BLECENT_PRIORITY + int "NimBLE task priority" + default 100 + +config EXAMPLES_NIMBLE_BLECENT_STACKSIZE + int "NimBLE stack size" + default DEFAULT_TASK_STACKSIZE + +endif # EXAMPLES_NIMBLE_BLECENT + diff --git a/examples/nimble_blecent/Make.defs b/examples/nimble_blecent/Make.defs new file mode 100644 index 00000000000..fb8b4456538 --- /dev/null +++ b/examples/nimble_blecent/Make.defs @@ -0,0 +1,23 @@ +############################################################################ +# apps/examples/nimble_blecent/Make.defs +# +# 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. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_NIMBLE_BLECENT),) +CONFIGURED_APPS += $(APPDIR)/examples/nimble +endif diff --git a/examples/nimble_blecent/Makefile b/examples/nimble_blecent/Makefile new file mode 100644 index 00000000000..964e7425c42 --- /dev/null +++ b/examples/nimble_blecent/Makefile @@ -0,0 +1,36 @@ +############################################################################ +# apps/examples/nimble_blecent/Makefile +# +# 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 $(APPDIR)/Make.defs + +# NimBLE built-in application info + +PROGNAME = $(CONFIG_EXAMPLES_NIMBLE_BLECENT_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_NIMBLE_BLECENT_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_NIMBLE_BLECENT_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_NIMBLE_BLECENT) + +# NimBLE Example + +MAINSRC = nimble_BLECENT_main.c + +include $(APPDIR)/wireless/bluetooth/nimble/Makefile.nimble + +include $(APPDIR)/Application.mk diff --git a/examples/nimble_blecent/blecent.h b/examples/nimble_blecent/blecent.h new file mode 100644 index 00000000000..3da21592751 --- /dev/null +++ b/examples/nimble_blecent/blecent.h @@ -0,0 +1,112 @@ +/**************************************************************************** + * apps/examples/nimble_blecent/blecent.h + * + * 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_BLECENT_ +#define H_BLECENT_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ble_hs_adv_fields; +struct ble_gap_conn_desc; +struct ble_hs_cfg; +union ble_store_value; +union ble_store_key; + +#define BLECENT_SVC_ALERT_UUID 0x1811 +#define BLECENT_CHR_SUP_NEW_ALERT_CAT_UUID 0x2A47 +#define BLECENT_CHR_NEW_ALERT 0x2A46 +#define BLECENT_CHR_SUP_UNR_ALERT_CAT_UUID 0x2A48 +#define BLECENT_CHR_UNR_ALERT_STAT_UUID 0x2A45 +#define BLECENT_CHR_ALERT_NOT_CTRL_PT 0x2A44 + +/** Misc. */ +void print_bytes(const uint8_t *bytes, int len); +void print_mbuf(const struct os_mbuf *om); +char *addr_str(const void *addr); +void print_uuid(const ble_uuid_t *uuid); +void print_conn_desc(const struct ble_gap_conn_desc *desc); +void print_adv_fields(const struct ble_hs_adv_fields *fields); + +/** Peer. */ +struct peer_dsc { + SLIST_ENTRY(peer_dsc) next; + struct ble_gatt_dsc dsc; +}; +SLIST_HEAD(peer_dsc_list, peer_dsc); + +struct peer_chr { + SLIST_ENTRY(peer_chr) next; + struct ble_gatt_chr chr; + + struct peer_dsc_list dscs; +}; +SLIST_HEAD(peer_chr_list, peer_chr); + +struct peer_svc { + SLIST_ENTRY(peer_svc) next; + struct ble_gatt_svc svc; + + struct peer_chr_list chrs; +}; +SLIST_HEAD(peer_svc_list, peer_svc); + +struct peer; +typedef void peer_disc_fn(const struct peer *peer, int status, void *arg); + +struct peer { + SLIST_ENTRY(peer) next; + + uint16_t conn_handle; + + /** List of discovered GATT services. */ + struct peer_svc_list svcs; + + /** Keeps track of where we are in the service discovery process. */ + uint16_t disc_prev_chr_val; + struct peer_svc *cur_svc; + + /** Callback that gets executed when service discovery completes. */ + peer_disc_fn *disc_cb; + void *disc_cb_arg; +}; + +int peer_disc_all(uint16_t conn_handle, peer_disc_fn *disc_cb, + void *disc_cb_arg); +const struct peer_dsc * +peer_dsc_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid, + const ble_uuid_t *chr_uuid, const ble_uuid_t *dsc_uuid); +const struct peer_chr * +peer_chr_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid, + const ble_uuid_t *chr_uuid); +const struct peer_svc * +peer_svc_find_uuid(const struct peer *peer, const ble_uuid_t *uuid); +int peer_delete(uint16_t conn_handle); +int peer_add(uint16_t conn_handle); +int peer_init(int max_peers, int max_svcs, int max_chrs, int max_dscs); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/nimble_blecent/misc.c b/examples/nimble_blecent/misc.c new file mode 100644 index 00000000000..4180d7049ba --- /dev/null +++ b/examples/nimble_blecent/misc.c @@ -0,0 +1,210 @@ +/**************************************************************************** + * apps/examples/nimble_blecent/misc.c + * + * 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 +#include +#include +#include "host/ble_hs.h" +#include "host/ble_uuid.h" +#include "blecent.h" + +/** + * Utility function to log an array of bytes. + */ +void +print_bytes(const uint8_t *bytes, int len) +{ + int i; + + for (i = 0; i < len; i++) { + printf("%s0x%02x", i != 0 ? ":" : "", bytes[i]); + } +} + +void +print_mbuf(const struct os_mbuf *om) +{ + int colon; + + colon = 0; + while (om != NULL) { + if (colon) { + printf(":"); + } else { + colon = 1; + } + print_bytes(om->om_data, om->om_len); + om = SLIST_NEXT(om, om_next); + } +} + +char * +addr_str(const void *addr) +{ + static char buf[6 * 2 + 5 + 1]; + const uint8_t *u8p; + + u8p = addr; + sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", + u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]); + + return buf; +} + +void +print_uuid(const ble_uuid_t *uuid) +{ + char buf[BLE_UUID_STR_LEN]; + + printf("%s", ble_uuid_to_str(uuid, buf)); +} + +/** + * Logs information about a connection to the console. + */ +void +print_conn_desc(const struct ble_gap_conn_desc *desc) +{ + printf("handle=%d our_ota_addr_type=%d our_ota_addr=%s ", + desc->conn_handle, desc->our_ota_addr.type, + addr_str(desc->our_ota_addr.val)); + printf("our_id_addr_type=%d our_id_addr=%s ", + desc->our_id_addr.type, addr_str(desc->our_id_addr.val)); + printf("peer_ota_addr_type=%d peer_ota_addr=%s ", + desc->peer_ota_addr.type, addr_str(desc->peer_ota_addr.val)); + printf("peer_id_addr_type=%d peer_id_addr=%s ", + desc->peer_id_addr.type, addr_str(desc->peer_id_addr.val)); + printf("conn_itvl=%d conn_latency=%d supervision_timeout=%d " + "encrypted=%d authenticated=%d bonded=%d", + desc->conn_itvl, desc->conn_latency, + desc->supervision_timeout, + desc->sec_state.encrypted, + desc->sec_state.authenticated, + desc->sec_state.bonded); +} + + +void +print_adv_fields(const struct ble_hs_adv_fields *fields) +{ + char s[BLE_HS_ADV_MAX_SZ]; + const uint8_t *u8p; + int i; + + if (fields->flags != 0) { + printf(" flags=0x%02x\n", fields->flags); + } + + if (fields->uuids16 != NULL) { + printf(" uuids16(%scomplete)=", + fields->uuids16_is_complete ? "" : "in"); + for (i = 0; i < fields->num_uuids16; i++) { + print_uuid(&fields->uuids16[i].u); + printf(" "); + } + printf("\n"); + } + + if (fields->uuids32 != NULL) { + printf(" uuids32(%scomplete)=", + fields->uuids32_is_complete ? "" : "in"); + for (i = 0; i < fields->num_uuids32; i++) { + print_uuid(&fields->uuids32[i].u); + printf(" "); + } + printf("\n"); + } + + if (fields->uuids128 != NULL) { + printf(" uuids128(%scomplete)=", + fields->uuids128_is_complete ? "" : "in"); + for (i = 0; i < fields->num_uuids128; i++) { + print_uuid(&fields->uuids128[i].u); + printf(" "); + } + printf("\n"); + } + + if (fields->name != NULL) { + assert(fields->name_len < sizeof s - 1); + memcpy(s, fields->name, fields->name_len); + s[fields->name_len] = '\0'; + printf(" name(%scomplete)=%s\n", + fields->name_is_complete ? "" : "in", s); + } + + if (fields->tx_pwr_lvl_is_present) { + printf(" tx_pwr_lvl=%d\n", fields->tx_pwr_lvl); + } + + if (fields->slave_itvl_range != NULL) { + printf(" slave_itvl_range="); + print_bytes(fields->slave_itvl_range, BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN); + printf("\n"); + } + + if (fields->svc_data_uuid16 != NULL) { + printf(" svc_data_uuid16="); + print_bytes(fields->svc_data_uuid16, fields->svc_data_uuid16_len); + printf("\n"); + } + + if (fields->public_tgt_addr != NULL) { + printf(" public_tgt_addr="); + u8p = fields->public_tgt_addr; + for (i = 0; i < fields->num_public_tgt_addrs; i++) { + printf("public_tgt_addr=%s ", addr_str(u8p)); + u8p += BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN; + } + printf("\n"); + } + + if (fields->appearance_is_present) { + printf(" appearance=0x%04x\n", fields->appearance); + } + + if (fields->adv_itvl_is_present) { + printf(" adv_itvl=0x%04x\n", fields->adv_itvl); + } + + if (fields->svc_data_uuid32 != NULL) { + printf(" svc_data_uuid32="); + print_bytes(fields->svc_data_uuid32, fields->svc_data_uuid32_len); + printf("\n"); + } + + if (fields->svc_data_uuid128 != NULL) { + printf(" svc_data_uuid128="); + print_bytes(fields->svc_data_uuid128, fields->svc_data_uuid128_len); + printf("\n"); + } + + if (fields->uri != NULL) { + printf(" uri="); + print_bytes(fields->uri, fields->uri_len); + printf("\n"); + } + + if (fields->mfg_data != NULL) { + printf(" mfg_data="); + print_bytes(fields->mfg_data, fields->mfg_data_len); + printf("\n"); + } +} diff --git a/examples/nimble_blecent/nimble_blecent_main.c b/examples/nimble_blecent/nimble_blecent_main.c new file mode 100644 index 00000000000..161021b03cc --- /dev/null +++ b/examples/nimble_blecent/nimble_blecent_main.c @@ -0,0 +1,628 @@ +/**************************************************************************** + * apps/examples/nimble_blecent/nimble_blecent_main.c + * + * 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 +#include + +/* BLE */ +#include "nimble/ble.h" +#include "nimble/nimble_port.h" +#include "host/ble_hs.h" +#include "host/util/util.h" + +/* Mandatory services. */ +#include "services/gap/ble_svc_gap.h" +#include "services/gatt/ble_svc_gatt.h" +#include "services/bas/ble_svc_bas.h" + +/* Application-specified header. */ +#include "blecent.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BLECENT_BAS_UUID 0x180f +#define BLECENT_CHR_BAS_BL_UUID 0x2a19 + +/* Not used now */ + +#define TASK_DEFAULT_PRIORITY CONFIG_EXAMPLES_NIMBLE_BLECENT_PRIORITY +#define TASK_DEFAULT_STACK NULL +#define TASK_DEFAULT_STACK_SIZE 0 + +/**************************************************************************** + * External Functions Prototypes + ****************************************************************************/ + +void ble_hci_sock_ack_handler(FAR void *param); +//void ble_hci_sock_init(void); +void ble_hci_sock_set_device(int dev); + +/**************************************************************************** + * Private Functions Prototypes + ****************************************************************************/ + +static int blecent_gap_event(struct ble_gap_event *event, void *arg); + +/** + * Application callback. Called when the read of the ANS Supported New Alert + * Category characteristic has completed. + */ +static int +blecent_on_read(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + printf("Read complete; status=%d conn_handle=%d", error->status, + conn_handle); + if (error->status == 0) { + printf(" attr_handle=%d value=", attr->handle); + print_mbuf(attr->om); + } + printf("\n"); + + return 0; +} + +/** + * Application callback. Called when the write to the ANS Alert Notification + * Control Point characteristic has completed. + */ +static int +blecent_on_write(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + printf("Write complete; status=%d conn_handle=%d attr_handle=%d\n", + error->status, conn_handle, attr->handle); + + return 0; +} + +/** + * Application callback. Called when the attempt to subscribe to notifications + * for the ANS Unread Alert Status characteristic has completed. + */ +static int +blecent_on_subscribe(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + printf("Subscribe complete; status=%d conn_handle=%d " + "attr_handle=%d\n", + error->status, conn_handle, attr->handle); + + return 0; +} + +/** + * Performs three concurrent GATT operations against the specified peer: + * 1. Reads the ANS Supported New Alert Category characteristic. + * 2. Writes the ANS Alert Notification Control Point characteristic. + * 3. Subscribes to notifications for the ANS Unread Alert Status + * characteristic. + * + * If the peer does not support a required service, characteristic, or + * descriptor, then the peer lied when it claimed support for the alert + * notification service! When this happens, or if a GATT procedure fails, + * this function immediately terminates the connection. + */ +static void +blecent_read_write_subscribe(const struct peer *peer) +{ + const struct peer_chr *chr; + const struct peer_dsc *dsc; + uint8_t value[2]; + int rc; + + /* Read the supported-new-alert-category characteristic. */ + chr = peer_chr_find_uuid(peer, + BLE_UUID16_DECLARE(BLECENT_SVC_ALERT_UUID), + BLE_UUID16_DECLARE(BLECENT_CHR_SUP_NEW_ALERT_CAT_UUID)); + if (chr == NULL) { + printf("Error: Peer doesn't support the Supported New " + "Alert Category characteristic\n"); + goto err; + } + + rc = ble_gattc_read(peer->conn_handle, chr->chr.val_handle, + blecent_on_read, NULL); + if (rc != 0) { + printf("Error: Failed to read characteristic; rc=%d\n", + rc); + goto err; + } + + /* Write two bytes (99, 100) to the alert-notification-control-point + * characteristic. + */ + chr = peer_chr_find_uuid(peer, + BLE_UUID16_DECLARE(BLECENT_SVC_ALERT_UUID), + BLE_UUID16_DECLARE(BLECENT_CHR_ALERT_NOT_CTRL_PT)); + if (chr == NULL) { + printf("Error: Peer doesn't support the Alert " + "Notification Control Point characteristic\n"); + goto err; + } + + value[0] = 99; + value[1] = 100; + rc = ble_gattc_write_flat(peer->conn_handle, chr->chr.val_handle, + value, sizeof value, blecent_on_write, NULL); + if (rc != 0) { + printf("Error: Failed to write characteristic; rc=%d\n", + rc); + } + + /* Subscribe to notifications for the Battery Level characteristic. + * A central enables notifications by writing two bytes (1, 0) to the + * characteristic's client-characteristic-configuration-descriptor (CCCD). + */ + dsc = peer_dsc_find_uuid(peer, + BLE_UUID16_DECLARE(BLE_SVC_BAS_UUID16), + BLE_UUID16_DECLARE(BLE_SVC_BAS_CHR_UUID16_BATTERY_LEVEL), + BLE_UUID16_DECLARE(BLE_GATT_DSC_CLT_CFG_UUID16)); + if (dsc == NULL) { + printf("Error: Peer lacks a CCCD for the Battery Level characteristic\n"); + goto err; + } + + value[0] = 1; + value[1] = 0; + rc = ble_gattc_write_flat(peer->conn_handle, dsc->dsc.handle, + value, sizeof value, blecent_on_subscribe, NULL); + if (rc != 0) { + printf("Error: Failed to subscribe to characteristic; " + "rc=%d\n", rc); + goto err; + } + + return; + +err: + /* Terminate the connection. */ + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); +} + +/** + * Called when service discovery of the specified peer has completed. + */ +static void +blecent_on_disc_complete(const struct peer *peer, int status, void *arg) +{ + + if (status != 0) { + /* Service discovery failed. Terminate the connection. */ + printf("Error: Service discovery failed; status=%d " + "conn_handle=%d\n", status, peer->conn_handle); + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return; + } + + /* Service discovery has completed successfully. Now we have a complete + * list of services, characteristics, and descriptors that the peer + * supports. + */ + printf("Service discovery complete; status=%d " + "conn_handle=%d\n", status, peer->conn_handle); + + /* Now perform three concurrent GATT procedures against the peer: read, + * write, and subscribe to notifications. + */ + blecent_read_write_subscribe(peer); +} + +/** + * Initiates the GAP general discovery procedure. + */ +static void +blecent_scan(void) +{ + uint8_t own_addr_type; + struct ble_gap_disc_params disc_params; + int rc; + + /* Figure out address to use while advertising (no privacy for now) */ + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + printf("error determining address type; rc=%d\n", rc); + return; + } + + /* Tell the controller to filter duplicates; we don't want to process + * repeated advertisements from the same device. + */ + disc_params.filter_duplicates = 1; + + /** + * Perform a passive scan. I.e., don't send follow-up scan requests to + * each advertiser. + */ + disc_params.passive = 1; + + /* Use defaults for the rest of the parameters. */ + disc_params.itvl = 0; + disc_params.window = 0; + disc_params.filter_policy = 0; + disc_params.limited = 0; + + rc = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &disc_params, + blecent_gap_event, NULL); + if (rc != 0) { + printf("Error initiating GAP discovery procedure; rc=%d\n", + rc); + } +} + +/** + * Indicates whether we should tre to connect to the sender of the specified + * advertisement. The function returns a positive result if the device + * advertises connectability and support for the Alert Notification service. + */ +static int +blecent_should_connect(const struct ble_gap_disc_desc *disc) +{ + struct ble_hs_adv_fields fields; + int rc; + int i; + + /* The device has to be advertising connectability. */ + if (disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && + disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) { + + return 0; + } + + rc = ble_hs_adv_parse_fields(&fields, disc->data, disc->length_data); + if (rc != 0) { + return 0; + } + + /* The device has to advertise support for the Alert Notification + * service (0x1811). + */ + for (i = 0; i < fields.num_uuids16; i++) { + if (ble_uuid_u16(&fields.uuids16[i].u) == BLECENT_SVC_ALERT_UUID) { + return 1; + } + } + + return 0; +} + +/** + * Connects to the sender of the specified advertisement of it looks + * interesting. A device is "interesting" if it advertises connectability and + * support for the Alert Notification service. + */ +static void +blecent_connect_if_interesting(const struct ble_gap_disc_desc *disc) +{ + uint8_t own_addr_type; + int rc; + + /* Don't do anything if we don't care about this advertiser. */ + if (!blecent_should_connect(disc)) { + return; + } + + /* Scanning must be stopped before a connection can be initiated. */ + rc = ble_gap_disc_cancel(); + if (rc != 0) { + printf("Failed to cancel scan; rc=%d\n", rc); + return; + } + + /* Figure out address to use for connect (no privacy for now) */ + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + printf("error determining address type; rc=%d\n", rc); + return; + } + + /* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for + * timeout. + */ + rc = ble_gap_connect(own_addr_type, &disc->addr, 30000, NULL, + blecent_gap_event, NULL); + if (rc != 0) { + printf("Error: Failed to connect to device; addr_type=%d " + "addr=%s\n; rc=%d", + disc->addr.type, addr_str(disc->addr.val), rc); + return; + } +} + +/** + * The nimble host executes this callback when a GAP event occurs. The + * application associates a GAP event callback with each connection that is + * established. blecent uses the same callback for all connections. + * + * @param event The event being signalled. + * @param arg Application-specified argument; unused by + * blecent. + * + * @return 0 if the application successfully handled the + * event; nonzero on failure. The semantics + * of the return code is specific to the + * particular GAP event being signalled. + */ +static int +blecent_gap_event(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc desc; + struct ble_hs_adv_fields fields; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_DISC: + rc = ble_hs_adv_parse_fields(&fields, event->disc.data, + event->disc.length_data); + if (rc != 0) { + return 0; + } + + /* An advertisment report was received during GAP discovery. */ + print_adv_fields(&fields); + + /* Try to connect to the advertiser if it looks interesting. */ + blecent_connect_if_interesting(&event->disc); + return 0; + + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + if (event->connect.status == 0) { + /* Connection successfully established. */ + printf("Connection established "); + + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + assert(rc == 0); + print_conn_desc(&desc); + printf("\n"); + + /* Remember peer. */ + rc = peer_add(event->connect.conn_handle); + if (rc != 0) { + printf("Failed to add peer; rc=%d\n", rc); + return 0; + } + + /* Perform service discovery. */ + rc = peer_disc_all(event->connect.conn_handle, + blecent_on_disc_complete, NULL); + if (rc != 0) { + printf("Failed to discover services; rc=%d\n", rc); + return 0; + } + } else { + /* Connection attempt failed; resume scanning. */ + printf("Error: Connection failed; status=%d\n", + event->connect.status); + blecent_scan(); + } + + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + /* Connection terminated. */ + printf("disconnect; reason=%d ", event->disconnect.reason); + print_conn_desc(&event->disconnect.conn); + printf("\n"); + + /* Forget about peer. */ + peer_delete(event->disconnect.conn.conn_handle); + + /* Resume scanning. */ + blecent_scan(); + return 0; + + case BLE_GAP_EVENT_DISC_COMPLETE: + printf("discovery complete; reason=%d\n", + event->disc_complete.reason); + return 0; + + case BLE_GAP_EVENT_ENC_CHANGE: + /* Encryption has been enabled or disabled for this connection. */ + printf("encryption change event; status=%d ", + event->enc_change.status); + rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc); + assert(rc == 0); + print_conn_desc(&desc); + return 0; + + case BLE_GAP_EVENT_NOTIFY_RX: + /* Peer sent us a notification or indication. */ + printf("received %s; conn_handle=%d attr_handle=%d " + "attr_len=%d\n", + event->notify_rx.indication ? + "indication" : + "notification", + event->notify_rx.conn_handle, + event->notify_rx.attr_handle, + OS_MBUF_PKTLEN(event->notify_rx.om)); + + uint8_t notif_data[100]; /* Size depending on the actual size of the notification data you have */ + uint16_t notif_len; + int offset = 0; + notif_len = OS_MBUF_PKTLEN(event->notify_rx.om); + os_mbuf_copydata(event->notify_rx.om, offset, notif_len, notif_data); + + printf("notification data: "); + for (int i = 0; i < notif_len; i++) + { + printf("%02d ", notif_data[i]); + } + printf("\n"); + + /* Attribute data is contained in event->notify_rx.attr_data. */ + return 0; + + case BLE_GAP_EVENT_MTU: + printf("mtu update event; conn_handle=%d cid=%d mtu=%d\n", + event->mtu.conn_handle, + event->mtu.channel_id, + event->mtu.value); + return 0; + + case BLE_GAP_EVENT_REPEAT_PAIRING: + /* We already have a bond with the peer, but it is attempting to + * establish a new secure link. This app sacrifices security for + * convenience: just throw away the old bond and accept the new link. + */ + + /* Delete the old bond. */ + rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc); + assert(rc == 0); + ble_store_util_delete_peer(&desc.peer_id_addr); + + /* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should + * continue with the pairing operation. + */ + return BLE_GAP_REPEAT_PAIRING_RETRY; + + default: + return 0; + } +} + +static void +blecent_on_reset(int reason) +{ + printf("Resetting state; reason=%d\n", reason); +} + +static void +blecent_on_sync(void) +{ + int rc; + + /* Make sure we have proper identity address set (public preferred) */ + rc = ble_hs_util_ensure_addr(0); + assert(rc == 0); + + /* Begin scanning for a peripheral to connect to. */ + blecent_scan(); +} + +/**************************************************************************** + * Name: nimble_host_task + ****************************************************************************/ + +static void nimble_host_task(FAR void *param) +{ + ble_svc_gap_device_name_set("NuttX NimBLE CENT"); + nimble_port_run(); +} + +/**************************************************************************** + * Name: ble_hci_sock_task + ****************************************************************************/ + +static FAR void *ble_hci_sock_task(FAR void *param) +{ + ble_hci_sock_ack_handler(param); + return NULL; +} + +/**************************************************************************** + * Name: ble_host_task + ****************************************************************************/ + +static FAR void *ble_host_task(FAR void *param) +{ + nimble_host_task(param); + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nimble_main + ****************************************************************************/ +int main(int argc, char **argv) +{ + struct ble_npl_task s_task_host; + struct ble_npl_task s_task_hci; + int ret = 0; + + /* allow to specify custom hci */ + + if (argc > 1) + { + ble_hci_sock_set_device(atoi(argv[1])); + } + +#ifndef CONFIG_NSH_ARCHINIT + /* Perform architecture-specific initialization */ + + boardctl(BOARDIOC_INIT, 0); +#endif + +#ifndef CONFIG_NSH_NETINIT + /* Bring up the network */ + + netinit_bringup(); +#endif + + nimble_port_init(); + //ble_hci_sock_init(); + + /* Configure the host. */ + ble_hs_cfg.reset_cb = blecent_on_reset; + ble_hs_cfg.sync_cb = blecent_on_sync; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + + /* Initialize data structures to track connected peers. */ + ret = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64); + assert(ret == 0); + + /* Create task which handles HCI socket */ + + ret = ble_npl_task_init(&s_task_hci, "hci_sock", ble_hci_sock_task, + NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, + TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); + if (ret != 0) + { + printf("ERROR: starting hci task: %i\n", ret); + } + + /* Create task which handles default event queue for host stack. */ + + ret = ble_npl_task_init(&s_task_host, "ble_host", ble_host_task, + NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, + TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); + if (ret != 0) + { + printf("ERROR: starting ble task: %i\n", ret); + } + + while (true) + { + sleep(1); + } + + return 0; +} diff --git a/examples/nimble_blecent/peer.c b/examples/nimble_blecent/peer.c new file mode 100644 index 00000000000..887a7a6f77e --- /dev/null +++ b/examples/nimble_blecent/peer.c @@ -0,0 +1,808 @@ +/**************************************************************************** + * apps/examples/nimble_blecent/peer.c + * + * 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 +#include +#include "host/ble_hs.h" +#include "blecent.h" + +static void *peer_svc_mem; +static struct os_mempool peer_svc_pool; + +static void *peer_chr_mem; +static struct os_mempool peer_chr_pool; + +static void *peer_dsc_mem; +static struct os_mempool peer_dsc_pool; + +static void *peer_mem; +static struct os_mempool peer_pool; +static SLIST_HEAD(, peer) peers; + +static struct peer_svc * +peer_svc_find_range(struct peer *peer, uint16_t attr_handle); +static struct peer_svc * +peer_svc_find(struct peer *peer, uint16_t svc_start_handle, + struct peer_svc **out_prev); +int +peer_svc_is_empty(const struct peer_svc *svc); + +uint16_t +chr_end_handle(const struct peer_svc *svc, const struct peer_chr *chr); +int +chr_is_empty(const struct peer_svc *svc, const struct peer_chr *chr); +static struct peer_chr * +peer_chr_find(const struct peer_svc *svc, uint16_t chr_def_handle, + struct peer_chr **out_prev); +static void +peer_disc_chrs(struct peer *peer); + +static int +peer_dsc_disced(uint16_t conn_handle, const struct ble_gatt_error *error, + uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc, + void *arg); + +static struct peer * +peer_find(uint16_t conn_handle) +{ + struct peer *peer; + + SLIST_FOREACH(peer, &peers, next) { + if (peer->conn_handle == conn_handle) { + return peer; + } + } + + return NULL; +} + +static void +peer_disc_complete(struct peer *peer, int rc) +{ + peer->disc_prev_chr_val = 0; + + /* Notify caller that discovery has completed. */ + if (peer->disc_cb != NULL) { + peer->disc_cb(peer, rc, peer->disc_cb_arg); + } +} + +static struct peer_dsc * +peer_dsc_find_prev(const struct peer_chr *chr, uint16_t dsc_handle) +{ + struct peer_dsc *prev; + struct peer_dsc *dsc; + + prev = NULL; + SLIST_FOREACH(dsc, &chr->dscs, next) { + if (dsc->dsc.handle >= dsc_handle) { + break; + } + + prev = dsc; + } + + return prev; +} + +static struct peer_dsc * +peer_dsc_find(const struct peer_chr *chr, uint16_t dsc_handle, + struct peer_dsc **out_prev) +{ + struct peer_dsc *prev; + struct peer_dsc *dsc; + + prev = peer_dsc_find_prev(chr, dsc_handle); + if (prev == NULL) { + dsc = SLIST_FIRST(&chr->dscs); + } else { + dsc = SLIST_NEXT(prev, next); + } + + if (dsc != NULL && dsc->dsc.handle != dsc_handle) { + dsc = NULL; + } + + if (out_prev != NULL) { + *out_prev = prev; + } + return dsc; +} + +static int +peer_dsc_add(struct peer *peer, uint16_t chr_val_handle, + const struct ble_gatt_dsc *gatt_dsc) +{ + struct peer_dsc *prev; + struct peer_dsc *dsc; + struct peer_svc *svc; + struct peer_chr *chr; + + svc = peer_svc_find_range(peer, chr_val_handle); + if (svc == NULL) { + /* Can't find service for discovered descriptor; this shouldn't + * happen. + */ + assert(0); + return BLE_HS_EUNKNOWN; + } + + chr = peer_chr_find(svc, chr_val_handle, NULL); + if (chr == NULL) { + /* Can't find characteristic for discovered descriptor; this shouldn't + * happen. + */ + assert(0); + return BLE_HS_EUNKNOWN; + } + + dsc = peer_dsc_find(chr, gatt_dsc->handle, &prev); + if (dsc != NULL) { + /* Descriptor already discovered. */ + return 0; + } + + dsc = os_memblock_get(&peer_dsc_pool); + if (dsc == NULL) { + /* Out of memory. */ + return BLE_HS_ENOMEM; + } + memset(dsc, 0, sizeof *dsc); + + dsc->dsc = *gatt_dsc; + + if (prev == NULL) { + SLIST_INSERT_HEAD(&chr->dscs, dsc, next); + } else { + SLIST_NEXT(prev, next) = dsc; + } + + return 0; +} + +static void +peer_disc_dscs(struct peer *peer) +{ + struct peer_chr *chr; + struct peer_svc *svc; + int rc; + + /* Search through the list of discovered characteristics for the first + * characteristic that contains undiscovered descriptors. Then, discover + * all descriptors belonging to that characteristic. + */ + SLIST_FOREACH(svc, &peer->svcs, next) { + SLIST_FOREACH(chr, &svc->chrs, next) { + if (!chr_is_empty(svc, chr) && + SLIST_EMPTY(&chr->dscs) && + peer->disc_prev_chr_val <= chr->chr.def_handle) { + + rc = ble_gattc_disc_all_dscs(peer->conn_handle, + chr->chr.val_handle, + chr_end_handle(svc, chr), + peer_dsc_disced, peer); + if (rc != 0) { + peer_disc_complete(peer, rc); + } + + peer->disc_prev_chr_val = chr->chr.val_handle; + return; + } + } + } + + /* All descriptors discovered. */ + peer_disc_complete(peer, 0); +} + +static int +peer_dsc_disced(uint16_t conn_handle, const struct ble_gatt_error *error, + uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc, + void *arg) +{ + struct peer *peer; + int rc; + + peer = arg; + assert(peer->conn_handle == conn_handle); + + switch (error->status) { + case 0: + rc = peer_dsc_add(peer, chr_val_handle, dsc); + break; + + case BLE_HS_EDONE: + /* All descriptors in this characteristic discovered; start discovering + * descriptors in the next characteristic. + */ + if (peer->disc_prev_chr_val > 0) { + peer_disc_dscs(peer); + } + rc = 0; + break; + + default: + /* Error; abort discovery. */ + rc = error->status; + break; + } + + if (rc != 0) { + /* Error; abort discovery. */ + peer_disc_complete(peer, rc); + } + + return rc; +} + +uint16_t +chr_end_handle(const struct peer_svc *svc, const struct peer_chr *chr) +{ + const struct peer_chr *next_chr; + + next_chr = SLIST_NEXT(chr, next); + if (next_chr != NULL) { + return next_chr->chr.def_handle - 1; + } else { + return svc->svc.end_handle; + } +} + +int +chr_is_empty(const struct peer_svc *svc, const struct peer_chr *chr) +{ + return chr_end_handle(svc, chr) <= chr->chr.val_handle; +} + +static struct peer_chr * +peer_chr_find_prev(const struct peer_svc *svc, uint16_t chr_val_handle) +{ + struct peer_chr *prev; + struct peer_chr *chr; + + prev = NULL; + SLIST_FOREACH(chr, &svc->chrs, next) { + if (chr->chr.val_handle >= chr_val_handle) { + break; + } + + prev = chr; + } + + return prev; +} + +static struct peer_chr * +peer_chr_find(const struct peer_svc *svc, uint16_t chr_val_handle, + struct peer_chr **out_prev) +{ + struct peer_chr *prev; + struct peer_chr *chr; + + prev = peer_chr_find_prev(svc, chr_val_handle); + if (prev == NULL) { + chr = SLIST_FIRST(&svc->chrs); + } else { + chr = SLIST_NEXT(prev, next); + } + + if (chr != NULL && chr->chr.val_handle != chr_val_handle) { + chr = NULL; + } + + if (out_prev != NULL) { + *out_prev = prev; + } + return chr; +} + +static void +peer_chr_delete(struct peer_chr *chr) +{ + struct peer_dsc *dsc; + + while ((dsc = SLIST_FIRST(&chr->dscs)) != NULL) { + SLIST_REMOVE_HEAD(&chr->dscs, next); + os_memblock_put(&peer_dsc_pool, dsc); + } + + os_memblock_put(&peer_chr_pool, chr); +} + +static int +peer_chr_add(struct peer *peer, uint16_t svc_start_handle, + const struct ble_gatt_chr *gatt_chr) +{ + struct peer_chr *prev; + struct peer_chr *chr; + struct peer_svc *svc; + + svc = peer_svc_find(peer, svc_start_handle, NULL); + if (svc == NULL) { + /* Can't find service for discovered characteristic; this shouldn't + * happen. + */ + assert(0); + return BLE_HS_EUNKNOWN; + } + + chr = peer_chr_find(svc, gatt_chr->def_handle, &prev); + if (chr != NULL) { + /* Characteristic already discovered. */ + return 0; + } + + chr = os_memblock_get(&peer_chr_pool); + if (chr == NULL) { + /* Out of memory. */ + return BLE_HS_ENOMEM; + } + memset(chr, 0, sizeof *chr); + + chr->chr = *gatt_chr; + + if (prev == NULL) { + SLIST_INSERT_HEAD(&svc->chrs, chr, next); + } else { + SLIST_NEXT(prev, next) = chr; + } + + return 0; +} + +static int +peer_chr_disced(uint16_t conn_handle, const struct ble_gatt_error *error, + const struct ble_gatt_chr *chr, void *arg) +{ + struct peer *peer; + int rc; + + peer = arg; + assert(peer->conn_handle == conn_handle); + + switch (error->status) { + case 0: + rc = peer_chr_add(peer, peer->cur_svc->svc.start_handle, chr); + break; + + case BLE_HS_EDONE: + /* All characteristics in this service discovered; start discovering + * characteristics in the next service. + */ + if (peer->disc_prev_chr_val > 0) { + peer_disc_chrs(peer); + } + rc = 0; + break; + + default: + rc = error->status; + break; + } + + if (rc != 0) { + /* Error; abort discovery. */ + peer_disc_complete(peer, rc); + } + + return rc; +} + +static void +peer_disc_chrs(struct peer *peer) +{ + struct peer_svc *svc; + int rc; + + /* Search through the list of discovered service for the first service that + * contains undiscovered characteristics. Then, discover all + * characteristics belonging to that service. + */ + SLIST_FOREACH(svc, &peer->svcs, next) { + if (!peer_svc_is_empty(svc) && SLIST_EMPTY(&svc->chrs)) { + peer->cur_svc = svc; + rc = ble_gattc_disc_all_chrs(peer->conn_handle, + svc->svc.start_handle, + svc->svc.end_handle, + peer_chr_disced, peer); + if (rc != 0) { + peer_disc_complete(peer, rc); + } + return; + } + } + + /* All characteristics discovered. */ + peer_disc_dscs(peer); +} + +int +peer_svc_is_empty(const struct peer_svc *svc) +{ + return svc->svc.end_handle <= svc->svc.start_handle; +} + +static struct peer_svc * +peer_svc_find_prev(struct peer *peer, uint16_t svc_start_handle) +{ + struct peer_svc *prev; + struct peer_svc *svc; + + prev = NULL; + SLIST_FOREACH(svc, &peer->svcs, next) { + if (svc->svc.start_handle >= svc_start_handle) { + break; + } + + prev = svc; + } + + return prev; +} + +static struct peer_svc * +peer_svc_find(struct peer *peer, uint16_t svc_start_handle, + struct peer_svc **out_prev) +{ + struct peer_svc *prev; + struct peer_svc *svc; + + prev = peer_svc_find_prev(peer, svc_start_handle); + if (prev == NULL) { + svc = SLIST_FIRST(&peer->svcs); + } else { + svc = SLIST_NEXT(prev, next); + } + + if (svc != NULL && svc->svc.start_handle != svc_start_handle) { + svc = NULL; + } + + if (out_prev != NULL) { + *out_prev = prev; + } + return svc; +} + +static struct peer_svc * +peer_svc_find_range(struct peer *peer, uint16_t attr_handle) +{ + struct peer_svc *svc; + + SLIST_FOREACH(svc, &peer->svcs, next) { + if (svc->svc.start_handle <= attr_handle && + svc->svc.end_handle >= attr_handle) { + + return svc; + } + } + + return NULL; +} + +const struct peer_svc * +peer_svc_find_uuid(const struct peer *peer, const ble_uuid_t *uuid) +{ + const struct peer_svc *svc; + + SLIST_FOREACH(svc, &peer->svcs, next) { + if (ble_uuid_cmp(&svc->svc.uuid.u, uuid) == 0) { + return svc; + } + } + + return NULL; +} + +const struct peer_chr * +peer_chr_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid, + const ble_uuid_t *chr_uuid) +{ + const struct peer_svc *svc; + const struct peer_chr *chr; + + svc = peer_svc_find_uuid(peer, svc_uuid); + if (svc == NULL) { + return NULL; + } + + SLIST_FOREACH(chr, &svc->chrs, next) { + if (ble_uuid_cmp(&chr->chr.uuid.u, chr_uuid) == 0) { + return chr; + } + } + + return NULL; +} + +const struct peer_dsc * +peer_dsc_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid, + const ble_uuid_t *chr_uuid, const ble_uuid_t *dsc_uuid) +{ + const struct peer_chr *chr; + const struct peer_dsc *dsc; + + chr = peer_chr_find_uuid(peer, svc_uuid, chr_uuid); + if (chr == NULL) { + return NULL; + } + + SLIST_FOREACH(dsc, &chr->dscs, next) { + if (ble_uuid_cmp(&dsc->dsc.uuid.u, dsc_uuid) == 0) { + return dsc; + } + } + + return NULL; +} + +static int +peer_svc_add(struct peer *peer, const struct ble_gatt_svc *gatt_svc) +{ + struct peer_svc *prev; + struct peer_svc *svc; + + svc = peer_svc_find(peer, gatt_svc->start_handle, &prev); + if (svc != NULL) { + /* Service already discovered. */ + return 0; + } + + svc = os_memblock_get(&peer_svc_pool); + if (svc == NULL) { + /* Out of memory. */ + return BLE_HS_ENOMEM; + } + memset(svc, 0, sizeof *svc); + + svc->svc = *gatt_svc; + SLIST_INIT(&svc->chrs); + + if (prev == NULL) { + SLIST_INSERT_HEAD(&peer->svcs, svc, next); + } else { + SLIST_INSERT_AFTER(prev, svc, next); + } + + return 0; +} + +static void +peer_svc_delete(struct peer_svc *svc) +{ + struct peer_chr *chr; + + while ((chr = SLIST_FIRST(&svc->chrs)) != NULL) { + SLIST_REMOVE_HEAD(&svc->chrs, next); + peer_chr_delete(chr); + } + + os_memblock_put(&peer_svc_pool, svc); +} + +static int +peer_svc_disced(uint16_t conn_handle, const struct ble_gatt_error *error, + const struct ble_gatt_svc *service, void *arg) +{ + struct peer *peer; + int rc; + + peer = arg; + assert(peer->conn_handle == conn_handle); + + switch (error->status) { + case 0: + rc = peer_svc_add(peer, service); + break; + + case BLE_HS_EDONE: + /* All services discovered; start discovering characteristics. */ + if (peer->disc_prev_chr_val > 0) { + peer_disc_chrs(peer); + } + rc = 0; + break; + + default: + rc = error->status; + break; + } + + if (rc != 0) { + /* Error; abort discovery. */ + peer_disc_complete(peer, rc); + } + + return rc; +} + + +int +peer_disc_all(uint16_t conn_handle, peer_disc_fn *disc_cb, void *disc_cb_arg) +{ + struct peer_svc *svc; + struct peer *peer; + int rc; + + peer = peer_find(conn_handle); + if (peer == NULL) { + return BLE_HS_ENOTCONN; + } + + /* Undiscover everything first. */ + while ((svc = SLIST_FIRST(&peer->svcs)) != NULL) { + SLIST_REMOVE_HEAD(&peer->svcs, next); + peer_svc_delete(svc); + } + + peer->disc_prev_chr_val = 1; + peer->disc_cb = disc_cb; + peer->disc_cb_arg = disc_cb_arg; + + rc = ble_gattc_disc_all_svcs(conn_handle, peer_svc_disced, peer); + if (rc != 0) { + return rc; + } + + return 0; +} + +int +peer_delete(uint16_t conn_handle) +{ + struct peer_svc *svc; + struct peer *peer; + int rc; + + peer = peer_find(conn_handle); + if (peer == NULL) { + return BLE_HS_ENOTCONN; + } + + SLIST_REMOVE(&peers, peer, peer, next); + + while ((svc = SLIST_FIRST(&peer->svcs)) != NULL) { + SLIST_REMOVE_HEAD(&peer->svcs, next); + peer_svc_delete(svc); + } + + rc = os_memblock_put(&peer_pool, peer); + if (rc != 0) { + return BLE_HS_EOS; + } + + return 0; +} + +int +peer_add(uint16_t conn_handle) +{ + struct peer *peer; + + /* Make sure the connection handle is unique. */ + peer = peer_find(conn_handle); + if (peer != NULL) { + return BLE_HS_EALREADY; + } + + peer = os_memblock_get(&peer_pool); + if (peer == NULL) { + /* Out of memory. */ + return BLE_HS_ENOMEM; + } + + memset(peer, 0, sizeof *peer); + peer->conn_handle = conn_handle; + + SLIST_INSERT_HEAD(&peers, peer, next); + + return 0; +} + +static void +peer_free_mem(void) +{ + free(peer_mem); + peer_mem = NULL; + + free(peer_svc_mem); + peer_svc_mem = NULL; + + free(peer_chr_mem); + peer_chr_mem = NULL; + + free(peer_dsc_mem); + peer_dsc_mem = NULL; +} + +int +peer_init(int max_peers, int max_svcs, int max_chrs, int max_dscs) +{ + int rc; + + /* Free memory first in case this function gets called more than once. */ + peer_free_mem(); + + peer_mem = malloc( + OS_MEMPOOL_BYTES(max_peers, sizeof (struct peer))); + if (peer_mem == NULL) { + rc = BLE_HS_ENOMEM; + goto err; + } + + rc = os_mempool_init(&peer_pool, max_peers, + sizeof (struct peer), peer_mem, + "peer_pool"); + if (rc != 0) { + rc = BLE_HS_EOS; + goto err; + } + + peer_svc_mem = malloc( + OS_MEMPOOL_BYTES(max_svcs, sizeof (struct peer_svc))); + if (peer_svc_mem == NULL) { + rc = BLE_HS_ENOMEM; + goto err; + } + + rc = os_mempool_init(&peer_svc_pool, max_svcs, + sizeof (struct peer_svc), peer_svc_mem, + "peer_svc_pool"); + if (rc != 0) { + rc = BLE_HS_EOS; + goto err; + } + + peer_chr_mem = malloc( + OS_MEMPOOL_BYTES(max_chrs, sizeof (struct peer_chr))); + if (peer_chr_mem == NULL) { + rc = BLE_HS_ENOMEM; + goto err; + } + + rc = os_mempool_init(&peer_chr_pool, max_chrs, + sizeof (struct peer_chr), peer_chr_mem, + "peer_chr_pool"); + if (rc != 0) { + rc = BLE_HS_EOS; + goto err; + } + + peer_dsc_mem = malloc( + OS_MEMPOOL_BYTES(max_dscs, sizeof (struct peer_dsc))); + if (peer_dsc_mem == NULL) { + rc = BLE_HS_ENOMEM; + goto err; + } + + rc = os_mempool_init(&peer_dsc_pool, max_dscs, + sizeof (struct peer_dsc), peer_dsc_mem, + "peer_dsc_pool"); + if (rc != 0) { + rc = BLE_HS_EOS; + goto err; + } + + return 0; + +err: + peer_free_mem(); + return rc; +} diff --git a/examples/nimble_bleprph/CMakeLists.txt b/examples/nimble_bleprph/CMakeLists.txt new file mode 100644 index 00000000000..6d53718b934 --- /dev/null +++ b/examples/nimble_bleprph/CMakeLists.txt @@ -0,0 +1,26 @@ +# ############################################################################## +# apps/examples/nimble_bleprph/CMakeLists.txt +# +# 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(CONFIG_EXAMPLES_NIMBLE_BLEPRPH) + nuttx_add_application( + NAME nimble + SRCS ${CMAKE_CURRENT_LIST_DIR}/nimble_bleprph_main.c ${CMAKE_CURRENT_LIST_DIR}/misc.c ${CMAKE_CURRENT_LIST_DIR}/gatt_svr.c + DEPENDS nimble) +endif() diff --git a/examples/nimble_bleprph/Kconfig b/examples/nimble_bleprph/Kconfig new file mode 100644 index 00000000000..7ee88ea6a47 --- /dev/null +++ b/examples/nimble_bleprph/Kconfig @@ -0,0 +1,30 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config EXAMPLES_NIMBLE_BLEPRPH + tristate "NimBLE peripheral" + default n + ---help--- + Enable the nimble peripheral + +if EXAMPLES_NIMBLE_BLEPRPH + +config EXAMPLES_NIMBLE_BLEPRPH_PROGNAME + string "Program name" + default "nimble" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config EXAMPLES_NIMBLE_BLEPRPH_PRIORITY + int "NimBLE task priority" + default 100 + +config EXAMPLES_NIMBLE_BLEPRPH_STACKSIZE + int "NimBLE stack size" + default DEFAULT_TASK_STACKSIZE + +endif # EXAMPLES_NIMBLE_BLEPRPH + diff --git a/examples/nimble_bleprph/Make.defs b/examples/nimble_bleprph/Make.defs new file mode 100644 index 00000000000..af5e367d96b --- /dev/null +++ b/examples/nimble_bleprph/Make.defs @@ -0,0 +1,23 @@ +############################################################################ +# apps/examples/nimble_bleprph/Make.defs +# +# 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. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_NIMBLE_BLEPRPH),) +CONFIGURED_APPS += $(APPDIR)/examples/nimble +endif diff --git a/examples/nimble_bleprph/Makefile b/examples/nimble_bleprph/Makefile new file mode 100644 index 00000000000..751ff48df09 --- /dev/null +++ b/examples/nimble_bleprph/Makefile @@ -0,0 +1,36 @@ +############################################################################ +# apps/examples/nimble_bleprph/Makefile +# +# 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 $(APPDIR)/Make.defs + +# NimBLE built-in application info + +PROGNAME = $(CONFIG_EXAMPLES_NIMBLE_BLEPRPH_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_NIMBLE_BLEPRPH_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_NIMBLE_BLEPRPH_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_NIMBLE_BLEPRPH) + +# NimBLE Example + +MAINSRC = nimble_bleprph_main.c + +include $(APPDIR)/wireless/bluetooth/nimble/Makefile.nimble + +include $(APPDIR)/Application.mk diff --git a/examples/nimble_bleprph/bleprph.h b/examples/nimble_bleprph/bleprph.h new file mode 100644 index 00000000000..495edd9276d --- /dev/null +++ b/examples/nimble_bleprph/bleprph.h @@ -0,0 +1,53 @@ +/**************************************************************************** + * apps/examples/nimble_bleprph/bleprph.h + * + * 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_BLEPRPH_ +#define H_BLEPRPH_ + +#include +#include +#include "nimble/ble.h" +#ifdef __cplusplus +extern "C" { +#endif + +struct ble_hs_cfg; +struct ble_gatt_register_ctxt; + +/** GATT server. */ +#define GATT_SVR_SVC_ALERT_UUID 0x1811 +#define GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID 0x2A47 +#define GATT_SVR_CHR_NEW_ALERT 0x2A46 +#define GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID 0x2A48 +#define GATT_SVR_CHR_UNR_ALERT_STAT_UUID 0x2A45 +#define GATT_SVR_CHR_ALERT_NOT_CTRL_PT 0x2A44 + +void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg); +int gatt_svr_init(void); + +/** Misc. */ +void print_bytes(const uint8_t *bytes, int len); +void print_addr(const void *addr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/nimble_bleprph/gatt_svr.c b/examples/nimble_bleprph/gatt_svr.c new file mode 100644 index 00000000000..c417d8914f0 --- /dev/null +++ b/examples/nimble_bleprph/gatt_svr.c @@ -0,0 +1,210 @@ +/**************************************************************************** + * apps/examples/nimble_bleprph/gatt_svr.c + * + * 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 +#include +#include +#include "host/ble_hs.h" +#include "host/ble_uuid.h" +#include "services/ans/ble_svc_ans.h" +#include "services/bas/ble_svc_bas.h" +#include "bleprph.h" + +/** + * The vendor specific security test service consists of two characteristics: + * o random-number-generator: generates a random 32-bit number each time + * it is read. This characteristic can only be read over an encrypted + * connection. + * o static-value: a single-byte characteristic that can always be read, + * but can only be written over an encrypted connection. + */ + +/* 59462f12-9543-9999-12c8-58b459a2712d */ +static const ble_uuid128_t gatt_svr_svc_sec_test_uuid = + BLE_UUID128_INIT(0x2d, 0x71, 0xa2, 0x59, 0xb4, 0x58, 0xc8, 0x12, + 0x99, 0x99, 0x43, 0x95, 0x12, 0x2f, 0x46, 0x59); + +/* 5c3a659e-897e-45e1-b016-007107c96df6 */ +static const ble_uuid128_t gatt_svr_chr_sec_test_rand_uuid = + BLE_UUID128_INIT(0xf6, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0, + 0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c); + +/* 5c3a659e-897e-45e1-b016-007107c96df7 */ +static const ble_uuid128_t gatt_svr_chr_sec_test_static_uuid = + BLE_UUID128_INIT(0xf7, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0, + 0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c); + +static uint8_t gatt_svr_sec_test_static_val; + +static int +gatt_svr_chr_access_sec_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static const struct ble_gatt_svc_def gatt_svr_svcs[] = { + { + /*** Service: Security test. */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = &gatt_svr_svc_sec_test_uuid.u, + .characteristics = (struct ble_gatt_chr_def[]) { { + /*** Characteristic: Random number generator. */ + .uuid = &gatt_svr_chr_sec_test_rand_uuid.u, + .access_cb = gatt_svr_chr_access_sec_test, + .flags = BLE_GATT_CHR_F_READ, + }, { + /*** Characteristic: Static value. */ + .uuid = &gatt_svr_chr_sec_test_static_uuid.u, + .access_cb = gatt_svr_chr_access_sec_test, + .flags = BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_WRITE, + }, { + 0, /* No more characteristics in this service. */ + } }, + }, + + { + 0, /* No more services. */ + }, +}; + +static int +gatt_svr_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 int +gatt_svr_chr_access_sec_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + const ble_uuid_t *uuid; + int rand_num; + int rc; + + uuid = ctxt->chr->uuid; + + /* Determine which characteristic is being accessed by examining its + * 128-bit UUID. + */ + + if (ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_rand_uuid.u) == 0) { + assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); + + /* Respond with a 32-bit random number. */ + rand_num = rand(); + rc = os_mbuf_append(ctxt->om, &rand_num, sizeof rand_num); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + + if (ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_static_uuid.u) == 0) { + switch (ctxt->op) { + case BLE_GATT_ACCESS_OP_READ_CHR: + rc = os_mbuf_append(ctxt->om, &gatt_svr_sec_test_static_val, + sizeof gatt_svr_sec_test_static_val); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + + case BLE_GATT_ACCESS_OP_WRITE_CHR: + rc = gatt_svr_chr_write(ctxt->om, + sizeof gatt_svr_sec_test_static_val, + sizeof gatt_svr_sec_test_static_val, + &gatt_svr_sec_test_static_val, NULL); + return rc; + + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } + } + + /* Unknown characteristic; the nimble stack should not have called this + * function. + */ + assert(0); + return BLE_ATT_ERR_UNLIKELY; +} + +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: + printf("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: + printf("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: + printf("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; + + ble_svc_ans_init(); + ble_svc_bas_init(); + + 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; +} diff --git a/examples/nimble_bleprph/misc.c b/examples/nimble_bleprph/misc.c new file mode 100644 index 00000000000..713bd911fa8 --- /dev/null +++ b/examples/nimble_bleprph/misc.c @@ -0,0 +1,45 @@ +/**************************************************************************** + * apps/examples/nimble_bleprph/misc.c + * + * 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 "bleprph.h" + +/** + * Utility function to log an array of bytes. + */ +void +print_bytes(const uint8_t *bytes, int len) +{ + int i; + + for (i = 0; i < len; i++) { + printf("%s0x%02x", i != 0 ? ":" : "", bytes[i]); + } +} + +void +print_addr(const void *addr) +{ + const uint8_t *u8p; + + u8p = addr; + printf("%02x:%02x:%02x:%02x:%02x:%02x", + u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]); +} diff --git a/examples/nimble_bleprph/nimble_bleprph_main.c b/examples/nimble_bleprph/nimble_bleprph_main.c new file mode 100644 index 00000000000..ecc3db17e70 --- /dev/null +++ b/examples/nimble_bleprph/nimble_bleprph_main.c @@ -0,0 +1,421 @@ +/**************************************************************************** + * apps/examples/nimble_bleprph/nimble_bleprph_main.c + * + * 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 +#include +#include +#include + +/* BLE */ +#include "nimble/ble.h" +#include "nimble/nimble_port.h" +#include "host/ble_hs.h" +#include "host/util/util.h" +#include "services/gap/ble_svc_gap.h" +#include "services/bas/ble_svc_bas.h" + +/* Application-specified header. */ +#include "bleprph.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Not used now */ + +#define TASK_DEFAULT_PRIORITY CONFIG_EXAMPLES_NIMBLE_BLEPRPH_PRIORITY +#define TASK_DEFAULT_STACK NULL +#define TASK_DEFAULT_STACK_SIZE 0 + +/**************************************************************************** + * External Functions Prototypes + ****************************************************************************/ + +void ble_hci_sock_ack_handler(FAR void *param); +//void ble_hci_sock_init(void); +void ble_hci_sock_set_device(int dev); + +/**************************************************************************** + * Private Functions Prototypes + ****************************************************************************/ + +static void bleprph_advertise(void); +static void nimble_host_task(FAR void *param); +static FAR void *ble_hci_sock_task(FAR void *param); +static FAR void *ble_host_task(FAR void *param); +static int bleprph_gap_event(struct ble_gap_event *event, void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/** + * Logs information about a connection to the console. + */ +static void +bleprph_print_conn_desc(struct ble_gap_conn_desc *desc) +{ + printf("handle=%d our_ota_addr_type=%d our_ota_addr=", + desc->conn_handle, desc->our_ota_addr.type); + print_addr(desc->our_ota_addr.val); + printf(" our_id_addr_type=%d our_id_addr=", + desc->our_id_addr.type); + print_addr(desc->our_id_addr.val); + printf(" peer_ota_addr_type=%d peer_ota_addr=", + desc->peer_ota_addr.type); + print_addr(desc->peer_ota_addr.val); + printf(" peer_id_addr_type=%d peer_id_addr=", + desc->peer_id_addr.type); + print_addr(desc->peer_id_addr.val); + printf(" conn_itvl=%d conn_latency=%d supervision_timeout=%d " + "encrypted=%d authenticated=%d bonded=%d\n", + desc->conn_itvl, desc->conn_latency, + desc->supervision_timeout, + desc->sec_state.encrypted, + desc->sec_state.authenticated, + desc->sec_state.bonded); +} + +/** + * Enables advertising with the following parameters: + * o General discoverable mode. + * o Undirected connectable mode. + */ +static void +bleprph_advertise(void) +{ + uint8_t own_addr_type; + struct ble_gap_adv_params adv_params; + struct ble_hs_adv_fields fields; + const char *name; + int rc; + + /* Figure out address to use while advertising (no privacy for now) */ + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) + { + printf("error determining address type; rc=%d\n", rc); + return; + } + + /** + * Set the advertisement data included in our advertisements: + * o Flags (indicates advertisement type and other general info). + * o Advertising tx power. + * o Device name. + * o 16-bit service UUIDs (alert notifications). + */ + + 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 assiging 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; + + name = ble_svc_gap_device_name(); + fields.name = (uint8_t *)name; + fields.name_len = strlen(name); + fields.name_is_complete = 1; + + fields.uuids16 = (ble_uuid16_t[]){ + BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID)}; + fields.num_uuids16 = 1; + fields.uuids16_is_complete = 1; + + rc = ble_gap_adv_set_fields(&fields); + if (rc != 0) + { + printf("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(own_addr_type, NULL, BLE_HS_FOREVER, + &adv_params, bleprph_gap_event, NULL); + if (rc != 0) + { + printf("error enabling advertisement; rc=%d\n", rc); + return; + } +} + +/** + * The nimble host executes this callback when a GAP event occurs. The + * application associates a GAP event callback with each connection that forms. + * bleprph uses the same callback for all connections. + * + * @param event The type of event being signalled. + * @param ctxt Various information pertaining to the event. + * @param arg Application-specified argument; unuesd by + * bleprph. + * + * @return 0 if the application successfully handled the + * event; nonzero on failure. The semantics + * of the return code is specific to the + * particular GAP event being signalled. + */ +static int +bleprph_gap_event(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc desc; + int rc; + + switch (event->type) + { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed. */ + printf("connection %s; status=%d ", + event->connect.status == 0 ? "established" : "failed", + event->connect.status); + if (event->connect.status == 0) + { + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + assert(rc == 0); + bleprph_print_conn_desc(&desc); + } + printf("\n"); + + if (event->connect.status != 0) + { + /* Connection failed; resume advertising. */ + bleprph_advertise(); + } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + printf("disconnect; reason=%d ", event->disconnect.reason); + bleprph_print_conn_desc(&event->disconnect.conn); + printf("\n"); + + /* Connection terminated; resume advertising. */ + bleprph_advertise(); + return 0; + + case BLE_GAP_EVENT_CONN_UPDATE: + /* The central has updated the connection parameters. */ + printf("connection updated; status=%d ", + event->conn_update.status); + rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc); + assert(rc == 0); + bleprph_print_conn_desc(&desc); + printf("\n"); + return 0; + + case BLE_GAP_EVENT_ADV_COMPLETE: + printf("advertise complete; reason=%d", + event->adv_complete.reason); + bleprph_advertise(); + return 0; + + case BLE_GAP_EVENT_ENC_CHANGE: + /* Encryption has been enabled or disabled for this connection. */ + printf("encryption change event; status=%d ", + event->enc_change.status); + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + assert(rc == 0); + bleprph_print_conn_desc(&desc); + printf("\n"); + return 0; + + case BLE_GAP_EVENT_SUBSCRIBE: + printf("subscribe event; conn_handle=%d attr_handle=%d " + "reason=%d prevn=%d curn=%d previ=%d curi=%d\n", + event->subscribe.conn_handle, + event->subscribe.attr_handle, + event->subscribe.reason, + event->subscribe.prev_notify, + event->subscribe.cur_notify, + event->subscribe.prev_indicate, + event->subscribe.cur_indicate); + return 0; + + case BLE_GAP_EVENT_MTU: + printf("mtu update event; conn_handle=%d cid=%d mtu=%d\n", + event->mtu.conn_handle, + event->mtu.channel_id, + event->mtu.value); + return 0; + + case BLE_GAP_EVENT_REPEAT_PAIRING: + /* We already have a bond with the peer, but it is attempting to + * establish a new secure link. This app sacrifices security for + * convenience: just throw away the old bond and accept the new link. + */ + + /* Delete the old bond. */ + rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc); + assert(rc == 0); + ble_store_util_delete_peer(&desc.peer_id_addr); + + /* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should + * continue with the pairing operation. + */ + return BLE_GAP_REPEAT_PAIRING_RETRY; + } + + return 0; +} + +static void +bleprph_on_reset(int reason) +{ + printf("Resetting state; reason=%d\n", reason); +} + +static void +bleprph_on_sync(void) +{ + int rc; + + /* Make sure we have proper identity address set (public preferred) */ + rc = ble_hs_util_ensure_addr(0); + assert(rc == 0); + + /* Begin advertising. */ + bleprph_advertise(); +} + +/**************************************************************************** + * Name: nimble_host_task + ****************************************************************************/ + +static void nimble_host_task(FAR void *param) +{ + ble_svc_gap_device_name_set("NuttX NimBLE PRPH"); + nimble_port_run(); +} + +/**************************************************************************** + * Name: ble_hci_sock_task + ****************************************************************************/ + +static FAR void *ble_hci_sock_task(FAR void *param) +{ + ble_hci_sock_ack_handler(param); + return NULL; +} + +/**************************************************************************** + * Name: ble_host_task + ****************************************************************************/ + +static FAR void *ble_host_task(FAR void *param) +{ + nimble_host_task(param); + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nimble_main + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + struct ble_npl_task s_task_host; + struct ble_npl_task s_task_hci; + int ret = 0; + uint8_t batt_level = 0; + + /* allow to specify custom hci */ + + if (argc > 1) + { + ble_hci_sock_set_device(atoi(argv[1])); + } + +#ifndef CONFIG_NSH_ARCHINIT + /* Perform architecture-specific initialization */ + + boardctl(BOARDIOC_INIT, 0); +#endif + +#ifndef CONFIG_NSH_NETINIT + /* Bring up the network */ + + netinit_bringup(); +#endif + + nimble_port_init(); + //ble_hci_sock_init(); + + /* Initialize the NimBLE host configuration. */ + ble_hs_cfg.reset_cb = bleprph_on_reset; + ble_hs_cfg.sync_cb = bleprph_on_sync; + ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + + /* Initialize services */ + ret = gatt_svr_init(); + assert(ret == 0); + + /* Create task which handles HCI socket */ + + ret = ble_npl_task_init(&s_task_hci, "hci_sock", ble_hci_sock_task, + NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, + TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); + if (ret != 0) + { + printf("ERROR: starting hci task: %i\n", ret); + } + + /* Create task which handles default event queue for host stack. */ + + ret = ble_npl_task_init(&s_task_host, "ble_host", ble_host_task, + NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, + TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); + if (ret != 0) + { + printf("ERROR: starting ble task: %i\n", ret); + } + + while (true) + { + /* Simulate battery */ + + batt_level += 1; + if (batt_level > 100) + { + batt_level = 0; + } + + ble_svc_bas_battery_level_set(batt_level); + sleep(1); + } + + return 0; +} From 43cf440256cdba10b3fceed6b409e7d60959e78b Mon Sep 17 00:00:00 2001 From: Max Kriegleder Date: Wed, 8 Jan 2025 20:40:29 +0100 Subject: [PATCH 2/3] Fix formatting --- examples/nimble_blecent/CMakeLists.txt | 11 +- examples/nimble_blecent/blecent.h | 34 +- examples/nimble_blecent/misc.c | 271 +++-- examples/nimble_blecent/nimble_blecent_main.c | 774 +++++++------ examples/nimble_blecent/peer.c | 1012 +++++++++-------- examples/nimble_bleprph/CMakeLists.txt | 11 +- examples/nimble_bleprph/bleprph.h | 13 +- examples/nimble_bleprph/gatt_svr.c | 235 ++-- examples/nimble_bleprph/misc.c | 29 +- examples/nimble_bleprph/nimble_bleprph_main.c | 494 ++++---- 10 files changed, 1606 insertions(+), 1278 deletions(-) diff --git a/examples/nimble_blecent/CMakeLists.txt b/examples/nimble_blecent/CMakeLists.txt index c4c803c1b72..6b10b76d66b 100644 --- a/examples/nimble_blecent/CMakeLists.txt +++ b/examples/nimble_blecent/CMakeLists.txt @@ -20,7 +20,12 @@ if(CONFIG_EXAMPLES_NIMBLE_BLECENT) nuttx_add_application( - NAME nimble - SRCS ${CMAKE_CURRENT_LIST_DIR}/nimble_blecent_main.c ${CMAKE_CURRENT_LIST_DIR}/misc.c ${CMAKE_CURRENT_LIST_DIR}/peer.c - DEPENDS nimble) + NAME + nimble + SRCS + ${CMAKE_CURRENT_LIST_DIR}/nimble_blecent_main.c + ${CMAKE_CURRENT_LIST_DIR}/misc.c + ${CMAKE_CURRENT_LIST_DIR}/peer.c + DEPENDS + nimble) endif() diff --git a/examples/nimble_blecent/blecent.h b/examples/nimble_blecent/blecent.h index 3da21592751..8ae394ecd29 100644 --- a/examples/nimble_blecent/blecent.h +++ b/examples/nimble_blecent/blecent.h @@ -21,10 +21,15 @@ #ifndef H_BLECENT_ #define H_BLECENT_ +/**************************************************************************** + * Included Files + ****************************************************************************/ + #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif struct ble_hs_adv_fields; @@ -40,7 +45,8 @@ union ble_store_key; #define BLECENT_CHR_UNR_ALERT_STAT_UUID 0x2A45 #define BLECENT_CHR_ALERT_NOT_CTRL_PT 0x2A44 -/** Misc. */ +/* Misc. */ + void print_bytes(const uint8_t *bytes, int len); void print_mbuf(const struct os_mbuf *om); char *addr_str(const void *addr); @@ -48,14 +54,17 @@ void print_uuid(const ble_uuid_t *uuid); void print_conn_desc(const struct ble_gap_conn_desc *desc); void print_adv_fields(const struct ble_hs_adv_fields *fields); -/** Peer. */ -struct peer_dsc { +/* Peer. */ + +struct peer_dsc +{ SLIST_ENTRY(peer_dsc) next; struct ble_gatt_dsc dsc; }; SLIST_HEAD(peer_dsc_list, peer_dsc); -struct peer_chr { +struct peer_chr +{ SLIST_ENTRY(peer_chr) next; struct ble_gatt_chr chr; @@ -63,7 +72,8 @@ struct peer_chr { }; SLIST_HEAD(peer_chr_list, peer_chr); -struct peer_svc { +struct peer_svc +{ SLIST_ENTRY(peer_svc) next; struct ble_gatt_svc svc; @@ -74,19 +84,23 @@ SLIST_HEAD(peer_svc_list, peer_svc); struct peer; typedef void peer_disc_fn(const struct peer *peer, int status, void *arg); -struct peer { +struct peer +{ SLIST_ENTRY(peer) next; uint16_t conn_handle; - /** List of discovered GATT services. */ + /* List of discovered GATT services. */ + struct peer_svc_list svcs; - /** Keeps track of where we are in the service discovery process. */ + /* Keeps track of where we are in the service discovery process. */ + uint16_t disc_prev_chr_val; struct peer_svc *cur_svc; - /** Callback that gets executed when service discovery completes. */ + /* Callback that gets executed when service discovery completes. */ + peer_disc_fn *disc_cb; void *disc_cb_arg; }; diff --git a/examples/nimble_blecent/misc.c b/examples/nimble_blecent/misc.c index 4180d7049ba..995ed856d55 100644 --- a/examples/nimble_blecent/misc.c +++ b/examples/nimble_blecent/misc.c @@ -18,6 +18,10 @@ * ****************************************************************************/ +/**************************************************************************** + * Included Files + ****************************************************************************/ + #include #include #include @@ -25,186 +29,215 @@ #include "host/ble_uuid.h" #include "blecent.h" +/**************************************************************************** + * Public Functions + ****************************************************************************/ + /** * Utility function to log an array of bytes. */ -void -print_bytes(const uint8_t *bytes, int len) + +void print_bytes(const uint8_t *bytes, int len) { - int i; + int i; - for (i = 0; i < len; i++) { - printf("%s0x%02x", i != 0 ? ":" : "", bytes[i]); + for (i = 0; i < len; i++) + { + printf("%s0x%02x", i != 0 ? ":" : "", bytes[i]); } } -void -print_mbuf(const struct os_mbuf *om) +void print_mbuf(const struct os_mbuf *om) { - int colon; - - colon = 0; - while (om != NULL) { - if (colon) { - printf(":"); - } else { - colon = 1; + int colon; + + colon = 0; + while (om != NULL) + { + if (colon) + { + printf(":"); + } + else + { + colon = 1; } - print_bytes(om->om_data, om->om_len); - om = SLIST_NEXT(om, om_next); + + print_bytes(om->om_data, om->om_len); + om = SLIST_NEXT(om, om_next); } } char * addr_str(const void *addr) { - static char buf[6 * 2 + 5 + 1]; - const uint8_t *u8p; + static char buf[6 * 2 + 5 + 1]; + const uint8_t *u8p; - u8p = addr; - sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", - u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]); + u8p = addr; + sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", + u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]); - return buf; + return buf; } -void -print_uuid(const ble_uuid_t *uuid) +void print_uuid(const ble_uuid_t *uuid) { - char buf[BLE_UUID_STR_LEN]; + char buf[BLE_UUID_STR_LEN]; - printf("%s", ble_uuid_to_str(uuid, buf)); + printf("%s", ble_uuid_to_str(uuid, buf)); } /** * Logs information about a connection to the console. */ -void -print_conn_desc(const struct ble_gap_conn_desc *desc) + +void print_conn_desc(const struct ble_gap_conn_desc *desc) { - printf("handle=%d our_ota_addr_type=%d our_ota_addr=%s ", - desc->conn_handle, desc->our_ota_addr.type, - addr_str(desc->our_ota_addr.val)); - printf("our_id_addr_type=%d our_id_addr=%s ", - desc->our_id_addr.type, addr_str(desc->our_id_addr.val)); - printf("peer_ota_addr_type=%d peer_ota_addr=%s ", - desc->peer_ota_addr.type, addr_str(desc->peer_ota_addr.val)); - printf("peer_id_addr_type=%d peer_id_addr=%s ", - desc->peer_id_addr.type, addr_str(desc->peer_id_addr.val)); - printf("conn_itvl=%d conn_latency=%d supervision_timeout=%d " - "encrypted=%d authenticated=%d bonded=%d", - desc->conn_itvl, desc->conn_latency, - desc->supervision_timeout, - desc->sec_state.encrypted, - desc->sec_state.authenticated, - desc->sec_state.bonded); + printf("handle=%d our_ota_addr_type=%d our_ota_addr=%s ", + desc->conn_handle, desc->our_ota_addr.type, + addr_str(desc->our_ota_addr.val)); + printf("our_id_addr_type=%d our_id_addr=%s ", + desc->our_id_addr.type, addr_str(desc->our_id_addr.val)); + printf("peer_ota_addr_type=%d peer_ota_addr=%s ", + desc->peer_ota_addr.type, addr_str(desc->peer_ota_addr.val)); + printf("peer_id_addr_type=%d peer_id_addr=%s ", + desc->peer_id_addr.type, addr_str(desc->peer_id_addr.val)); + printf("conn_itvl=%d conn_latency=%d supervision_timeout=%d " + "encrypted=%d authenticated=%d bonded=%d", + desc->conn_itvl, desc->conn_latency, + desc->supervision_timeout, + desc->sec_state.encrypted, + desc->sec_state.authenticated, + desc->sec_state.bonded); } - -void -print_adv_fields(const struct ble_hs_adv_fields *fields) +void print_adv_fields(const struct ble_hs_adv_fields *fields) { - char s[BLE_HS_ADV_MAX_SZ]; - const uint8_t *u8p; - int i; + char s[BLE_HS_ADV_MAX_SZ]; + const uint8_t *u8p; + int i; + + if (fields->flags != 0) + { + printf(" flags=0x%02x\n", fields->flags); + } + + if (fields->uuids16 != NULL) + { + printf(" uuids16(%scomplete)=", + fields->uuids16_is_complete ? "" : "in"); + for (i = 0; i < fields->num_uuids16; i++) + { + print_uuid(&fields->uuids16[i].u); + printf(" "); + } - if (fields->flags != 0) { - printf(" flags=0x%02x\n", fields->flags); + printf("\n"); } - if (fields->uuids16 != NULL) { - printf(" uuids16(%scomplete)=", - fields->uuids16_is_complete ? "" : "in"); - for (i = 0; i < fields->num_uuids16; i++) { - print_uuid(&fields->uuids16[i].u); - printf(" "); + if (fields->uuids32 != NULL) + { + printf(" uuids32(%scomplete)=", + fields->uuids32_is_complete ? "" : "in"); + for (i = 0; i < fields->num_uuids32; i++) + { + print_uuid(&fields->uuids32[i].u); + printf(" "); } - printf("\n"); - } - if (fields->uuids32 != NULL) { - printf(" uuids32(%scomplete)=", - fields->uuids32_is_complete ? "" : "in"); - for (i = 0; i < fields->num_uuids32; i++) { - print_uuid(&fields->uuids32[i].u); - printf(" "); - } - printf("\n"); + printf("\n"); } - if (fields->uuids128 != NULL) { - printf(" uuids128(%scomplete)=", - fields->uuids128_is_complete ? "" : "in"); - for (i = 0; i < fields->num_uuids128; i++) { - print_uuid(&fields->uuids128[i].u); - printf(" "); + if (fields->uuids128 != NULL) + { + printf(" uuids128(%scomplete)=", + fields->uuids128_is_complete ? "" : "in"); + for (i = 0; i < fields->num_uuids128; i++) + { + print_uuid(&fields->uuids128[i].u); + printf(" "); } - printf("\n"); + + printf("\n"); } - if (fields->name != NULL) { - assert(fields->name_len < sizeof s - 1); - memcpy(s, fields->name, fields->name_len); - s[fields->name_len] = '\0'; - printf(" name(%scomplete)=%s\n", - fields->name_is_complete ? "" : "in", s); + if (fields->name != NULL) + { + assert(fields->name_len < sizeof s - 1); + memcpy(s, fields->name, fields->name_len); + s[fields->name_len] = '\0'; + printf(" name(%scomplete)=%s\n", + fields->name_is_complete ? "" : "in", s); } - if (fields->tx_pwr_lvl_is_present) { - printf(" tx_pwr_lvl=%d\n", fields->tx_pwr_lvl); + if (fields->tx_pwr_lvl_is_present) + { + printf(" tx_pwr_lvl=%d\n", fields->tx_pwr_lvl); } - if (fields->slave_itvl_range != NULL) { - printf(" slave_itvl_range="); - print_bytes(fields->slave_itvl_range, BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN); - printf("\n"); + if (fields->slave_itvl_range != NULL) + { + printf(" slave_itvl_range="); + print_bytes(fields->slave_itvl_range, BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN); + printf("\n"); } - if (fields->svc_data_uuid16 != NULL) { - printf(" svc_data_uuid16="); - print_bytes(fields->svc_data_uuid16, fields->svc_data_uuid16_len); - printf("\n"); + if (fields->svc_data_uuid16 != NULL) + { + printf(" svc_data_uuid16="); + print_bytes(fields->svc_data_uuid16, fields->svc_data_uuid16_len); + printf("\n"); } - if (fields->public_tgt_addr != NULL) { - printf(" public_tgt_addr="); - u8p = fields->public_tgt_addr; - for (i = 0; i < fields->num_public_tgt_addrs; i++) { - printf("public_tgt_addr=%s ", addr_str(u8p)); - u8p += BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN; + if (fields->public_tgt_addr != NULL) + { + printf(" public_tgt_addr="); + u8p = fields->public_tgt_addr; + for (i = 0; i < fields->num_public_tgt_addrs; i++) + { + printf("public_tgt_addr=%s ", addr_str(u8p)); + u8p += BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN; } - printf("\n"); + + printf("\n"); } - if (fields->appearance_is_present) { - printf(" appearance=0x%04x\n", fields->appearance); + if (fields->appearance_is_present) + { + printf(" appearance=0x%04x\n", fields->appearance); } - if (fields->adv_itvl_is_present) { - printf(" adv_itvl=0x%04x\n", fields->adv_itvl); + if (fields->adv_itvl_is_present) + { + printf(" adv_itvl=0x%04x\n", fields->adv_itvl); } - if (fields->svc_data_uuid32 != NULL) { - printf(" svc_data_uuid32="); - print_bytes(fields->svc_data_uuid32, fields->svc_data_uuid32_len); - printf("\n"); + if (fields->svc_data_uuid32 != NULL) + { + printf(" svc_data_uuid32="); + print_bytes(fields->svc_data_uuid32, fields->svc_data_uuid32_len); + printf("\n"); } - if (fields->svc_data_uuid128 != NULL) { - printf(" svc_data_uuid128="); - print_bytes(fields->svc_data_uuid128, fields->svc_data_uuid128_len); - printf("\n"); + if (fields->svc_data_uuid128 != NULL) + { + printf(" svc_data_uuid128="); + print_bytes(fields->svc_data_uuid128, fields->svc_data_uuid128_len); + printf("\n"); } - if (fields->uri != NULL) { - printf(" uri="); - print_bytes(fields->uri, fields->uri_len); - printf("\n"); + if (fields->uri != NULL) + { + printf(" uri="); + print_bytes(fields->uri, fields->uri_len); + printf("\n"); } - if (fields->mfg_data != NULL) { - printf(" mfg_data="); - print_bytes(fields->mfg_data, fields->mfg_data_len); - printf("\n"); + if (fields->mfg_data != NULL) + { + printf(" mfg_data="); + print_bytes(fields->mfg_data, fields->mfg_data_len); + printf("\n"); } } diff --git a/examples/nimble_blecent/nimble_blecent_main.c b/examples/nimble_blecent/nimble_blecent_main.c index 161021b03cc..b965accc2ca 100644 --- a/examples/nimble_blecent/nimble_blecent_main.c +++ b/examples/nimble_blecent/nimble_blecent_main.c @@ -18,28 +18,35 @@ * ****************************************************************************/ +/**************************************************************************** + * Included Files + ****************************************************************************/ + #include #include /* BLE */ + #include "nimble/ble.h" #include "nimble/nimble_port.h" #include "host/ble_hs.h" #include "host/util/util.h" /* Mandatory services. */ + #include "services/gap/ble_svc_gap.h" #include "services/gatt/ble_svc_gatt.h" #include "services/bas/ble_svc_bas.h" /* Application-specified header. */ + #include "blecent.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -#define BLECENT_BAS_UUID 0x180f +#define BLECENT_BAS_UUID 0x180f #define BLECENT_CHR_BAS_BL_UUID 0x2a19 /* Not used now */ @@ -53,7 +60,6 @@ ****************************************************************************/ void ble_hci_sock_ack_handler(FAR void *param); -//void ble_hci_sock_init(void); void ble_hci_sock_set_device(int dev); /**************************************************************************** @@ -66,54 +72,59 @@ static int blecent_gap_event(struct ble_gap_event *event, void *arg); * Application callback. Called when the read of the ANS Supported New Alert * Category characteristic has completed. */ + static int blecent_on_read(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { - printf("Read complete; status=%d conn_handle=%d", error->status, - conn_handle); - if (error->status == 0) { - printf(" attr_handle=%d value=", attr->handle); - print_mbuf(attr->om); - } - printf("\n"); - - return 0; + printf("Read complete; status=%d conn_handle=%d", error->status, + conn_handle); + if (error->status == 0) + { + printf(" attr_handle=%d value=", attr->handle); + print_mbuf(attr->om); + } + printf("\n"); + + return 0; } /** - * Application callback. Called when the write to the ANS Alert Notification + * Application callback. Called when the write to the ANS Alert Notification * Control Point characteristic has completed. */ + static int blecent_on_write(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { - printf("Write complete; status=%d conn_handle=%d attr_handle=%d\n", - error->status, conn_handle, attr->handle); + printf("Write complete; status=%d conn_handle=%d attr_handle=%d\n", + error->status, conn_handle, attr->handle); - return 0; + return 0; } /** - * Application callback. Called when the attempt to subscribe to notifications - * for the ANS Unread Alert Status characteristic has completed. + * Application callback. Called when the attempt to subscribe to + * notifications for the ANS Unread Alert Status characteristic + * has completed. */ + static int blecent_on_subscribe(uint16_t conn_handle, const struct ble_gatt_error *error, struct ble_gatt_attr *attr, void *arg) { - printf("Subscribe complete; status=%d conn_handle=%d " - "attr_handle=%d\n", - error->status, conn_handle, attr->handle); + printf("Subscribe complete; status=%d conn_handle=%d " + "attr_handle=%d\n", + error->status, conn_handle, attr->handle); - return 0; + return 0; } /** @@ -128,151 +139,178 @@ blecent_on_subscribe(uint16_t conn_handle, * notification service! When this happens, or if a GATT procedure fails, * this function immediately terminates the connection. */ + static void blecent_read_write_subscribe(const struct peer *peer) { - const struct peer_chr *chr; - const struct peer_dsc *dsc; - uint8_t value[2]; - int rc; - - /* Read the supported-new-alert-category characteristic. */ - chr = peer_chr_find_uuid(peer, - BLE_UUID16_DECLARE(BLECENT_SVC_ALERT_UUID), - BLE_UUID16_DECLARE(BLECENT_CHR_SUP_NEW_ALERT_CAT_UUID)); - if (chr == NULL) { - printf("Error: Peer doesn't support the Supported New " - "Alert Category characteristic\n"); - goto err; - } + const struct peer_chr *chr; + const struct peer_dsc *dsc; + uint8_t value[2]; + int rc; + + /* Read the supported-new-alert-category characteristic. */ + + chr = peer_chr_find_uuid(peer, + BLE_UUID16_DECLARE(BLECENT_SVC_ALERT_UUID), + BLE_UUID16_DECLARE(BLECENT_CHR_SUP_NEW_ALERT_CAT_UUID)); + if (chr == NULL) + { + printf("Error: Peer doesn't support the Supported New " + "Alert Category characteristic\n"); + goto err; + } + + rc = ble_gattc_read(peer->conn_handle, chr->chr.val_handle, + blecent_on_read, NULL); + if (rc != 0) + { + printf("Error: Failed to read characteristic; rc=%d\n", + rc); + goto err; + } + + /* Write two bytes (99, 100) to the alert-notification-control-point + * characteristic. + */ + + chr = peer_chr_find_uuid(peer, + BLE_UUID16_DECLARE(BLECENT_SVC_ALERT_UUID), + BLE_UUID16_DECLARE(BLECENT_CHR_ALERT_NOT_CTRL_PT)); + if (chr == NULL) + { + printf("Error: Peer doesn't support the Alert " + "Notification Control Point characteristic\n"); + goto err; + } + + value[0] = 99; + value[1] = 100; + rc = ble_gattc_write_flat(peer->conn_handle, chr->chr.val_handle, + value, sizeof value, blecent_on_write, NULL); + if (rc != 0) + { + printf("Error: Failed to write characteristic; rc=%d\n", + rc); + } + + /* Subscribe to notifications for the Battery Level characteristic. + * A central enables notifications by writing two bytes (1, 0) to the + * characteristic's client-characteristic-configuration-descriptor (CCCD). + */ + + dsc = peer_dsc_find_uuid(peer, + BLE_UUID16_DECLARE(BLE_SVC_BAS_UUID16), + BLE_UUID16_DECLARE(BLE_SVC_BAS_CHR_UUID16_BATTERY_LEVEL), + BLE_UUID16_DECLARE(BLE_GATT_DSC_CLT_CFG_UUID16)); + if (dsc == NULL) + { + printf("Error: Peer lacks a CCCD for the \ + Battery Level characteristic\n"); + goto err; + } + + value[0] = 1; + value[1] = 0; + rc = ble_gattc_write_flat(peer->conn_handle, dsc->dsc.handle, + value, sizeof value, blecent_on_subscribe, NULL); + if (rc != 0) + { + printf("Error: Failed to subscribe to characteristic; " + "rc=%d\n", + rc); + goto err; + } + + return; - rc = ble_gattc_read(peer->conn_handle, chr->chr.val_handle, - blecent_on_read, NULL); - if (rc != 0) { - printf("Error: Failed to read characteristic; rc=%d\n", - rc); - goto err; - } - - /* Write two bytes (99, 100) to the alert-notification-control-point - * characteristic. - */ - chr = peer_chr_find_uuid(peer, - BLE_UUID16_DECLARE(BLECENT_SVC_ALERT_UUID), - BLE_UUID16_DECLARE(BLECENT_CHR_ALERT_NOT_CTRL_PT)); - if (chr == NULL) { - printf("Error: Peer doesn't support the Alert " - "Notification Control Point characteristic\n"); - goto err; - } - - value[0] = 99; - value[1] = 100; - rc = ble_gattc_write_flat(peer->conn_handle, chr->chr.val_handle, - value, sizeof value, blecent_on_write, NULL); - if (rc != 0) { - printf("Error: Failed to write characteristic; rc=%d\n", - rc); - } - - /* Subscribe to notifications for the Battery Level characteristic. - * A central enables notifications by writing two bytes (1, 0) to the - * characteristic's client-characteristic-configuration-descriptor (CCCD). - */ - dsc = peer_dsc_find_uuid(peer, - BLE_UUID16_DECLARE(BLE_SVC_BAS_UUID16), - BLE_UUID16_DECLARE(BLE_SVC_BAS_CHR_UUID16_BATTERY_LEVEL), - BLE_UUID16_DECLARE(BLE_GATT_DSC_CLT_CFG_UUID16)); - if (dsc == NULL) { - printf("Error: Peer lacks a CCCD for the Battery Level characteristic\n"); - goto err; - } - - value[0] = 1; - value[1] = 0; - rc = ble_gattc_write_flat(peer->conn_handle, dsc->dsc.handle, - value, sizeof value, blecent_on_subscribe, NULL); - if (rc != 0) { - printf("Error: Failed to subscribe to characteristic; " - "rc=%d\n", rc); - goto err; - } +err: - return; + /* Terminate the connection. */ -err: - /* Terminate the connection. */ - ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); } /** * Called when service discovery of the specified peer has completed. */ + static void blecent_on_disc_complete(const struct peer *peer, int status, void *arg) { + if (status != 0) + { + /* Service discovery failed. Terminate the connection. */ - if (status != 0) { - /* Service discovery failed. Terminate the connection. */ - printf("Error: Service discovery failed; status=%d " - "conn_handle=%d\n", status, peer->conn_handle); - ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); - return; + printf("Error: Service discovery failed; status=%d " + "conn_handle=%d\n", + status, peer->conn_handle); + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return; } - /* Service discovery has completed successfully. Now we have a complete - * list of services, characteristics, and descriptors that the peer - * supports. - */ - printf("Service discovery complete; status=%d " - "conn_handle=%d\n", status, peer->conn_handle); + /* Service discovery has completed successfully. Now we have a complete + * list of services, characteristics, and descriptors that the peer + * supports. + */ - /* Now perform three concurrent GATT procedures against the peer: read, - * write, and subscribe to notifications. - */ - blecent_read_write_subscribe(peer); + printf("Service discovery complete; status=%d " + "conn_handle=%d\n", + status, peer->conn_handle); + + /* Now perform three concurrent GATT procedures against the peer: read, + * write, and subscribe to notifications. + */ + + blecent_read_write_subscribe(peer); } /** * Initiates the GAP general discovery procedure. */ + static void blecent_scan(void) { - uint8_t own_addr_type; - struct ble_gap_disc_params disc_params; - int rc; - - /* Figure out address to use while advertising (no privacy for now) */ - rc = ble_hs_id_infer_auto(0, &own_addr_type); - if (rc != 0) { - printf("error determining address type; rc=%d\n", rc); - return; - } + uint8_t own_addr_type; + struct ble_gap_disc_params disc_params; + int rc; - /* Tell the controller to filter duplicates; we don't want to process - * repeated advertisements from the same device. - */ - disc_params.filter_duplicates = 1; + /* Figure out address to use while advertising (no privacy for now) */ - /** - * Perform a passive scan. I.e., don't send follow-up scan requests to - * each advertiser. - */ - disc_params.passive = 1; - - /* Use defaults for the rest of the parameters. */ - disc_params.itvl = 0; - disc_params.window = 0; - disc_params.filter_policy = 0; - disc_params.limited = 0; - - rc = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &disc_params, - blecent_gap_event, NULL); - if (rc != 0) { - printf("Error initiating GAP discovery procedure; rc=%d\n", - rc); + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) + { + printf("error determining address type; rc=%d\n", rc); + return; } + + /* Tell the controller to filter duplicates; we don't want to process + * repeated advertisements from the same device. + */ + + disc_params.filter_duplicates = 1; + + /** + * Perform a passive scan. I.e., don't send follow-up scan requests to + * each advertiser. + */ + + disc_params.passive = 1; + + /* Use defaults for the rest of the parameters. */ + + disc_params.itvl = 0; + disc_params.window = 0; + disc_params.filter_policy = 0; + disc_params.limited = 0; + + rc = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &disc_params, + blecent_gap_event, NULL); + if (rc != 0) + { + printf("Error initiating GAP discovery procedure; rc=%d\n", + rc); + } } /** @@ -280,78 +318,93 @@ blecent_scan(void) * advertisement. The function returns a positive result if the device * advertises connectability and support for the Alert Notification service. */ + static int blecent_should_connect(const struct ble_gap_disc_desc *disc) { - struct ble_hs_adv_fields fields; - int rc; - int i; + struct ble_hs_adv_fields fields; + int rc; + int i; - /* The device has to be advertising connectability. */ - if (disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && - disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) { + /* The device has to be advertising connectability. */ - return 0; + if (disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && + disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) + { + return 0; } - rc = ble_hs_adv_parse_fields(&fields, disc->data, disc->length_data); - if (rc != 0) { - return 0; + rc = ble_hs_adv_parse_fields(&fields, disc->data, disc->length_data); + if (rc != 0) + { + return 0; } - /* The device has to advertise support for the Alert Notification - * service (0x1811). - */ - for (i = 0; i < fields.num_uuids16; i++) { - if (ble_uuid_u16(&fields.uuids16[i].u) == BLECENT_SVC_ALERT_UUID) { - return 1; + /* The device has to advertise support for the Alert Notification + * service (0x1811). + */ + + for (i = 0; i < fields.num_uuids16; i++) + { + if (ble_uuid_u16(&fields.uuids16[i].u) == BLECENT_SVC_ALERT_UUID) + { + return 1; } } - return 0; + return 0; } /** * Connects to the sender of the specified advertisement of it looks - * interesting. A device is "interesting" if it advertises connectability and - * support for the Alert Notification service. + * interesting. A device is "interesting" if it advertises + * connectability and support for the Alert Notification service. */ + static void blecent_connect_if_interesting(const struct ble_gap_disc_desc *disc) { - uint8_t own_addr_type; - int rc; + uint8_t own_addr_type; + int rc; - /* Don't do anything if we don't care about this advertiser. */ - if (!blecent_should_connect(disc)) { - return; - } + /* Don't do anything if we don't care about this advertiser. */ - /* Scanning must be stopped before a connection can be initiated. */ - rc = ble_gap_disc_cancel(); - if (rc != 0) { - printf("Failed to cancel scan; rc=%d\n", rc); - return; - } + if (!blecent_should_connect(disc)) + { + return; + } - /* Figure out address to use for connect (no privacy for now) */ - rc = ble_hs_id_infer_auto(0, &own_addr_type); - if (rc != 0) { - printf("error determining address type; rc=%d\n", rc); - return; - } + /* Scanning must be stopped before a connection can be initiated. */ - /* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for - * timeout. - */ - rc = ble_gap_connect(own_addr_type, &disc->addr, 30000, NULL, - blecent_gap_event, NULL); - if (rc != 0) { - printf("Error: Failed to connect to device; addr_type=%d " - "addr=%s\n; rc=%d", - disc->addr.type, addr_str(disc->addr.val), rc); - return; - } + rc = ble_gap_disc_cancel(); + if (rc != 0) + { + printf("Failed to cancel scan; rc=%d\n", rc); + return; + } + + /* Figure out address to use for connect (no privacy for now) */ + + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) + { + printf("error determining address type; rc=%d\n", rc); + return; + } + + /* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for + * timeout. + */ + + rc = ble_gap_connect(own_addr_type, &disc->addr, 30000, NULL, + blecent_gap_event, NULL); + if (rc != 0) + { + printf("Error: Failed to connect to device; addr_type=%d " + "addr=%s\n; rc=%d", + disc->addr.type, addr_str(disc->addr.val), rc); + return; + } } /** @@ -368,161 +421,188 @@ blecent_connect_if_interesting(const struct ble_gap_disc_desc *disc) * of the return code is specific to the * particular GAP event being signalled. */ + static int blecent_gap_event(struct ble_gap_event *event, void *arg) { - struct ble_gap_conn_desc desc; - struct ble_hs_adv_fields fields; - int rc; - - switch (event->type) { - case BLE_GAP_EVENT_DISC: - rc = ble_hs_adv_parse_fields(&fields, event->disc.data, - event->disc.length_data); - if (rc != 0) { - return 0; - } + struct ble_gap_conn_desc desc; + struct ble_hs_adv_fields fields; + int rc; + + switch (event->type) + { + case BLE_GAP_EVENT_DISC: + rc = ble_hs_adv_parse_fields(&fields, event->disc.data, + event->disc.length_data); + if (rc != 0) + { + return 0; + } - /* An advertisment report was received during GAP discovery. */ - print_adv_fields(&fields); + /* An advertisment report was received during GAP discovery. */ - /* Try to connect to the advertiser if it looks interesting. */ - blecent_connect_if_interesting(&event->disc); - return 0; + print_adv_fields(&fields); - case BLE_GAP_EVENT_CONNECT: - /* A new connection was established or a connection attempt failed. */ - if (event->connect.status == 0) { - /* Connection successfully established. */ - printf("Connection established "); - - rc = ble_gap_conn_find(event->connect.conn_handle, &desc); - assert(rc == 0); - print_conn_desc(&desc); - printf("\n"); - - /* Remember peer. */ - rc = peer_add(event->connect.conn_handle); - if (rc != 0) { - printf("Failed to add peer; rc=%d\n", rc); - return 0; - } - - /* Perform service discovery. */ - rc = peer_disc_all(event->connect.conn_handle, - blecent_on_disc_complete, NULL); - if (rc != 0) { - printf("Failed to discover services; rc=%d\n", rc); - return 0; - } - } else { - /* Connection attempt failed; resume scanning. */ - printf("Error: Connection failed; status=%d\n", - event->connect.status); - blecent_scan(); - } + /* Try to connect to the advertiser if it looks interesting. */ - return 0; + blecent_connect_if_interesting(&event->disc); + return 0; - case BLE_GAP_EVENT_DISCONNECT: - /* Connection terminated. */ - printf("disconnect; reason=%d ", event->disconnect.reason); - print_conn_desc(&event->disconnect.conn); - printf("\n"); + case BLE_GAP_EVENT_CONNECT: - /* Forget about peer. */ - peer_delete(event->disconnect.conn.conn_handle); + /* A new connection was established or a connection attempt failed. */ - /* Resume scanning. */ - blecent_scan(); - return 0; + if (event->connect.status == 0) + { + /* Connection successfully established. */ - case BLE_GAP_EVENT_DISC_COMPLETE: - printf("discovery complete; reason=%d\n", - event->disc_complete.reason); - return 0; + printf("Connection established "); - case BLE_GAP_EVENT_ENC_CHANGE: - /* Encryption has been enabled or disabled for this connection. */ - printf("encryption change event; status=%d ", - event->enc_change.status); - rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc); - assert(rc == 0); - print_conn_desc(&desc); - return 0; + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + assert(rc == 0); + print_conn_desc(&desc); + printf("\n"); - case BLE_GAP_EVENT_NOTIFY_RX: - /* Peer sent us a notification or indication. */ - printf("received %s; conn_handle=%d attr_handle=%d " - "attr_len=%d\n", - event->notify_rx.indication ? - "indication" : - "notification", - event->notify_rx.conn_handle, - event->notify_rx.attr_handle, - OS_MBUF_PKTLEN(event->notify_rx.om)); - - uint8_t notif_data[100]; /* Size depending on the actual size of the notification data you have */ - uint16_t notif_len; - int offset = 0; - notif_len = OS_MBUF_PKTLEN(event->notify_rx.om); - os_mbuf_copydata(event->notify_rx.om, offset, notif_len, notif_data); - - printf("notification data: "); - for (int i = 0; i < notif_len; i++) - { - printf("%02d ", notif_data[i]); - } - printf("\n"); + /* Remember peer. */ - /* Attribute data is contained in event->notify_rx.attr_data. */ + rc = peer_add(event->connect.conn_handle); + if (rc != 0) + { + printf("Failed to add peer; rc=%d\n", rc); return 0; + } - case BLE_GAP_EVENT_MTU: - printf("mtu update event; conn_handle=%d cid=%d mtu=%d\n", - event->mtu.conn_handle, - event->mtu.channel_id, - event->mtu.value); + /* Perform service discovery. */ + + rc = peer_disc_all(event->connect.conn_handle, + blecent_on_disc_complete, NULL); + if (rc != 0) + { + printf("Failed to discover services; rc=%d\n", rc); return 0; + } + } + else + { + /* Connection attempt failed; resume scanning. */ - case BLE_GAP_EVENT_REPEAT_PAIRING: - /* We already have a bond with the peer, but it is attempting to - * establish a new secure link. This app sacrifices security for - * convenience: just throw away the old bond and accept the new link. - */ + printf("Error: Connection failed; status=%d\n", + event->connect.status); + blecent_scan(); + } - /* Delete the old bond. */ - rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc); - assert(rc == 0); - ble_store_util_delete_peer(&desc.peer_id_addr); + return 0; - /* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should - * continue with the pairing operation. - */ - return BLE_GAP_REPEAT_PAIRING_RETRY; + case BLE_GAP_EVENT_DISCONNECT: - default: - return 0; + /* Connection terminated. */ + + printf("disconnect; reason=%d ", event->disconnect.reason); + print_conn_desc(&event->disconnect.conn); + printf("\n"); + + /* Forget about peer. */ + + peer_delete(event->disconnect.conn.conn_handle); + + /* Resume scanning. */ + + blecent_scan(); + return 0; + + case BLE_GAP_EVENT_DISC_COMPLETE: + printf("discovery complete; reason=%d\n", + event->disc_complete.reason); + return 0; + + case BLE_GAP_EVENT_ENC_CHANGE: + + /* Encryption has been enabled or disabled for this connection. */ + + printf("encryption change event; status=%d ", + event->enc_change.status); + rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc); + assert(rc == 0); + print_conn_desc(&desc); + return 0; + + case BLE_GAP_EVENT_NOTIFY_RX: + + /* Peer sent us a notification or indication. */ + + printf("received %s; conn_handle=%d attr_handle=%d " + "attr_len=%d\n", + event->notify_rx.indication ? "indication" : "notification", + event->notify_rx.conn_handle, + event->notify_rx.attr_handle, + OS_MBUF_PKTLEN(event->notify_rx.om)); + + uint8_t notif_data[100]; /* Size depending on the actual size of the notification data you have */ + uint16_t notif_len; + int offset = 0; + notif_len = OS_MBUF_PKTLEN(event->notify_rx.om); + os_mbuf_copydata(event->notify_rx.om, offset, notif_len, notif_data); + + printf("notification data: "); + for (int i = 0; i < notif_len; i++) + { + printf("%02d ", notif_data[i]); } + printf("\n"); + + /* Attribute data is contained in event->notify_rx.attr_data. */ + + return 0; + + case BLE_GAP_EVENT_MTU: + printf("mtu update event; conn_handle=%d cid=%d mtu=%d\n", + event->mtu.conn_handle, + event->mtu.channel_id, + event->mtu.value); + return 0; + + case BLE_GAP_EVENT_REPEAT_PAIRING: + /* We already have a bond with the peer, but it is attempting to + * establish a new secure link. This app sacrifices security for + * convenience: just throw away the old bond and accept the new link. + */ + + /* Delete the old bond. */ + + rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc); + assert(rc == 0); + ble_store_util_delete_peer(&desc.peer_id_addr); + + /* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should + * continue with the pairing operation. + */ + + return BLE_GAP_REPEAT_PAIRING_RETRY; + + default: + return 0; + } } static void blecent_on_reset(int reason) { - printf("Resetting state; reason=%d\n", reason); + printf("Resetting state; reason=%d\n", reason); } static void blecent_on_sync(void) { - int rc; + int rc; - /* Make sure we have proper identity address set (public preferred) */ - rc = ble_hs_util_ensure_addr(0); - assert(rc == 0); + /* Make sure we have proper identity address set (public preferred) */ - /* Begin scanning for a peripheral to connect to. */ - blecent_scan(); + rc = ble_hs_util_ensure_addr(0); + assert(rc == 0); + + /* Begin scanning for a peripheral to connect to. */ + + blecent_scan(); } /**************************************************************************** @@ -531,8 +611,8 @@ blecent_on_sync(void) static void nimble_host_task(FAR void *param) { - ble_svc_gap_device_name_set("NuttX NimBLE CENT"); - nimble_port_run(); + ble_svc_gap_device_name_set("NuttX NimBLE CENT"); + nimble_port_run(); } /**************************************************************************** @@ -541,8 +621,8 @@ static void nimble_host_task(FAR void *param) static FAR void *ble_hci_sock_task(FAR void *param) { - ble_hci_sock_ack_handler(param); - return NULL; + ble_hci_sock_ack_handler(param); + return NULL; } /**************************************************************************** @@ -551,8 +631,8 @@ static FAR void *ble_hci_sock_task(FAR void *param) static FAR void *ble_host_task(FAR void *param) { - nimble_host_task(param); - return NULL; + nimble_host_task(param); + return NULL; } /**************************************************************************** @@ -562,67 +642,69 @@ static FAR void *ble_host_task(FAR void *param) /**************************************************************************** * Name: nimble_main ****************************************************************************/ + int main(int argc, char **argv) { - struct ble_npl_task s_task_host; - struct ble_npl_task s_task_hci; - int ret = 0; + struct ble_npl_task s_task_host; + struct ble_npl_task s_task_hci; + int ret = 0; - /* allow to specify custom hci */ + /* allow to specify custom hci */ - if (argc > 1) + if (argc > 1) { - ble_hci_sock_set_device(atoi(argv[1])); + ble_hci_sock_set_device(atoi(argv[1])); } #ifndef CONFIG_NSH_ARCHINIT - /* Perform architecture-specific initialization */ + /* Perform architecture-specific initialization */ - boardctl(BOARDIOC_INIT, 0); + boardctl(BOARDIOC_INIT, 0); #endif #ifndef CONFIG_NSH_NETINIT - /* Bring up the network */ + /* Bring up the network */ - netinit_bringup(); + netinit_bringup(); #endif - nimble_port_init(); - //ble_hci_sock_init(); + nimble_port_init(); + + /* Configure the host. */ - /* Configure the host. */ - ble_hs_cfg.reset_cb = blecent_on_reset; - ble_hs_cfg.sync_cb = blecent_on_sync; - ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + ble_hs_cfg.reset_cb = blecent_on_reset; + ble_hs_cfg.sync_cb = blecent_on_sync; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; - /* Initialize data structures to track connected peers. */ - ret = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64); - assert(ret == 0); + /* Initialize data structures to track connected peers. */ - /* Create task which handles HCI socket */ + ret = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64); + assert(ret == 0); - ret = ble_npl_task_init(&s_task_hci, "hci_sock", ble_hci_sock_task, - NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, - TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); - if (ret != 0) + /* Create task which handles HCI socket */ + + ret = ble_npl_task_init(&s_task_hci, "hci_sock", ble_hci_sock_task, + NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, + TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); + if (ret != 0) { - printf("ERROR: starting hci task: %i\n", ret); + printf("ERROR: starting hci task: %i\n", ret); } - /* Create task which handles default event queue for host stack. */ + /* Create task which handles default event queue for host stack. */ - ret = ble_npl_task_init(&s_task_host, "ble_host", ble_host_task, - NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, - TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); - if (ret != 0) + ret = ble_npl_task_init(&s_task_host, "ble_host", ble_host_task, + NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, + TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); + if (ret != 0) { - printf("ERROR: starting ble task: %i\n", ret); + printf("ERROR: starting ble task: %i\n", ret); } - while (true) + while (true) { - sleep(1); + sleep(1); } - return 0; + return 0; } diff --git a/examples/nimble_blecent/peer.c b/examples/nimble_blecent/peer.c index 887a7a6f77e..97a9125b9ce 100644 --- a/examples/nimble_blecent/peer.c +++ b/examples/nimble_blecent/peer.c @@ -18,6 +18,10 @@ * ****************************************************************************/ +/**************************************************************************** + * Included Files + ****************************************************************************/ + #include #include #include "host/ble_hs.h" @@ -41,13 +45,11 @@ peer_svc_find_range(struct peer *peer, uint16_t attr_handle); static struct peer_svc * peer_svc_find(struct peer *peer, uint16_t svc_start_handle, struct peer_svc **out_prev); -int -peer_svc_is_empty(const struct peer_svc *svc); +int peer_svc_is_empty(const struct peer_svc *svc); uint16_t chr_end_handle(const struct peer_svc *svc, const struct peer_chr *chr); -int -chr_is_empty(const struct peer_svc *svc, const struct peer_chr *chr); +int chr_is_empty(const struct peer_svc *svc, const struct peer_chr *chr); static struct peer_chr * peer_chr_find(const struct peer_svc *svc, uint16_t chr_def_handle, struct peer_chr **out_prev); @@ -59,157 +61,188 @@ peer_dsc_disced(uint16_t conn_handle, const struct ble_gatt_error *error, uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc, void *arg); -static struct peer * -peer_find(uint16_t conn_handle) +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +static struct peer *peer_find(uint16_t conn_handle) { - struct peer *peer; + struct peer *peer; - SLIST_FOREACH(peer, &peers, next) { - if (peer->conn_handle == conn_handle) { - return peer; + SLIST_FOREACH(peer, &peers, next) + { + if (peer->conn_handle == conn_handle) + { + return peer; } } - return NULL; + return NULL; } -static void -peer_disc_complete(struct peer *peer, int rc) +static void peer_disc_complete(struct peer *peer, int rc) { - peer->disc_prev_chr_val = 0; + peer->disc_prev_chr_val = 0; + + /* Notify caller that discovery has completed. */ - /* Notify caller that discovery has completed. */ - if (peer->disc_cb != NULL) { - peer->disc_cb(peer, rc, peer->disc_cb_arg); + if (peer->disc_cb != NULL) + { + peer->disc_cb(peer, rc, peer->disc_cb_arg); } } static struct peer_dsc * peer_dsc_find_prev(const struct peer_chr *chr, uint16_t dsc_handle) { - struct peer_dsc *prev; - struct peer_dsc *dsc; - - prev = NULL; - SLIST_FOREACH(dsc, &chr->dscs, next) { - if (dsc->dsc.handle >= dsc_handle) { - break; + struct peer_dsc *prev; + struct peer_dsc *dsc; + + prev = NULL; + SLIST_FOREACH(dsc, &chr->dscs, next) + { + if (dsc->dsc.handle >= dsc_handle) + { + break; } - prev = dsc; + prev = dsc; } - return prev; + return prev; } static struct peer_dsc * peer_dsc_find(const struct peer_chr *chr, uint16_t dsc_handle, struct peer_dsc **out_prev) { - struct peer_dsc *prev; - struct peer_dsc *dsc; + struct peer_dsc *prev; + struct peer_dsc *dsc; - prev = peer_dsc_find_prev(chr, dsc_handle); - if (prev == NULL) { - dsc = SLIST_FIRST(&chr->dscs); - } else { - dsc = SLIST_NEXT(prev, next); + prev = peer_dsc_find_prev(chr, dsc_handle); + if (prev == NULL) + { + dsc = SLIST_FIRST(&chr->dscs); + } + else + { + dsc = SLIST_NEXT(prev, next); } - if (dsc != NULL && dsc->dsc.handle != dsc_handle) { - dsc = NULL; + if (dsc != NULL && dsc->dsc.handle != dsc_handle) + { + dsc = NULL; } - if (out_prev != NULL) { - *out_prev = prev; + if (out_prev != NULL) + { + *out_prev = prev; } - return dsc; + + return dsc; } static int peer_dsc_add(struct peer *peer, uint16_t chr_val_handle, const struct ble_gatt_dsc *gatt_dsc) { - struct peer_dsc *prev; - struct peer_dsc *dsc; - struct peer_svc *svc; - struct peer_chr *chr; + struct peer_dsc *prev; + struct peer_dsc *dsc; + struct peer_svc *svc; + struct peer_chr *chr; + + svc = peer_svc_find_range(peer, chr_val_handle); + if (svc == NULL) + { + /* Can't find service for discovered descriptor; + * this shouldn't happen. + */ - svc = peer_svc_find_range(peer, chr_val_handle); - if (svc == NULL) { - /* Can't find service for discovered descriptor; this shouldn't - * happen. - */ - assert(0); - return BLE_HS_EUNKNOWN; + assert(0); + return BLE_HS_EUNKNOWN; } - chr = peer_chr_find(svc, chr_val_handle, NULL); - if (chr == NULL) { - /* Can't find characteristic for discovered descriptor; this shouldn't - * happen. - */ - assert(0); - return BLE_HS_EUNKNOWN; + chr = peer_chr_find(svc, chr_val_handle, NULL); + if (chr == NULL) + { + /* Can't find characteristic for discovered descriptor; + * this shouldn't happen. + */ + + assert(0); + return BLE_HS_EUNKNOWN; } - dsc = peer_dsc_find(chr, gatt_dsc->handle, &prev); - if (dsc != NULL) { - /* Descriptor already discovered. */ - return 0; + dsc = peer_dsc_find(chr, gatt_dsc->handle, &prev); + if (dsc != NULL) + { + /* Descriptor already discovered. */ + + return 0; } - dsc = os_memblock_get(&peer_dsc_pool); - if (dsc == NULL) { - /* Out of memory. */ - return BLE_HS_ENOMEM; + dsc = os_memblock_get(&peer_dsc_pool); + if (dsc == NULL) + { + /* Out of memory. */ + + return BLE_HS_ENOMEM; } - memset(dsc, 0, sizeof *dsc); - dsc->dsc = *gatt_dsc; + memset(dsc, 0, sizeof *dsc); - if (prev == NULL) { - SLIST_INSERT_HEAD(&chr->dscs, dsc, next); - } else { - SLIST_NEXT(prev, next) = dsc; + dsc->dsc = *gatt_dsc; + + if (prev == NULL) + { + SLIST_INSERT_HEAD(&chr->dscs, dsc, next); + } + else + { + SLIST_NEXT(prev, next) = dsc; } - return 0; + return 0; } static void peer_disc_dscs(struct peer *peer) { - struct peer_chr *chr; - struct peer_svc *svc; - int rc; - - /* Search through the list of discovered characteristics for the first - * characteristic that contains undiscovered descriptors. Then, discover - * all descriptors belonging to that characteristic. - */ - SLIST_FOREACH(svc, &peer->svcs, next) { - SLIST_FOREACH(chr, &svc->chrs, next) { - if (!chr_is_empty(svc, chr) && - SLIST_EMPTY(&chr->dscs) && - peer->disc_prev_chr_val <= chr->chr.def_handle) { - - rc = ble_gattc_disc_all_dscs(peer->conn_handle, - chr->chr.val_handle, - chr_end_handle(svc, chr), - peer_dsc_disced, peer); - if (rc != 0) { - peer_disc_complete(peer, rc); + struct peer_chr *chr; + struct peer_svc *svc; + int rc; + + /* Search through the list of discovered characteristics for the first + * characteristic that contains undiscovered descriptors. + * Then, discover all descriptors belonging to that characteristic. + */ + + SLIST_FOREACH(svc, &peer->svcs, next) + { + SLIST_FOREACH(chr, &svc->chrs, next) + { + if (!chr_is_empty(svc, chr) && + SLIST_EMPTY(&chr->dscs) && + peer->disc_prev_chr_val <= chr->chr.def_handle) + { + rc = ble_gattc_disc_all_dscs(peer->conn_handle, + chr->chr.val_handle, + chr_end_handle(svc, chr), + peer_dsc_disced, peer); + if (rc != 0) + { + peer_disc_complete(peer, rc); } - peer->disc_prev_chr_val = chr->chr.val_handle; - return; + peer->disc_prev_chr_val = chr->chr.val_handle; + return; } } } - /* All descriptors discovered. */ - peer_disc_complete(peer, 0); + /* All descriptors discovered. */ + + peer_disc_complete(peer, 0); } static int @@ -217,592 +250,681 @@ peer_dsc_disced(uint16_t conn_handle, const struct ble_gatt_error *error, uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc, void *arg) { - struct peer *peer; - int rc; - - peer = arg; - assert(peer->conn_handle == conn_handle); - - switch (error->status) { - case 0: - rc = peer_dsc_add(peer, chr_val_handle, dsc); - break; - - case BLE_HS_EDONE: - /* All descriptors in this characteristic discovered; start discovering - * descriptors in the next characteristic. - */ - if (peer->disc_prev_chr_val > 0) { - peer_disc_dscs(peer); - } - rc = 0; - break; + struct peer *peer; + int rc; - default: - /* Error; abort discovery. */ - rc = error->status; - break; - } + peer = arg; + assert(peer->conn_handle == conn_handle); + + switch (error->status) + { + case 0: + rc = peer_dsc_add(peer, chr_val_handle, dsc); + break; + + case BLE_HS_EDONE: + /* All descriptors in this characteristic discovered; + * start discovering descriptors in the next characteristic. + */ + + if (peer->disc_prev_chr_val > 0) + { + peer_disc_dscs(peer); + } + + rc = 0; + break; + + default: - if (rc != 0) { - /* Error; abort discovery. */ - peer_disc_complete(peer, rc); + /* Error; abort discovery. */ + + rc = error->status; + break; + } + + if (rc != 0) + { + /* Error; abort discovery. */ + + peer_disc_complete(peer, rc); } - return rc; + return rc; } uint16_t chr_end_handle(const struct peer_svc *svc, const struct peer_chr *chr) { - const struct peer_chr *next_chr; + const struct peer_chr *next_chr; - next_chr = SLIST_NEXT(chr, next); - if (next_chr != NULL) { - return next_chr->chr.def_handle - 1; - } else { - return svc->svc.end_handle; + next_chr = SLIST_NEXT(chr, next); + if (next_chr != NULL) + { + return next_chr->chr.def_handle - 1; + } + else + { + return svc->svc.end_handle; } } -int -chr_is_empty(const struct peer_svc *svc, const struct peer_chr *chr) +int chr_is_empty(const struct peer_svc *svc, const struct peer_chr *chr) { - return chr_end_handle(svc, chr) <= chr->chr.val_handle; + return chr_end_handle(svc, chr) <= chr->chr.val_handle; } static struct peer_chr * peer_chr_find_prev(const struct peer_svc *svc, uint16_t chr_val_handle) { - struct peer_chr *prev; - struct peer_chr *chr; - - prev = NULL; - SLIST_FOREACH(chr, &svc->chrs, next) { - if (chr->chr.val_handle >= chr_val_handle) { - break; + struct peer_chr *prev; + struct peer_chr *chr; + + prev = NULL; + SLIST_FOREACH(chr, &svc->chrs, next) + { + if (chr->chr.val_handle >= chr_val_handle) + { + break; } - prev = chr; + prev = chr; } - return prev; + return prev; } static struct peer_chr * peer_chr_find(const struct peer_svc *svc, uint16_t chr_val_handle, struct peer_chr **out_prev) { - struct peer_chr *prev; - struct peer_chr *chr; + struct peer_chr *prev; + struct peer_chr *chr; - prev = peer_chr_find_prev(svc, chr_val_handle); - if (prev == NULL) { - chr = SLIST_FIRST(&svc->chrs); - } else { - chr = SLIST_NEXT(prev, next); + prev = peer_chr_find_prev(svc, chr_val_handle); + if (prev == NULL) + { + chr = SLIST_FIRST(&svc->chrs); + } + else + { + chr = SLIST_NEXT(prev, next); } - if (chr != NULL && chr->chr.val_handle != chr_val_handle) { - chr = NULL; + if (chr != NULL && chr->chr.val_handle != chr_val_handle) + { + chr = NULL; } - if (out_prev != NULL) { - *out_prev = prev; + if (out_prev != NULL) + { + *out_prev = prev; } - return chr; + + return chr; } static void peer_chr_delete(struct peer_chr *chr) { - struct peer_dsc *dsc; + struct peer_dsc *dsc; - while ((dsc = SLIST_FIRST(&chr->dscs)) != NULL) { - SLIST_REMOVE_HEAD(&chr->dscs, next); - os_memblock_put(&peer_dsc_pool, dsc); + while ((dsc = SLIST_FIRST(&chr->dscs)) != NULL) + { + SLIST_REMOVE_HEAD(&chr->dscs, next); + os_memblock_put(&peer_dsc_pool, dsc); } - os_memblock_put(&peer_chr_pool, chr); + os_memblock_put(&peer_chr_pool, chr); } static int -peer_chr_add(struct peer *peer, uint16_t svc_start_handle, +peer_chr_add(struct peer *peer, uint16_t svc_start_handle, const struct ble_gatt_chr *gatt_chr) { - struct peer_chr *prev; - struct peer_chr *chr; - struct peer_svc *svc; + struct peer_chr *prev; + struct peer_chr *chr; + struct peer_svc *svc; - svc = peer_svc_find(peer, svc_start_handle, NULL); - if (svc == NULL) { - /* Can't find service for discovered characteristic; this shouldn't - * happen. - */ - assert(0); - return BLE_HS_EUNKNOWN; + svc = peer_svc_find(peer, svc_start_handle, NULL); + if (svc == NULL) + { + /* Can't find service for discovered characteristic; this shouldn't + * happen. + */ + + assert(0); + return BLE_HS_EUNKNOWN; } - chr = peer_chr_find(svc, gatt_chr->def_handle, &prev); - if (chr != NULL) { - /* Characteristic already discovered. */ - return 0; + chr = peer_chr_find(svc, gatt_chr->def_handle, &prev); + if (chr != NULL) + { + /* Characteristic already discovered. */ + + return 0; } - chr = os_memblock_get(&peer_chr_pool); - if (chr == NULL) { - /* Out of memory. */ - return BLE_HS_ENOMEM; + chr = os_memblock_get(&peer_chr_pool); + if (chr == NULL) + { + /* Out of memory. */ + + return BLE_HS_ENOMEM; } - memset(chr, 0, sizeof *chr); - chr->chr = *gatt_chr; + memset(chr, 0, sizeof *chr); + + chr->chr = *gatt_chr; - if (prev == NULL) { - SLIST_INSERT_HEAD(&svc->chrs, chr, next); - } else { - SLIST_NEXT(prev, next) = chr; + if (prev == NULL) + { + SLIST_INSERT_HEAD(&svc->chrs, chr, next); + } + else + { + SLIST_NEXT(prev, next) = chr; } - return 0; + return 0; } static int peer_chr_disced(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_chr *chr, void *arg) { - struct peer *peer; - int rc; - - peer = arg; - assert(peer->conn_handle == conn_handle); - - switch (error->status) { - case 0: - rc = peer_chr_add(peer, peer->cur_svc->svc.start_handle, chr); - break; - - case BLE_HS_EDONE: - /* All characteristics in this service discovered; start discovering - * characteristics in the next service. - */ - if (peer->disc_prev_chr_val > 0) { - peer_disc_chrs(peer); - } - rc = 0; - break; + struct peer *peer; + int rc; - default: - rc = error->status; - break; - } + peer = arg; + assert(peer->conn_handle == conn_handle); + + switch (error->status) + { + case 0: + rc = peer_chr_add(peer, peer->cur_svc->svc.start_handle, chr); + break; + + case BLE_HS_EDONE: + /* All characteristics in this service discovered; start discovering + * characteristics in the next service. + */ + + if (peer->disc_prev_chr_val > 0) + { + peer_disc_chrs(peer); + } + + rc = 0; + break; - if (rc != 0) { - /* Error; abort discovery. */ - peer_disc_complete(peer, rc); + default: + rc = error->status; + break; + } + + if (rc != 0) + { + /* Error; abort discovery. */ + + peer_disc_complete(peer, rc); } - return rc; + return rc; } static void peer_disc_chrs(struct peer *peer) { - struct peer_svc *svc; - int rc; - - /* Search through the list of discovered service for the first service that - * contains undiscovered characteristics. Then, discover all - * characteristics belonging to that service. - */ - SLIST_FOREACH(svc, &peer->svcs, next) { - if (!peer_svc_is_empty(svc) && SLIST_EMPTY(&svc->chrs)) { - peer->cur_svc = svc; - rc = ble_gattc_disc_all_chrs(peer->conn_handle, - svc->svc.start_handle, - svc->svc.end_handle, - peer_chr_disced, peer); - if (rc != 0) { - peer_disc_complete(peer, rc); + struct peer_svc *svc; + int rc; + + /* Search through the list of discovered service for the first + * service that contains undiscovered characteristics. + * Then, discover all characteristics belonging to that service. + */ + + SLIST_FOREACH(svc, &peer->svcs, next) + { + if (!peer_svc_is_empty(svc) && SLIST_EMPTY(&svc->chrs)) + { + peer->cur_svc = svc; + rc = ble_gattc_disc_all_chrs(peer->conn_handle, + svc->svc.start_handle, + svc->svc.end_handle, + peer_chr_disced, peer); + if (rc != 0) + { + peer_disc_complete(peer, rc); } - return; + + return; } } - /* All characteristics discovered. */ - peer_disc_dscs(peer); + /* All characteristics discovered. */ + + peer_disc_dscs(peer); } -int -peer_svc_is_empty(const struct peer_svc *svc) +int peer_svc_is_empty(const struct peer_svc *svc) { - return svc->svc.end_handle <= svc->svc.start_handle; + return svc->svc.end_handle <= svc->svc.start_handle; } static struct peer_svc * peer_svc_find_prev(struct peer *peer, uint16_t svc_start_handle) { - struct peer_svc *prev; - struct peer_svc *svc; - - prev = NULL; - SLIST_FOREACH(svc, &peer->svcs, next) { - if (svc->svc.start_handle >= svc_start_handle) { - break; + struct peer_svc *prev; + struct peer_svc *svc; + + prev = NULL; + SLIST_FOREACH(svc, &peer->svcs, next) + { + if (svc->svc.start_handle >= svc_start_handle) + { + break; } - prev = svc; + prev = svc; } - return prev; + return prev; } static struct peer_svc * peer_svc_find(struct peer *peer, uint16_t svc_start_handle, struct peer_svc **out_prev) { - struct peer_svc *prev; - struct peer_svc *svc; + struct peer_svc *prev; + struct peer_svc *svc; - prev = peer_svc_find_prev(peer, svc_start_handle); - if (prev == NULL) { - svc = SLIST_FIRST(&peer->svcs); - } else { - svc = SLIST_NEXT(prev, next); + prev = peer_svc_find_prev(peer, svc_start_handle); + if (prev == NULL) + { + svc = SLIST_FIRST(&peer->svcs); + } + else + { + svc = SLIST_NEXT(prev, next); } - if (svc != NULL && svc->svc.start_handle != svc_start_handle) { - svc = NULL; + if (svc != NULL && svc->svc.start_handle != svc_start_handle) + { + svc = NULL; } - if (out_prev != NULL) { - *out_prev = prev; + if (out_prev != NULL) + { + *out_prev = prev; } - return svc; + + return svc; } static struct peer_svc * peer_svc_find_range(struct peer *peer, uint16_t attr_handle) { - struct peer_svc *svc; - - SLIST_FOREACH(svc, &peer->svcs, next) { - if (svc->svc.start_handle <= attr_handle && - svc->svc.end_handle >= attr_handle) { - - return svc; + struct peer_svc *svc; + + SLIST_FOREACH(svc, &peer->svcs, next) + { + if (svc->svc.start_handle <= attr_handle && + svc->svc.end_handle >= attr_handle) + { + return svc; } } - return NULL; + return NULL; } const struct peer_svc * peer_svc_find_uuid(const struct peer *peer, const ble_uuid_t *uuid) { - const struct peer_svc *svc; + const struct peer_svc *svc; - SLIST_FOREACH(svc, &peer->svcs, next) { - if (ble_uuid_cmp(&svc->svc.uuid.u, uuid) == 0) { - return svc; + SLIST_FOREACH(svc, &peer->svcs, next) + { + if (ble_uuid_cmp(&svc->svc.uuid.u, uuid) == 0) + { + return svc; } } - return NULL; + return NULL; } const struct peer_chr * peer_chr_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid) { - const struct peer_svc *svc; - const struct peer_chr *chr; + const struct peer_svc *svc; + const struct peer_chr *chr; - svc = peer_svc_find_uuid(peer, svc_uuid); - if (svc == NULL) { - return NULL; + svc = peer_svc_find_uuid(peer, svc_uuid); + if (svc == NULL) + { + return NULL; } - SLIST_FOREACH(chr, &svc->chrs, next) { - if (ble_uuid_cmp(&chr->chr.uuid.u, chr_uuid) == 0) { - return chr; + SLIST_FOREACH(chr, &svc->chrs, next) + { + if (ble_uuid_cmp(&chr->chr.uuid.u, chr_uuid) == 0) + { + return chr; } } - return NULL; + return NULL; } const struct peer_dsc * peer_dsc_find_uuid(const struct peer *peer, const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid, const ble_uuid_t *dsc_uuid) { - const struct peer_chr *chr; - const struct peer_dsc *dsc; + const struct peer_chr *chr; + const struct peer_dsc *dsc; - chr = peer_chr_find_uuid(peer, svc_uuid, chr_uuid); - if (chr == NULL) { - return NULL; + chr = peer_chr_find_uuid(peer, svc_uuid, chr_uuid); + if (chr == NULL) + { + return NULL; } - SLIST_FOREACH(dsc, &chr->dscs, next) { - if (ble_uuid_cmp(&dsc->dsc.uuid.u, dsc_uuid) == 0) { - return dsc; + SLIST_FOREACH(dsc, &chr->dscs, next) + { + if (ble_uuid_cmp(&dsc->dsc.uuid.u, dsc_uuid) == 0) + { + return dsc; } } - return NULL; + return NULL; } static int peer_svc_add(struct peer *peer, const struct ble_gatt_svc *gatt_svc) { - struct peer_svc *prev; - struct peer_svc *svc; + struct peer_svc *prev; + struct peer_svc *svc; + + svc = peer_svc_find(peer, gatt_svc->start_handle, &prev); + if (svc != NULL) + { + /* Service already discovered. */ - svc = peer_svc_find(peer, gatt_svc->start_handle, &prev); - if (svc != NULL) { - /* Service already discovered. */ - return 0; + return 0; } - svc = os_memblock_get(&peer_svc_pool); - if (svc == NULL) { - /* Out of memory. */ - return BLE_HS_ENOMEM; + svc = os_memblock_get(&peer_svc_pool); + if (svc == NULL) + { + /* Out of memory. */ + + return BLE_HS_ENOMEM; } - memset(svc, 0, sizeof *svc); - svc->svc = *gatt_svc; - SLIST_INIT(&svc->chrs); + memset(svc, 0, sizeof *svc); + + svc->svc = *gatt_svc; + SLIST_INIT(&svc->chrs); - if (prev == NULL) { - SLIST_INSERT_HEAD(&peer->svcs, svc, next); - } else { - SLIST_INSERT_AFTER(prev, svc, next); + if (prev == NULL) + { + SLIST_INSERT_HEAD(&peer->svcs, svc, next); + } + else + { + SLIST_INSERT_AFTER(prev, svc, next); } - return 0; + return 0; } static void peer_svc_delete(struct peer_svc *svc) { - struct peer_chr *chr; + struct peer_chr *chr; - while ((chr = SLIST_FIRST(&svc->chrs)) != NULL) { - SLIST_REMOVE_HEAD(&svc->chrs, next); - peer_chr_delete(chr); + while ((chr = SLIST_FIRST(&svc->chrs)) != NULL) + { + SLIST_REMOVE_HEAD(&svc->chrs, next); + peer_chr_delete(chr); } - os_memblock_put(&peer_svc_pool, svc); + os_memblock_put(&peer_svc_pool, svc); } static int peer_svc_disced(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, void *arg) { - struct peer *peer; - int rc; + struct peer *peer; + int rc; - peer = arg; - assert(peer->conn_handle == conn_handle); + peer = arg; + assert(peer->conn_handle == conn_handle); - switch (error->status) { - case 0: - rc = peer_svc_add(peer, service); - break; + switch (error->status) + { + case 0: + rc = peer_svc_add(peer, service); + break; - case BLE_HS_EDONE: - /* All services discovered; start discovering characteristics. */ - if (peer->disc_prev_chr_val > 0) { - peer_disc_chrs(peer); - } - rc = 0; - break; + case BLE_HS_EDONE: - default: - rc = error->status; - break; - } + /* All services discovered; start discovering characteristics. */ - if (rc != 0) { - /* Error; abort discovery. */ - peer_disc_complete(peer, rc); - } + if (peer->disc_prev_chr_val > 0) + { + peer_disc_chrs(peer); + } - return rc; -} + rc = 0; + break; + + default: + rc = error->status; + break; + } + + if (rc != 0) + { + /* Error; abort discovery. */ + peer_disc_complete(peer, rc); + } + + return rc; +} -int -peer_disc_all(uint16_t conn_handle, peer_disc_fn *disc_cb, void *disc_cb_arg) +int peer_disc_all(uint16_t conn_handle, peer_disc_fn *disc_cb, + void *disc_cb_arg) { - struct peer_svc *svc; - struct peer *peer; - int rc; + struct peer_svc *svc; + struct peer *peer; + int rc; - peer = peer_find(conn_handle); - if (peer == NULL) { - return BLE_HS_ENOTCONN; + peer = peer_find(conn_handle); + if (peer == NULL) + { + return BLE_HS_ENOTCONN; } - /* Undiscover everything first. */ - while ((svc = SLIST_FIRST(&peer->svcs)) != NULL) { - SLIST_REMOVE_HEAD(&peer->svcs, next); - peer_svc_delete(svc); + /* Undiscover everything first. */ + + while ((svc = SLIST_FIRST(&peer->svcs)) != NULL) + { + SLIST_REMOVE_HEAD(&peer->svcs, next); + peer_svc_delete(svc); } - peer->disc_prev_chr_val = 1; - peer->disc_cb = disc_cb; - peer->disc_cb_arg = disc_cb_arg; + peer->disc_prev_chr_val = 1; + peer->disc_cb = disc_cb; + peer->disc_cb_arg = disc_cb_arg; - rc = ble_gattc_disc_all_svcs(conn_handle, peer_svc_disced, peer); - if (rc != 0) { - return rc; + rc = ble_gattc_disc_all_svcs(conn_handle, peer_svc_disced, peer); + if (rc != 0) + { + return rc; } - return 0; + return 0; } -int -peer_delete(uint16_t conn_handle) +int peer_delete(uint16_t conn_handle) { - struct peer_svc *svc; - struct peer *peer; - int rc; + struct peer_svc *svc; + struct peer *peer; + int rc; - peer = peer_find(conn_handle); - if (peer == NULL) { - return BLE_HS_ENOTCONN; + peer = peer_find(conn_handle); + if (peer == NULL) + { + return BLE_HS_ENOTCONN; } - SLIST_REMOVE(&peers, peer, peer, next); + SLIST_REMOVE(&peers, peer, peer, next); - while ((svc = SLIST_FIRST(&peer->svcs)) != NULL) { - SLIST_REMOVE_HEAD(&peer->svcs, next); - peer_svc_delete(svc); + while ((svc = SLIST_FIRST(&peer->svcs)) != NULL) + { + SLIST_REMOVE_HEAD(&peer->svcs, next); + peer_svc_delete(svc); } - rc = os_memblock_put(&peer_pool, peer); - if (rc != 0) { - return BLE_HS_EOS; + rc = os_memblock_put(&peer_pool, peer); + if (rc != 0) + { + return BLE_HS_EOS; } - return 0; + return 0; } -int -peer_add(uint16_t conn_handle) +int peer_add(uint16_t conn_handle) { - struct peer *peer; + struct peer *peer; + + /* Make sure the connection handle is unique. */ - /* Make sure the connection handle is unique. */ - peer = peer_find(conn_handle); - if (peer != NULL) { - return BLE_HS_EALREADY; + peer = peer_find(conn_handle); + if (peer != NULL) + { + return BLE_HS_EALREADY; } - peer = os_memblock_get(&peer_pool); - if (peer == NULL) { - /* Out of memory. */ - return BLE_HS_ENOMEM; + peer = os_memblock_get(&peer_pool); + if (peer == NULL) + { + /* Out of memory. */ + + return BLE_HS_ENOMEM; } - memset(peer, 0, sizeof *peer); - peer->conn_handle = conn_handle; + memset(peer, 0, sizeof *peer); + peer->conn_handle = conn_handle; - SLIST_INSERT_HEAD(&peers, peer, next); + SLIST_INSERT_HEAD(&peers, peer, next); - return 0; + return 0; } static void peer_free_mem(void) { - free(peer_mem); - peer_mem = NULL; + free(peer_mem); + peer_mem = NULL; - free(peer_svc_mem); - peer_svc_mem = NULL; + free(peer_svc_mem); + peer_svc_mem = NULL; - free(peer_chr_mem); - peer_chr_mem = NULL; + free(peer_chr_mem); + peer_chr_mem = NULL; - free(peer_dsc_mem); - peer_dsc_mem = NULL; + free(peer_dsc_mem); + peer_dsc_mem = NULL; } -int -peer_init(int max_peers, int max_svcs, int max_chrs, int max_dscs) +int peer_init(int max_peers, int max_svcs, int max_chrs, int max_dscs) { - int rc; + int rc; + + /* Free memory first in case this function gets called more than once. */ - /* Free memory first in case this function gets called more than once. */ - peer_free_mem(); + peer_free_mem(); - peer_mem = malloc( - OS_MEMPOOL_BYTES(max_peers, sizeof (struct peer))); - if (peer_mem == NULL) { - rc = BLE_HS_ENOMEM; - goto err; + peer_mem = malloc( + OS_MEMPOOL_BYTES(max_peers, sizeof(struct peer))); + if (peer_mem == NULL) + { + rc = BLE_HS_ENOMEM; + goto err; } - rc = os_mempool_init(&peer_pool, max_peers, - sizeof (struct peer), peer_mem, - "peer_pool"); - if (rc != 0) { - rc = BLE_HS_EOS; - goto err; + rc = os_mempool_init(&peer_pool, max_peers, + sizeof(struct peer), peer_mem, + "peer_pool"); + if (rc != 0) + { + rc = BLE_HS_EOS; + goto err; } - peer_svc_mem = malloc( - OS_MEMPOOL_BYTES(max_svcs, sizeof (struct peer_svc))); - if (peer_svc_mem == NULL) { - rc = BLE_HS_ENOMEM; - goto err; + peer_svc_mem = malloc( + OS_MEMPOOL_BYTES(max_svcs, sizeof(struct peer_svc))); + if (peer_svc_mem == NULL) + { + rc = BLE_HS_ENOMEM; + goto err; } - rc = os_mempool_init(&peer_svc_pool, max_svcs, - sizeof (struct peer_svc), peer_svc_mem, - "peer_svc_pool"); - if (rc != 0) { - rc = BLE_HS_EOS; - goto err; + rc = os_mempool_init(&peer_svc_pool, max_svcs, + sizeof(struct peer_svc), peer_svc_mem, + "peer_svc_pool"); + if (rc != 0) + { + rc = BLE_HS_EOS; + goto err; } - peer_chr_mem = malloc( - OS_MEMPOOL_BYTES(max_chrs, sizeof (struct peer_chr))); - if (peer_chr_mem == NULL) { - rc = BLE_HS_ENOMEM; - goto err; + peer_chr_mem = malloc( + OS_MEMPOOL_BYTES(max_chrs, sizeof(struct peer_chr))); + if (peer_chr_mem == NULL) + { + rc = BLE_HS_ENOMEM; + goto err; } - rc = os_mempool_init(&peer_chr_pool, max_chrs, - sizeof (struct peer_chr), peer_chr_mem, - "peer_chr_pool"); - if (rc != 0) { - rc = BLE_HS_EOS; - goto err; + rc = os_mempool_init(&peer_chr_pool, max_chrs, + sizeof(struct peer_chr), peer_chr_mem, + "peer_chr_pool"); + if (rc != 0) + { + rc = BLE_HS_EOS; + goto err; } - peer_dsc_mem = malloc( - OS_MEMPOOL_BYTES(max_dscs, sizeof (struct peer_dsc))); - if (peer_dsc_mem == NULL) { - rc = BLE_HS_ENOMEM; - goto err; + peer_dsc_mem = malloc( + OS_MEMPOOL_BYTES(max_dscs, sizeof(struct peer_dsc))); + if (peer_dsc_mem == NULL) + { + rc = BLE_HS_ENOMEM; + goto err; } - rc = os_mempool_init(&peer_dsc_pool, max_dscs, - sizeof (struct peer_dsc), peer_dsc_mem, - "peer_dsc_pool"); - if (rc != 0) { - rc = BLE_HS_EOS; - goto err; + rc = os_mempool_init(&peer_dsc_pool, max_dscs, + sizeof(struct peer_dsc), peer_dsc_mem, + "peer_dsc_pool"); + if (rc != 0) + { + rc = BLE_HS_EOS; + goto err; } - return 0; + return 0; err: - peer_free_mem(); - return rc; + peer_free_mem(); + return rc; } diff --git a/examples/nimble_bleprph/CMakeLists.txt b/examples/nimble_bleprph/CMakeLists.txt index 6d53718b934..1213cc279bc 100644 --- a/examples/nimble_bleprph/CMakeLists.txt +++ b/examples/nimble_bleprph/CMakeLists.txt @@ -20,7 +20,12 @@ if(CONFIG_EXAMPLES_NIMBLE_BLEPRPH) nuttx_add_application( - NAME nimble - SRCS ${CMAKE_CURRENT_LIST_DIR}/nimble_bleprph_main.c ${CMAKE_CURRENT_LIST_DIR}/misc.c ${CMAKE_CURRENT_LIST_DIR}/gatt_svr.c - DEPENDS nimble) + NAME + nimble + SRCS + ${CMAKE_CURRENT_LIST_DIR}/nimble_bleprph_main.c + ${CMAKE_CURRENT_LIST_DIR}/misc.c + ${CMAKE_CURRENT_LIST_DIR}/gatt_svr.c + DEPENDS + nimble) endif() diff --git a/examples/nimble_bleprph/bleprph.h b/examples/nimble_bleprph/bleprph.h index 495edd9276d..43995c58942 100644 --- a/examples/nimble_bleprph/bleprph.h +++ b/examples/nimble_bleprph/bleprph.h @@ -21,17 +21,23 @@ #ifndef H_BLEPRPH_ #define H_BLEPRPH_ +/**************************************************************************** + * Included Files + ****************************************************************************/ + #include #include #include "nimble/ble.h" #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif struct ble_hs_cfg; struct ble_gatt_register_ctxt; -/** GATT server. */ +/* GATT server. */ + #define GATT_SVR_SVC_ALERT_UUID 0x1811 #define GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID 0x2A47 #define GATT_SVR_CHR_NEW_ALERT 0x2A46 @@ -42,7 +48,8 @@ struct ble_gatt_register_ctxt; void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg); int gatt_svr_init(void); -/** Misc. */ +/* Misc. */ + void print_bytes(const uint8_t *bytes, int len); void print_addr(const void *addr); diff --git a/examples/nimble_bleprph/gatt_svr.c b/examples/nimble_bleprph/gatt_svr.c index c417d8914f0..f8a3a7fd174 100644 --- a/examples/nimble_bleprph/gatt_svr.c +++ b/examples/nimble_bleprph/gatt_svr.c @@ -18,6 +18,9 @@ * ****************************************************************************/ +/**************************************************************************** + * Included Files + ****************************************************************************/ #include #include @@ -38,19 +41,22 @@ */ /* 59462f12-9543-9999-12c8-58b459a2712d */ + static const ble_uuid128_t gatt_svr_svc_sec_test_uuid = BLE_UUID128_INIT(0x2d, 0x71, 0xa2, 0x59, 0xb4, 0x58, 0xc8, 0x12, 0x99, 0x99, 0x43, 0x95, 0x12, 0x2f, 0x46, 0x59); /* 5c3a659e-897e-45e1-b016-007107c96df6 */ + static const ble_uuid128_t gatt_svr_chr_sec_test_rand_uuid = - BLE_UUID128_INIT(0xf6, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0, - 0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c); + BLE_UUID128_INIT(0xf6, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0, + 0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c); /* 5c3a659e-897e-45e1-b016-007107c96df7 */ + static const ble_uuid128_t gatt_svr_chr_sec_test_static_uuid = - BLE_UUID128_INIT(0xf7, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0, - 0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c); + BLE_UUID128_INIT(0xf7, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0, + 0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c); static uint8_t gatt_svr_sec_test_static_val; @@ -59,50 +65,65 @@ gatt_svr_chr_access_sec_test(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); -static const struct ble_gatt_svc_def gatt_svr_svcs[] = { - { - /*** Service: Security test. */ - .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = &gatt_svr_svc_sec_test_uuid.u, - .characteristics = (struct ble_gatt_chr_def[]) { { - /*** Characteristic: Random number generator. */ +static const struct ble_gatt_svc_def gatt_svr_svcs[] = +{ + { + /* Service: Security test. */ + + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = &gatt_svr_svc_sec_test_uuid.u, + .characteristics = (struct ble_gatt_chr_def[]) + { + { + /* Characteristic: Random number generator. */ + .uuid = &gatt_svr_chr_sec_test_rand_uuid.u, .access_cb = gatt_svr_chr_access_sec_test, .flags = BLE_GATT_CHR_F_READ, - }, { - /*** Characteristic: Static value. */ + }, + { + /* Characteristic: Static value. */ + .uuid = &gatt_svr_chr_sec_test_static_uuid.u, .access_cb = gatt_svr_chr_access_sec_test, .flags = BLE_GATT_CHR_F_READ | - BLE_GATT_CHR_F_WRITE, - }, { + BLE_GATT_CHR_F_WRITE, + }, + { 0, /* No more characteristics in this service. */ - } }, - }, + } + }, + }, - { - 0, /* No more services. */ - }, + { + 0, /* No more services. */ + }, }; +/**************************************************************************** + * Public Functions + ****************************************************************************/ + static int gatt_svr_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; + 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; + 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; + rc = ble_hs_mbuf_to_flat(om, dst, max_len, len); + if (rc != 0) + { + return BLE_ATT_ERR_UNLIKELY; } - return 0; + return 0; } static int @@ -110,101 +131,107 @@ gatt_svr_chr_access_sec_test(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { - const ble_uuid_t *uuid; - int rand_num; - int rc; - - uuid = ctxt->chr->uuid; - - /* Determine which characteristic is being accessed by examining its - * 128-bit UUID. - */ - - if (ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_rand_uuid.u) == 0) { - assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); - - /* Respond with a 32-bit random number. */ - rand_num = rand(); - rc = os_mbuf_append(ctxt->om, &rand_num, sizeof rand_num); - return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + const ble_uuid_t *uuid; + int rand_num; + int rc; + + uuid = ctxt->chr->uuid; + + /* Determine which characteristic is being accessed by examining its + * 128-bit UUID. + */ + + if (ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_rand_uuid.u) == 0) + { + assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); + + /* Respond with a 32-bit random number. */ + + rand_num = rand(); + rc = os_mbuf_append(ctxt->om, &rand_num, sizeof rand_num); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; } - if (ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_static_uuid.u) == 0) { - switch (ctxt->op) { + if (ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_static_uuid.u) == 0) + { + switch (ctxt->op) + { case BLE_GATT_ACCESS_OP_READ_CHR: - rc = os_mbuf_append(ctxt->om, &gatt_svr_sec_test_static_val, - sizeof gatt_svr_sec_test_static_val); - return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + rc = os_mbuf_append(ctxt->om, &gatt_svr_sec_test_static_val, + sizeof gatt_svr_sec_test_static_val); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; case BLE_GATT_ACCESS_OP_WRITE_CHR: - rc = gatt_svr_chr_write(ctxt->om, - sizeof gatt_svr_sec_test_static_val, - sizeof gatt_svr_sec_test_static_val, - &gatt_svr_sec_test_static_val, NULL); - return rc; + rc = gatt_svr_chr_write(ctxt->om, + sizeof gatt_svr_sec_test_static_val, + sizeof gatt_svr_sec_test_static_val, + &gatt_svr_sec_test_static_val, NULL); + return rc; default: - assert(0); - return BLE_ATT_ERR_UNLIKELY; + assert(0); + return BLE_ATT_ERR_UNLIKELY; } } - /* Unknown characteristic; the nimble stack should not have called this - * function. - */ - assert(0); - return BLE_ATT_ERR_UNLIKELY; + /* Unknown characteristic; the nimble stack should not have called this + * function. + */ + + assert(0); + return BLE_ATT_ERR_UNLIKELY; } -void -gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) +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: - printf("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: - printf("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: - printf("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; - } + char buf[BLE_UUID_STR_LEN]; + + switch (ctxt->op) + { + case BLE_GATT_REGISTER_OP_SVC: + printf("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: + printf("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: + printf("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 gatt_svr_init(void) { - int rc; + int rc; - ble_svc_ans_init(); - ble_svc_bas_init(); + ble_svc_ans_init(); + ble_svc_bas_init(); - rc = ble_gatts_count_cfg(gatt_svr_svcs); - if (rc != 0) { - return 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; + rc = ble_gatts_add_svcs(gatt_svr_svcs); + if (rc != 0) + { + return rc; } - return 0; + return 0; } diff --git a/examples/nimble_bleprph/misc.c b/examples/nimble_bleprph/misc.c index 713bd911fa8..a22dd337da7 100644 --- a/examples/nimble_bleprph/misc.c +++ b/examples/nimble_bleprph/misc.c @@ -18,28 +18,35 @@ * ****************************************************************************/ +/**************************************************************************** + * Included Files + ****************************************************************************/ #include "bleprph.h" +/**************************************************************************** + * Public Functions + ****************************************************************************/ + /** * Utility function to log an array of bytes. */ -void -print_bytes(const uint8_t *bytes, int len) + +void print_bytes(const uint8_t *bytes, int len) { - int i; + int i; - for (i = 0; i < len; i++) { - printf("%s0x%02x", i != 0 ? ":" : "", bytes[i]); + for (i = 0; i < len; i++) + { + printf("%s0x%02x", i != 0 ? ":" : "", bytes[i]); } } -void -print_addr(const void *addr) +void print_addr(const void *addr) { - const uint8_t *u8p; + const uint8_t *u8p; - u8p = addr; - printf("%02x:%02x:%02x:%02x:%02x:%02x", - u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]); + u8p = addr; + printf("%02x:%02x:%02x:%02x:%02x:%02x", + u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]); } diff --git a/examples/nimble_bleprph/nimble_bleprph_main.c b/examples/nimble_bleprph/nimble_bleprph_main.c index ecc3db17e70..1b0076d572a 100644 --- a/examples/nimble_bleprph/nimble_bleprph_main.c +++ b/examples/nimble_bleprph/nimble_bleprph_main.c @@ -18,6 +18,9 @@ * ****************************************************************************/ +/**************************************************************************** + * Included Files + ****************************************************************************/ #include #include @@ -25,6 +28,7 @@ #include /* BLE */ + #include "nimble/ble.h" #include "nimble/nimble_port.h" #include "host/ble_hs.h" @@ -33,6 +37,7 @@ #include "services/bas/ble_svc_bas.h" /* Application-specified header. */ + #include "bleprph.h" /**************************************************************************** @@ -50,7 +55,6 @@ ****************************************************************************/ void ble_hci_sock_ack_handler(FAR void *param); -//void ble_hci_sock_init(void); void ble_hci_sock_set_device(int dev); /**************************************************************************** @@ -70,28 +74,29 @@ static int bleprph_gap_event(struct ble_gap_event *event, void *arg); /** * Logs information about a connection to the console. */ + static void bleprph_print_conn_desc(struct ble_gap_conn_desc *desc) { - printf("handle=%d our_ota_addr_type=%d our_ota_addr=", - desc->conn_handle, desc->our_ota_addr.type); - print_addr(desc->our_ota_addr.val); - printf(" our_id_addr_type=%d our_id_addr=", - desc->our_id_addr.type); - print_addr(desc->our_id_addr.val); - printf(" peer_ota_addr_type=%d peer_ota_addr=", - desc->peer_ota_addr.type); - print_addr(desc->peer_ota_addr.val); - printf(" peer_id_addr_type=%d peer_id_addr=", - desc->peer_id_addr.type); - print_addr(desc->peer_id_addr.val); - printf(" conn_itvl=%d conn_latency=%d supervision_timeout=%d " - "encrypted=%d authenticated=%d bonded=%d\n", - desc->conn_itvl, desc->conn_latency, - desc->supervision_timeout, - desc->sec_state.encrypted, - desc->sec_state.authenticated, - desc->sec_state.bonded); + printf("handle=%d our_ota_addr_type=%d our_ota_addr=", + desc->conn_handle, desc->our_ota_addr.type); + print_addr(desc->our_ota_addr.val); + printf(" our_id_addr_type=%d our_id_addr=", + desc->our_id_addr.type); + print_addr(desc->our_id_addr.val); + printf(" peer_ota_addr_type=%d peer_ota_addr=", + desc->peer_ota_addr.type); + print_addr(desc->peer_ota_addr.val); + printf(" peer_id_addr_type=%d peer_id_addr=", + desc->peer_id_addr.type); + print_addr(desc->peer_id_addr.val); + printf(" conn_itvl=%d conn_latency=%d supervision_timeout=%d " + "encrypted=%d authenticated=%d bonded=%d\n", + desc->conn_itvl, desc->conn_latency, + desc->supervision_timeout, + desc->sec_state.encrypted, + desc->sec_state.authenticated, + desc->sec_state.bonded); } /** @@ -99,81 +104,88 @@ bleprph_print_conn_desc(struct ble_gap_conn_desc *desc) * o General discoverable mode. * o Undirected connectable mode. */ + static void bleprph_advertise(void) { - uint8_t own_addr_type; - struct ble_gap_adv_params adv_params; - struct ble_hs_adv_fields fields; - const char *name; - int rc; - - /* Figure out address to use while advertising (no privacy for now) */ - rc = ble_hs_id_infer_auto(0, &own_addr_type); - if (rc != 0) - { - printf("error determining address type; rc=%d\n", rc); - return; - } - - /** - * Set the advertisement data included in our advertisements: - * o Flags (indicates advertisement type and other general info). - * o Advertising tx power. - * o Device name. - * o 16-bit service UUIDs (alert notifications). - */ - - 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 assiging 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; - - name = ble_svc_gap_device_name(); - fields.name = (uint8_t *)name; - fields.name_len = strlen(name); - fields.name_is_complete = 1; - - fields.uuids16 = (ble_uuid16_t[]){ - BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID)}; - fields.num_uuids16 = 1; - fields.uuids16_is_complete = 1; - - rc = ble_gap_adv_set_fields(&fields); - if (rc != 0) - { - printf("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(own_addr_type, NULL, BLE_HS_FOREVER, - &adv_params, bleprph_gap_event, NULL); - if (rc != 0) - { - printf("error enabling advertisement; rc=%d\n", rc); - return; - } + uint8_t own_addr_type; + struct ble_gap_adv_params adv_params; + struct ble_hs_adv_fields fields; + const char *name; + int rc; + + /* Figure out address to use while advertising (no privacy for now) */ + + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) + { + printf("error determining address type; rc=%d\n", rc); + return; + } + + /** + * Set the advertisement data included in our advertisements: + * o Flags (indicates advertisement type and other general info). + * o Advertising tx power. + * o Device name. + * o 16-bit service UUIDs (alert notifications). + */ + + 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 assiging 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; + + name = ble_svc_gap_device_name(); + fields.name = (uint8_t *)name; + fields.name_len = strlen(name); + fields.name_is_complete = 1; + + fields.uuids16 = (ble_uuid16_t[]) + { + BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID) + }; + fields.num_uuids16 = 1; + fields.uuids16_is_complete = 1; + + rc = ble_gap_adv_set_fields(&fields); + if (rc != 0) + { + printf("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(own_addr_type, NULL, BLE_HS_FOREVER, + &adv_params, bleprph_gap_event, NULL); + if (rc != 0) + { + printf("error enabling advertisement; rc=%d\n", rc); + return; + } } /** - * The nimble host executes this callback when a GAP event occurs. The - * application associates a GAP event callback with each connection that forms. - * bleprph uses the same callback for all connections. + * The nimble host executes this callback when a GAP event occurs. + * The application associates a GAP event callback with each connection + * that forms. bleprph uses the same callback for all connections. * * @param event The type of event being signalled. * @param ctxt Various information pertaining to the event. @@ -185,125 +197,138 @@ bleprph_advertise(void) * of the return code is specific to the * particular GAP event being signalled. */ + static int bleprph_gap_event(struct ble_gap_event *event, void *arg) { - struct ble_gap_conn_desc desc; - int rc; + struct ble_gap_conn_desc desc; + int rc; + + switch (event->type) + { + case BLE_GAP_EVENT_CONNECT: - switch (event->type) + /* A new connection was established or a connection attempt failed. */ + + printf("connection %s; status=%d ", + event->connect.status == 0 ? "established" : "failed", + event->connect.status); + if (event->connect.status == 0) { - case BLE_GAP_EVENT_CONNECT: - /* A new connection was established or a connection attempt failed. */ - printf("connection %s; status=%d ", - event->connect.status == 0 ? "established" : "failed", - event->connect.status); - if (event->connect.status == 0) - { - rc = ble_gap_conn_find(event->connect.conn_handle, &desc); - assert(rc == 0); - bleprph_print_conn_desc(&desc); - } - printf("\n"); + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + assert(rc == 0); + bleprph_print_conn_desc(&desc); + } + printf("\n"); - if (event->connect.status != 0) - { - /* Connection failed; resume advertising. */ - bleprph_advertise(); - } - return 0; - - case BLE_GAP_EVENT_DISCONNECT: - printf("disconnect; reason=%d ", event->disconnect.reason); - bleprph_print_conn_desc(&event->disconnect.conn); - printf("\n"); - - /* Connection terminated; resume advertising. */ - bleprph_advertise(); - return 0; - - case BLE_GAP_EVENT_CONN_UPDATE: - /* The central has updated the connection parameters. */ - printf("connection updated; status=%d ", - event->conn_update.status); - rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc); - assert(rc == 0); - bleprph_print_conn_desc(&desc); - printf("\n"); - return 0; - - case BLE_GAP_EVENT_ADV_COMPLETE: - printf("advertise complete; reason=%d", - event->adv_complete.reason); - bleprph_advertise(); - return 0; - - case BLE_GAP_EVENT_ENC_CHANGE: - /* Encryption has been enabled or disabled for this connection. */ - printf("encryption change event; status=%d ", - event->enc_change.status); - rc = ble_gap_conn_find(event->connect.conn_handle, &desc); - assert(rc == 0); - bleprph_print_conn_desc(&desc); - printf("\n"); - return 0; - - case BLE_GAP_EVENT_SUBSCRIBE: - printf("subscribe event; conn_handle=%d attr_handle=%d " - "reason=%d prevn=%d curn=%d previ=%d curi=%d\n", - event->subscribe.conn_handle, - event->subscribe.attr_handle, - event->subscribe.reason, - event->subscribe.prev_notify, - event->subscribe.cur_notify, - event->subscribe.prev_indicate, - event->subscribe.cur_indicate); - return 0; - - case BLE_GAP_EVENT_MTU: - printf("mtu update event; conn_handle=%d cid=%d mtu=%d\n", - event->mtu.conn_handle, - event->mtu.channel_id, - event->mtu.value); - return 0; - - case BLE_GAP_EVENT_REPEAT_PAIRING: - /* We already have a bond with the peer, but it is attempting to - * establish a new secure link. This app sacrifices security for - * convenience: just throw away the old bond and accept the new link. - */ - - /* Delete the old bond. */ - rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc); - assert(rc == 0); - ble_store_util_delete_peer(&desc.peer_id_addr); - - /* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should - * continue with the pairing operation. - */ - return BLE_GAP_REPEAT_PAIRING_RETRY; + if (event->connect.status != 0) + { + /* Connection failed; resume advertising. */ + + bleprph_advertise(); } + return 0; + + case BLE_GAP_EVENT_DISCONNECT: + printf("disconnect; reason=%d ", event->disconnect.reason); + bleprph_print_conn_desc(&event->disconnect.conn); + printf("\n"); + /* Connection terminated; resume advertising. */ + + bleprph_advertise(); + return 0; + + case BLE_GAP_EVENT_CONN_UPDATE: + + /* The central has updated the connection parameters. */ + + printf("connection updated; status=%d ", + event->conn_update.status); + rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc); + assert(rc == 0); + bleprph_print_conn_desc(&desc); + printf("\n"); + return 0; + + case BLE_GAP_EVENT_ADV_COMPLETE: + printf("advertise complete; reason=%d", + event->adv_complete.reason); + bleprph_advertise(); return 0; + + case BLE_GAP_EVENT_ENC_CHANGE: + + /* Encryption has been enabled or disabled for this connection. */ + + printf("encryption change event; status=%d ", + event->enc_change.status); + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + assert(rc == 0); + bleprph_print_conn_desc(&desc); + printf("\n"); + return 0; + + case BLE_GAP_EVENT_SUBSCRIBE: + printf("subscribe event; conn_handle=%d attr_handle=%d " + "reason=%d prevn=%d curn=%d previ=%d curi=%d\n", + event->subscribe.conn_handle, + event->subscribe.attr_handle, + event->subscribe.reason, + event->subscribe.prev_notify, + event->subscribe.cur_notify, + event->subscribe.prev_indicate, + event->subscribe.cur_indicate); + return 0; + + case BLE_GAP_EVENT_MTU: + printf("mtu update event; conn_handle=%d cid=%d mtu=%d\n", + event->mtu.conn_handle, + event->mtu.channel_id, + event->mtu.value); + return 0; + + case BLE_GAP_EVENT_REPEAT_PAIRING: + /* We already have a bond with the peer, but it is attempting to + * establish a new secure link. This app sacrifices security for + * convenience: just throw away the old bond and accept the new link. + */ + + /* Delete the old bond. */ + + rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc); + assert(rc == 0); + ble_store_util_delete_peer(&desc.peer_id_addr); + + /* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should + * continue with the pairing operation. + */ + + return BLE_GAP_REPEAT_PAIRING_RETRY; + } + + return 0; } static void bleprph_on_reset(int reason) { - printf("Resetting state; reason=%d\n", reason); + printf("Resetting state; reason=%d\n", reason); } static void bleprph_on_sync(void) { - int rc; + int rc; - /* Make sure we have proper identity address set (public preferred) */ - rc = ble_hs_util_ensure_addr(0); - assert(rc == 0); + /* Make sure we have proper identity address set (public preferred) */ - /* Begin advertising. */ - bleprph_advertise(); + rc = ble_hs_util_ensure_addr(0); + assert(rc == 0); + + /* Begin advertising. */ + + bleprph_advertise(); } /**************************************************************************** @@ -312,8 +337,8 @@ bleprph_on_sync(void) static void nimble_host_task(FAR void *param) { - ble_svc_gap_device_name_set("NuttX NimBLE PRPH"); - nimble_port_run(); + ble_svc_gap_device_name_set("NuttX NimBLE PRPH"); + nimble_port_run(); } /**************************************************************************** @@ -322,8 +347,8 @@ static void nimble_host_task(FAR void *param) static FAR void *ble_hci_sock_task(FAR void *param) { - ble_hci_sock_ack_handler(param); - return NULL; + ble_hci_sock_ack_handler(param); + return NULL; } /**************************************************************************** @@ -332,8 +357,8 @@ static FAR void *ble_hci_sock_task(FAR void *param) static FAR void *ble_host_task(FAR void *param) { - nimble_host_task(param); - return NULL; + nimble_host_task(param); + return NULL; } /**************************************************************************** @@ -346,76 +371,77 @@ static FAR void *ble_host_task(FAR void *param) int main(int argc, FAR char *argv[]) { - struct ble_npl_task s_task_host; - struct ble_npl_task s_task_hci; - int ret = 0; - uint8_t batt_level = 0; + struct ble_npl_task s_task_host; + struct ble_npl_task s_task_hci; + int ret = 0; + uint8_t batt_level = 0; - /* allow to specify custom hci */ + /* allow to specify custom hci */ - if (argc > 1) + if (argc > 1) { - ble_hci_sock_set_device(atoi(argv[1])); + ble_hci_sock_set_device(atoi(argv[1])); } #ifndef CONFIG_NSH_ARCHINIT - /* Perform architecture-specific initialization */ + /* Perform architecture-specific initialization */ - boardctl(BOARDIOC_INIT, 0); + boardctl(BOARDIOC_INIT, 0); #endif #ifndef CONFIG_NSH_NETINIT - /* Bring up the network */ + /* Bring up the network */ - netinit_bringup(); + netinit_bringup(); #endif - nimble_port_init(); - //ble_hci_sock_init(); + nimble_port_init(); + + /* Initialize the NimBLE host configuration. */ - /* Initialize the NimBLE host configuration. */ - ble_hs_cfg.reset_cb = bleprph_on_reset; - ble_hs_cfg.sync_cb = bleprph_on_sync; - ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb; - ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + ble_hs_cfg.reset_cb = bleprph_on_reset; + ble_hs_cfg.sync_cb = bleprph_on_sync; + ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; - /* Initialize services */ - ret = gatt_svr_init(); - assert(ret == 0); + /* Initialize services */ - /* Create task which handles HCI socket */ + ret = gatt_svr_init(); + assert(ret == 0); - ret = ble_npl_task_init(&s_task_hci, "hci_sock", ble_hci_sock_task, - NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, - TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); - if (ret != 0) + /* Create task which handles HCI socket */ + + ret = ble_npl_task_init(&s_task_hci, "hci_sock", ble_hci_sock_task, + NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, + TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); + if (ret != 0) { - printf("ERROR: starting hci task: %i\n", ret); + printf("ERROR: starting hci task: %i\n", ret); } - /* Create task which handles default event queue for host stack. */ + /* Create task which handles default event queue for host stack. */ - ret = ble_npl_task_init(&s_task_host, "ble_host", ble_host_task, - NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, - TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); - if (ret != 0) + ret = ble_npl_task_init(&s_task_host, "ble_host", ble_host_task, + NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, + TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); + if (ret != 0) { - printf("ERROR: starting ble task: %i\n", ret); + printf("ERROR: starting ble task: %i\n", ret); } - while (true) + while (true) { - /* Simulate battery */ + /* Simulate battery */ - batt_level += 1; - if (batt_level > 100) + batt_level += 1; + if (batt_level > 100) { - batt_level = 0; + batt_level = 0; } - ble_svc_bas_battery_level_set(batt_level); - sleep(1); + ble_svc_bas_battery_level_set(batt_level); + sleep(1); } - return 0; + return 0; } From 0cf8da4d8d06fb78fdac7afdcdfc4e6623b2228e Mon Sep 17 00:00:00 2001 From: Max Kriegleder Date: Wed, 8 Jan 2025 22:16:04 +0100 Subject: [PATCH 3/3] Fix Makefiles --- examples/nimble_blecent/Makefile | 6 ++++-- examples/nimble_bleprph/Makefile | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/nimble_blecent/Makefile b/examples/nimble_blecent/Makefile index 964e7425c42..36f93724e52 100644 --- a/examples/nimble_blecent/Makefile +++ b/examples/nimble_blecent/Makefile @@ -27,10 +27,12 @@ PRIORITY = $(CONFIG_EXAMPLES_NIMBLE_BLECENT_PRIORITY) STACKSIZE = $(CONFIG_EXAMPLES_NIMBLE_BLECENT_STACKSIZE) MODULE = $(CONFIG_EXAMPLES_NIMBLE_BLECENT) -# NimBLE Example +# NimBLE Central Example -MAINSRC = nimble_BLECENT_main.c +CSRCS += misc.c peer.c +MAINSRC = nimble_blecent_main.c include $(APPDIR)/wireless/bluetooth/nimble/Makefile.nimble include $(APPDIR)/Application.mk + diff --git a/examples/nimble_bleprph/Makefile b/examples/nimble_bleprph/Makefile index 751ff48df09..7e4e76dd756 100644 --- a/examples/nimble_bleprph/Makefile +++ b/examples/nimble_bleprph/Makefile @@ -27,10 +27,12 @@ PRIORITY = $(CONFIG_EXAMPLES_NIMBLE_BLEPRPH_PRIORITY) STACKSIZE = $(CONFIG_EXAMPLES_NIMBLE_BLEPRPH_STACKSIZE) MODULE = $(CONFIG_EXAMPLES_NIMBLE_BLEPRPH) -# NimBLE Example +# NimBLE Peripheral Example +CSRCS += misc.c gatt_svr.c MAINSRC = nimble_bleprph_main.c include $(APPDIR)/wireless/bluetooth/nimble/Makefile.nimble include $(APPDIR)/Application.mk +