mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 03:00:34 +03:00
feat(nimble): Added example support for Current Time Service
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(cts_prph)
|
||||
@@ -0,0 +1,79 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# BLE Current Time Service Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example creates GATT server demonstrating standard Current Time Service.
|
||||
|
||||
It advertises support for the Current Time Service(0x1805) as primary service UUID.
|
||||
|
||||
It uses ESP32's Bluetooth controller and NimBLE stack based BLE host
|
||||
|
||||
|
||||
## How to Use Example
|
||||
|
||||
Before project configuration and build, be sure to set the correct chip target using:
|
||||
|
||||
```bash
|
||||
idf.py set-target <chip_name>
|
||||
```
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* A development board with ESP32/ESP32-C3 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
|
||||
* A USB cable for Power supply and programming
|
||||
|
||||
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
This console output can be observed when client is connected to server :
|
||||
|
||||
```
|
||||
I (357) BLE_INIT: BT controller compile version [59725b5]
|
||||
I (357) BLE_INIT: Bluetooth MAC: 60:55:f9:68:c4:fa
|
||||
I (367) phy_init: phy_version 1110,9c20f0a,Jul 27 2023,10:42:54
|
||||
I (407) NimBLE_cts_PRPH: BLE Host Task Started
|
||||
I (407) NimBLE: GAP procedure initiated: stop advertising.
|
||||
|
||||
I (407) NimBLE: Failed to restore IRKs from store; status=8
|
||||
|
||||
I (407) NimBLE: Device Address:
|
||||
I (417) NimBLE: 60:55:f9:68:c4:fa
|
||||
I (417) NimBLE:
|
||||
|
||||
I (417) NimBLE: GAP procedure initiated: advertise;
|
||||
I (427) NimBLE: disc_mode=2
|
||||
I (427) NimBLE: adv_channel_map=0 own_addr_type=0 adv_filter_policy=0 adv_itvl_min=0 adv_itvl_max=0
|
||||
I (437) NimBLE:
|
||||
|
||||
I (447) main_task: Returned from app_main()
|
||||
|
||||
I (27317) NimBLE: GAP procedure initiated: advertise;
|
||||
I (27317) NimBLE: disc_mode=2
|
||||
I (27327) NimBLE: adv_channel_map=0 own_addr_type=0 adv_filter_policy=0 adv_itvl_min=0 adv_itvl_max=0
|
||||
I (27337) NimBLE:
|
||||
|
||||
I (31987) NimBLE: connection established; status=0
|
||||
|
||||
I (53297) NimBLE: subscribe event; cur_notify=1
|
||||
value handle; val_handle=12
|
||||
|
||||
I (68317) NimBLE: subscribe event; cur_notify=0
|
||||
value handle; val_handle=12
|
||||
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "main.c" "gatt_svr.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,14 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_EXTENDED_ADV
|
||||
bool
|
||||
depends on SOC_BLE_50_SUPPORTED
|
||||
default y if SOC_ESP_NIMBLE_CONTROLLER
|
||||
select BT_NIMBLE_EXT_ADV
|
||||
prompt "Enable Extended Adv"
|
||||
help
|
||||
Use this option to enable extended advertising in the example.
|
||||
If this option is disabled, ensure config BT_NIMBLE_EXT_ADV is
|
||||
also disabled from Nimble stack menuconfig
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef H_BLE_CTS_PRPH_
|
||||
#define H_BLE_CTS_PRPH_
|
||||
|
||||
#include "nimble/ble.h"
|
||||
#include "modlog/modlog.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ble_hs_cfg;
|
||||
struct ble_gatt_register_ctxt;
|
||||
|
||||
void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
|
||||
int gatt_svr_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/ble_uuid.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
#include "ble_cts_prph.h"
|
||||
#include "services/cts/ble_svc_cts.h"
|
||||
#include <time.h>
|
||||
#include "sys/time.h"
|
||||
|
||||
|
||||
void
|
||||
gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
|
||||
{
|
||||
char buf[BLE_UUID_STR_LEN];
|
||||
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_REGISTER_OP_SVC:
|
||||
MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
|
||||
ctxt->svc.handle);
|
||||
break;
|
||||
|
||||
case BLE_GATT_REGISTER_OP_CHR:
|
||||
MODLOG_DFLT(DEBUG, "registering characteristic %s with "
|
||||
"def_handle=%d val_handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
|
||||
ctxt->chr.def_handle,
|
||||
ctxt->chr.val_handle);
|
||||
break;
|
||||
|
||||
case BLE_GATT_REGISTER_OP_DSC:
|
||||
MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
|
||||
ctxt->dsc.handle);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct ble_svc_cts_local_time_info local_info = { .timezone = 0, .dst_offset = TIME_STANDARD };
|
||||
static struct timeval last_updated;
|
||||
uint8_t adjust_reason;
|
||||
int fetch_current_time(struct ble_svc_cts_curr_time *ctime) {
|
||||
time_t now;
|
||||
struct tm timeinfo;
|
||||
struct timeval tv_now;
|
||||
/* time given by 'time()' api does not persist after reboots */
|
||||
time(&now);
|
||||
localtime_r(&now, &timeinfo);
|
||||
gettimeofday(&tv_now, NULL);
|
||||
if(ctime != NULL) {
|
||||
/* fill date_time */
|
||||
ctime->et_256.d_d_t.d_t.year = timeinfo.tm_year + 1900;
|
||||
ctime->et_256.d_d_t.d_t.month = timeinfo.tm_mon + 1;
|
||||
ctime->et_256.d_d_t.d_t.day = timeinfo.tm_mday;
|
||||
ctime->et_256.d_d_t.d_t.hours = timeinfo.tm_hour;
|
||||
ctime->et_256.d_d_t.d_t.minutes = timeinfo.tm_min;
|
||||
ctime->et_256.d_d_t.d_t.seconds = timeinfo.tm_sec;
|
||||
|
||||
/* day of week */
|
||||
/* time gives day range of [0, 6], current_time_sevice
|
||||
has day range of [1,7] */
|
||||
ctime->et_256.d_d_t.day_of_week = timeinfo.tm_wday + 1;
|
||||
|
||||
/* fractions_256 */
|
||||
ctime->et_256.fractions_256 = (((uint64_t)tv_now.tv_usec * 256L )/ 1000000L);
|
||||
|
||||
ctime->adjust_reason = adjust_reason;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_current_time(struct ble_svc_cts_curr_time ctime) {
|
||||
time_t now;
|
||||
struct tm timeinfo;
|
||||
struct timeval tv_now;
|
||||
/* fill date_time */
|
||||
timeinfo.tm_year= ctime.et_256.d_d_t.d_t.year - 1900 ;
|
||||
timeinfo.tm_mon = ctime.et_256.d_d_t.d_t.month - 1;
|
||||
timeinfo.tm_mday = ctime.et_256.d_d_t.d_t.day;
|
||||
timeinfo.tm_hour = ctime.et_256.d_d_t.d_t.hours;
|
||||
timeinfo.tm_min = ctime.et_256.d_d_t.d_t.minutes;
|
||||
timeinfo.tm_sec = ctime.et_256.d_d_t.d_t.seconds;
|
||||
timeinfo.tm_wday = ctime.et_256.d_d_t.day_of_week - 1;
|
||||
now = mktime(&timeinfo);
|
||||
tv_now.tv_sec = now;
|
||||
settimeofday(&tv_now, NULL);
|
||||
/* set the last updated */
|
||||
gettimeofday(&last_updated, NULL);
|
||||
adjust_reason = ctime.adjust_reason;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fetch_local_time_info(struct ble_svc_cts_local_time_info *info) {
|
||||
|
||||
if(info != NULL) {
|
||||
memcpy(info, &local_info, sizeof local_info);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_local_time_info(struct ble_svc_cts_local_time_info info) {
|
||||
/* just store the dst offset and timezone locally
|
||||
as we don't have the access to time using ntp server */
|
||||
local_info.timezone = info.timezone;
|
||||
local_info.dst_offset = info.dst_offset;
|
||||
gettimeofday(&last_updated, NULL);
|
||||
return 0;
|
||||
}
|
||||
int fetch_reference_time_info(struct ble_svc_cts_reference_time_info *info) {
|
||||
struct timeval tv_now;
|
||||
uint64_t days_since_update;
|
||||
uint64_t hours_since_update;
|
||||
|
||||
gettimeofday(&tv_now, NULL);
|
||||
/* subtract the time when the last time was updated */
|
||||
tv_now.tv_sec -= last_updated.tv_sec; /* ignore microseconds */
|
||||
info->time_source = TIME_SOURCE_MANUAL;
|
||||
info->time_accuracy = 0;
|
||||
days_since_update = (tv_now.tv_sec / 86400L);
|
||||
hours_since_update = (tv_now.tv_sec / 3600);
|
||||
info->days_since_update = days_since_update < 255 ? days_since_update : 255;
|
||||
|
||||
if(days_since_update > 254) {
|
||||
info->hours_since_update = 255;
|
||||
}
|
||||
else {
|
||||
hours_since_update = (tv_now.tv_sec % 86400L) / 3600;
|
||||
info->hours_since_update = hours_since_update;
|
||||
}
|
||||
adjust_reason = (CHANGE_OF_DST_MASK | CHANGE_OF_TIME_ZONE_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
int
|
||||
gatt_svr_init(void)
|
||||
{
|
||||
struct ble_svc_cts_cfg cfg;
|
||||
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
|
||||
cfg.fetch_time_cb = fetch_current_time;
|
||||
cfg.local_time_info_cb = fetch_local_time_info;
|
||||
cfg.ref_time_info_cb = fetch_reference_time_info;
|
||||
cfg.set_time_cb = set_current_time;
|
||||
cfg.set_local_time_info_cb = set_local_time_info;
|
||||
ble_svc_cts_init(cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
nimble_peripheral_utils:
|
||||
path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "freertos/FreeRTOSConfig.h"
|
||||
/* BLE */
|
||||
#include "nimble/nimble_port.h"
|
||||
#include "nimble/nimble_port_freertos.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "console/console.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "ble_cts_prph.h"
|
||||
#include "services/cts/ble_svc_cts.h"
|
||||
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
static uint8_t ext_adv_pattern_1[] = {
|
||||
0x02, 0x01, 0x06,
|
||||
0x03, 0x03, 0xab, 0xcd,
|
||||
0x03, 0x03, 0x05, 0x18,
|
||||
0x12, 0X09, 'n', 'i', 'm', 'b', 'l', 'e', '-', 'c', 't', 's', '-', 'p', 'r', 'p', 'h', '-', 'e',
|
||||
};
|
||||
#endif
|
||||
|
||||
static const char *tag = "NimBLE_CTS_PRPH";
|
||||
static const char *device_name = "ble_cts_prph";
|
||||
|
||||
static int ble_cts_prph_gap_event(struct ble_gap_event *event, void *arg);
|
||||
|
||||
static uint8_t ble_cts_prph_addr_type;
|
||||
|
||||
/**
|
||||
* 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++) {
|
||||
MODLOG_DFLT(INFO, "%s0x%02x", i != 0 ? ":" : "", bytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_addr(const void *addr)
|
||||
{
|
||||
const uint8_t *u8p;
|
||||
|
||||
u8p = addr;
|
||||
MODLOG_DFLT(INFO, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]);
|
||||
}
|
||||
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
/**
|
||||
* Enables advertising with the following parameters:
|
||||
* o General discoverable mode.
|
||||
* o Undirected connectable mode.
|
||||
*/
|
||||
static void
|
||||
ext_ble_cts_prph_advertise(void)
|
||||
{
|
||||
struct ble_gap_ext_adv_params params;
|
||||
struct os_mbuf *data;
|
||||
uint8_t instance = 0;
|
||||
int rc;
|
||||
|
||||
/* First check if any instance is already active */
|
||||
if (ble_gap_ext_adv_active(instance)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* use defaults for non-set params */
|
||||
memset (¶ms, 0, sizeof(params));
|
||||
|
||||
/* enable connectable advertising */
|
||||
params.connectable = 1;
|
||||
|
||||
/* advertise using random addr */
|
||||
params.own_addr_type = BLE_OWN_ADDR_PUBLIC;
|
||||
|
||||
params.primary_phy = BLE_HCI_LE_PHY_1M;
|
||||
params.secondary_phy = BLE_HCI_LE_PHY_2M;
|
||||
params.sid = 1;
|
||||
|
||||
params.itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN;
|
||||
params.itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MIN;
|
||||
|
||||
/* configure instance 0 */
|
||||
rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL,
|
||||
ble_cts_prph_gap_event, NULL);
|
||||
assert (rc == 0);
|
||||
|
||||
/* in this case only scan response is allowed */
|
||||
|
||||
/* get mbuf for scan rsp data */
|
||||
data = os_msys_get_pkthdr(sizeof(ext_adv_pattern_1), 0);
|
||||
assert(data);
|
||||
|
||||
/* fill mbuf with scan rsp data */
|
||||
rc = os_mbuf_append(data, ext_adv_pattern_1, sizeof(ext_adv_pattern_1));
|
||||
assert(rc == 0);
|
||||
|
||||
rc = ble_gap_ext_adv_set_data(instance, data);
|
||||
assert (rc == 0);
|
||||
|
||||
/* start advertising */
|
||||
rc = ble_gap_ext_adv_start(instance, 0, 0);
|
||||
assert (rc == 0);
|
||||
}
|
||||
#else
|
||||
|
||||
static void
|
||||
ble_cts_prph_advertise(void)
|
||||
{
|
||||
struct ble_gap_adv_params adv_params;
|
||||
struct ble_hs_adv_fields fields;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Set the advertisement data included in our advertisements:
|
||||
* o Flags (indicates advertisement type and other general info)
|
||||
* o Advertising tx power
|
||||
* o Device name
|
||||
*/
|
||||
memset(&fields, 0, sizeof(fields));
|
||||
|
||||
/*
|
||||
* Advertise two flags:
|
||||
* o Discoverability in forthcoming advertisement (general)
|
||||
* o BLE-only (BR/EDR unsupported)
|
||||
*/
|
||||
fields.flags = BLE_HS_ADV_F_DISC_GEN |
|
||||
BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
|
||||
/*
|
||||
* Indicate that the TX power level field should be included; have the
|
||||
* stack fill this value automatically. This is done by assigning the
|
||||
* special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
|
||||
*/
|
||||
fields.tx_pwr_lvl_is_present = 1;
|
||||
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
|
||||
|
||||
fields.name = (uint8_t *)device_name;
|
||||
fields.name_len = strlen(device_name);
|
||||
fields.name_is_complete = 1;
|
||||
|
||||
fields.uuids16 = (ble_uuid16_t[]) {
|
||||
BLE_UUID16_INIT(BLE_SVC_CTS_UUID16)
|
||||
};
|
||||
fields.num_uuids16 = 1;
|
||||
fields.uuids16_is_complete = 1;
|
||||
|
||||
rc = ble_gap_adv_set_fields(&fields);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Begin advertising */
|
||||
memset(&adv_params, 0, sizeof(adv_params));
|
||||
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
|
||||
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||
rc = ble_gap_adv_start(ble_cts_prph_addr_type, NULL, BLE_HS_FOREVER,
|
||||
&adv_params, ble_cts_prph_gap_event, NULL);
|
||||
if (rc != 0) {
|
||||
MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
ble_cts_prph_gap_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_CONNECT:
|
||||
/* A new connection was established or a connection attempt failed */
|
||||
MODLOG_DFLT(INFO, "connection %s; status=%d\n",
|
||||
event->connect.status == 0 ? "established" : "failed",
|
||||
event->connect.status);
|
||||
|
||||
if (event->connect.status != 0) {
|
||||
/* Connection failed; resume advertising */
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
ext_ble_cts_prph_advertise();
|
||||
#else
|
||||
ble_cts_prph_advertise();
|
||||
#endif
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
MODLOG_DFLT(INFO, "disconnect; reason=%d\n", event->disconnect.reason);
|
||||
|
||||
/* Connection terminated; resume advertising */
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
ext_ble_cts_prph_advertise();
|
||||
#else
|
||||
ble_cts_prph_advertise();
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||
MODLOG_DFLT(INFO, "adv complete\n");
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
ext_ble_cts_prph_advertise();
|
||||
#else
|
||||
ble_cts_prph_advertise();
|
||||
#endif
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_SUBSCRIBE:
|
||||
MODLOG_DFLT(INFO, "subscribe event; cur_notify=%d\n value handle; "
|
||||
"val_handle=%d\n",
|
||||
event->subscribe.cur_notify, event->subscribe.attr_handle);
|
||||
|
||||
break;
|
||||
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d mtu=%d\n",
|
||||
event->mtu.conn_handle,
|
||||
event->mtu.value);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ble_cts_prph_on_sync(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ble_hs_id_infer_auto(0, &ble_cts_prph_addr_type);
|
||||
assert(rc == 0);
|
||||
|
||||
uint8_t addr_val[6] = {0};
|
||||
rc = ble_hs_id_copy_addr(ble_cts_prph_addr_type, addr_val, NULL);
|
||||
|
||||
MODLOG_DFLT(INFO, "Device Address: ");
|
||||
print_addr(addr_val);
|
||||
MODLOG_DFLT(INFO, "\n");
|
||||
|
||||
/* Begin advertising */
|
||||
#if CONFIG_EXAMPLE_EXTENDED_ADV
|
||||
ext_ble_cts_prph_advertise();
|
||||
#else
|
||||
ble_cts_prph_advertise();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
ble_cts_prph_on_reset(int reason)
|
||||
{
|
||||
MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
void ble_cts_prph_host_task(void *param)
|
||||
{
|
||||
ESP_LOGI(tag, "BLE Host Task Started");
|
||||
/* This function will return only when nimble_port_stop() is executed */
|
||||
nimble_port_run();
|
||||
|
||||
nimble_port_freertos_deinit();
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Initialize NVS — it is used to store PHY calibration data */
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
ret = nimble_port_init();
|
||||
if (ret != ESP_OK) {
|
||||
MODLOG_DFLT(ERROR, "Failed to init nimble %d \n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialize the NimBLE host configuration */
|
||||
ble_hs_cfg.sync_cb = ble_cts_prph_on_sync;
|
||||
ble_hs_cfg.reset_cb = ble_cts_prph_on_reset;
|
||||
|
||||
/* Enable bonding */
|
||||
ble_hs_cfg.sm_bonding = 1;
|
||||
ble_hs_cfg.sm_our_key_dist |= BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID;
|
||||
ble_hs_cfg.sm_their_key_dist |= BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID;
|
||||
|
||||
ble_hs_cfg.sm_sc = 1;
|
||||
ble_hs_cfg.sm_mitm = 1;
|
||||
|
||||
rc = gatt_svr_init();
|
||||
assert(rc == 0);
|
||||
|
||||
/* Set the default device name */
|
||||
rc = ble_svc_gap_device_name_set(device_name);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Start the task */
|
||||
nimble_port_freertos_init(ble_cts_prph_host_task);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# in this example
|
||||
|
||||
#
|
||||
# BT config
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
Reference in New Issue
Block a user