diff --git a/examples/nimble/Kconfig b/examples/nimble/Kconfig new file mode 100644 index 000000000..1fc566378 --- /dev/null +++ b/examples/nimble/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 + tristate "NimBLE example" + default n + ---help--- + Enable the nimble example + +if EXAMPLES_NIMBLE + +config EXAMPLES_NIMBLE_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_PRIORITY + int "NimBLE task priority" + default 100 + +config EXAMPLES_NIMBLE_STACKSIZE + int "NimBLE stack size" + default DEFAULT_TASK_STACKSIZE + +endif # EXAMPLES_NIMBLE + diff --git a/examples/nimble/Make.defs b/examples/nimble/Make.defs new file mode 100644 index 000000000..a3be37e41 --- /dev/null +++ b/examples/nimble/Make.defs @@ -0,0 +1,23 @@ +############################################################################ +# apps/examples/nimble/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),) +CONFIGURED_APPS += $(APPDIR)/examples/nimble +endif diff --git a/examples/nimble/Makefile b/examples/nimble/Makefile new file mode 100644 index 000000000..4e6a3b714 --- /dev/null +++ b/examples/nimble/Makefile @@ -0,0 +1,36 @@ +############################################################################ +# apps/examples/nimble/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_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_NIMBLE_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_NIMBLE_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_NIMBLE) + +# NimBLE Example + +MAINSRC = nimble_main.c + +include $(APPDIR)/wireless/bluetooth/nimble/Makefile.nimble + +include $(APPDIR)/Application.mk diff --git a/examples/nimble/nimble_main.c b/examples/nimble/nimble_main.c new file mode 100644 index 000000000..4bc3d013e --- /dev/null +++ b/examples/nimble/nimble_main.c @@ -0,0 +1,322 @@ +/**************************************************************************** + * apps/examples/nimble/nimble_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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "netutils/netinit.h" + +#include "nimble/nimble_npl.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/gatt/ble_svc_gatt.h" +#include "services/ans/ble_svc_ans.h" +#include "services/ias/ble_svc_ias.h" +#include "services/lls/ble_svc_lls.h" +#include "services/tps/ble_svc_tps.h" +#include "services/gap/ble_svc_gap.h" +#include "services/bas/ble_svc_bas.h" +#include "services/dis/ble_svc_dis.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Not used now */ + +#define TASK_DEFAULT_PRIORITY 0 +#define TASK_DEFAULT_STACK NULL +#define TASK_DEFAULT_STACK_SIZE 0 + +/**************************************************************************** + * External Functions Prototypes + ****************************************************************************/ + +void ble_hci_sock_ack_handler(void *param); +void ble_hci_sock_init(void); +void ble_hci_sock_set_device(int dev); + +/**************************************************************************** + * Private Functions Prototypes + ****************************************************************************/ + +static void put_ad(uint8_t ad_type, uint8_t ad_len, FAR const void *ad, + FAR uint8_t *buf, FAR uint8_t *len); +static void update_ad(void); +static void start_advertise(void); +static int gap_event_cb(FAR struct ble_gap_event *event, FAR void *arg); +static void app_ble_sync_cb(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); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char *g_gap_name = "NuttX NimBLE"; +static uint8_t g_own_addr_type; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: put_ad + ****************************************************************************/ + +static void put_ad(uint8_t ad_type, uint8_t ad_len, FAR const void *ad, + FAR uint8_t *buf, FAR uint8_t *len) +{ + buf[(*len)++] = ad_len + 1; + buf[(*len)++] = ad_type; + + memcpy(&buf[*len], ad, ad_len); + + *len += ad_len; +} + +/**************************************************************************** + * Name: update_ad + ****************************************************************************/ + +static void update_ad(void) +{ + uint8_t ad_flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP; + uint8_t ad_len = 0; + uint8_t ad[BLE_HS_ADV_MAX_SZ]; + + put_ad(BLE_HS_ADV_TYPE_FLAGS, 1, &ad_flags, ad, &ad_len); + put_ad(BLE_HS_ADV_TYPE_COMP_NAME, sizeof(g_gap_name), g_gap_name, + ad, &ad_len); + + ble_gap_adv_set_data(ad, ad_len); +} + +/**************************************************************************** + * Name: start_advertise + ****************************************************************************/ + +static void start_advertise(void) +{ + struct ble_gap_adv_params advp; + int rc; + + printf("advertise\n"); + + update_ad(); + + memset(&advp, 0, sizeof advp); + advp.conn_mode = BLE_GAP_CONN_MODE_UND; + advp.disc_mode = BLE_GAP_DISC_MODE_GEN; + rc = ble_gap_adv_start(g_own_addr_type, NULL, BLE_HS_FOREVER, + &advp, gap_event_cb, NULL); + assert(rc == 0); +} + +/**************************************************************************** + * Name: gap_event_cb + ****************************************************************************/ + +static int gap_event_cb(FAR struct ble_gap_event *event, FAR void *arg) +{ + switch (event->type) + { + case BLE_GAP_EVENT_CONNECT: + { + if (event->connect.status) + { + start_advertise(); + } + break; + } + + case BLE_GAP_EVENT_DISCONNECT: + { + start_advertise(); + break; + } + } + + return 0; +} + +/**************************************************************************** + * Name: app_ble_sync_cb + ****************************************************************************/ + +static void app_ble_sync_cb(void) +{ + ble_addr_t addr; + int rc; + + /* Generate new non-resolvable private address */ + + rc = ble_hs_id_gen_rnd(1, &addr); + assert(rc == 0); + + /* Set generated address */ + + rc = ble_hs_id_set_rnd(addr.val); + assert(rc == 0); + + rc = ble_hs_util_ensure_addr(0); + assert(rc == 0); + + rc = ble_hs_id_infer_auto(0, &g_own_addr_type); + assert(rc == 0); + + start_advertise(); +} + +/**************************************************************************** + * Name: nimble_host_task + ****************************************************************************/ + +static void nimble_host_task(FAR void *param) +{ + ble_hs_cfg.sync_cb = app_ble_sync_cb; + ble_svc_gap_device_name_set(g_gap_name); + 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; + uint8_t batt_level = 0; + 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(); + + /* Initialize services */ + + ble_svc_gap_init(); + ble_svc_gatt_init(); + ble_svc_ans_init(); + ble_svc_ias_init(); + ble_svc_lls_init(); + ble_svc_tps_init(); + ble_svc_bas_init(); + ble_svc_dis_init(); + + /* 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; +}