全部文档
概述 硬件支持 快速开发指南 内核 驱动 通用组件 专业组件 常见问题

BLE

NimBLE是Apache 在Mynewt项目中实现的完全符合Bluetooth 5规范且支持Bluetooth Mesh的完全开源的Bluetooth Low Energy(BLE)协议栈。NimBLE提供了大量的配置选项,允许开发人员配置系统以获取最优的实现。NimBLE还具有较好的可移植性,可以方便地移植到带os的系统中。

NimBLE详细资料参见官网:https://mynewt.apache.org/latest/network/index.html


目录


简介

NimBLE是Apache Mynewt提供的一个完全兼容Bluetooth 5规格、完全开源的Bluetooth Low Energy(BLE)协议栈,并支持Bluetooth Mesh。

BLE技术在2.4~2.485 GHz的工业、科学和医学(ISM)频段中运行,该频段在大多数国家/地区都可用。它使用扩频,跳频,全双工信号。BLE FHSS使用40个2MHz宽的信道,以确保长距离时更高的可靠性。它还具有0-dBm(1 mW)的功率输出,典型最大通信范围为50米。使用Bluetooth 5规格时,通信范围可以增加4倍,通信速度可以增加2倍。

请注意,BLE与标准蓝牙不兼容。

特征

NimBLE符合Bluetooth Core Specification 5.0。

  • LE广播拓展;
  • LE 2Msym/s PHY,可获得更高的吞吐量;
  • LE Coded PHY,远距离通信;
  • 高占空比不可连接广播(High Duty Cycle Non-Connectable Advertising);
  • Channel Selection Algorithm #2,以更有效的方式利用通道;
  • LE Privacy 1.2,用于频繁更改设备地址,从而使外部人员难以跟踪设备;
  • LE安全连接,带有符合FIPS的算法;
  • LE数据长度扩展,提高吞吐量。

Bluetooth 5向后兼容以前的4.2版本,NimBLE也支持该版本。

组成

NimBLE由两部分和几个子部分组成。

  • Controller 物理层:自适应跳频高斯频移键控(GFSK),使用40个RF信道(0-39),间隔2 MHz; 链路层:随时处于五个状态之一(待机,广播,扫描,发起,连接状态)。

  • Host 逻辑链路控制和适配协议(L2CAP):提供名为L2CAP信道的逻辑信道,这些逻辑信道在一个或多个逻辑链路上多路复用,以提供数据包分段和重组、流控制、错误控制、流传输、QoS等; 安全管理器(SM):使用安全管理器协议(SMP)进行配对和特定密钥分发,以确保无线通信的安全; 属性协议(ATT):允许设备(服务器端)向另一台设备(客户端)公开某些称为属性的数据; 通用属性配置(GATT):使用ATT协议交换封装为特性或服务的属性的框架; 通用访问配置(GAP):所有蓝牙设备都需实现的基本配置,对于LE,定义了物理层、链路层、L2CAP、安全管理器、属性协议和通用属性配置。 host/controller接口(HCI):host和controller之间的接口,可以通过软件API或硬件接口(例如SPI,UART或USB)。

NimBLE安全性

BLE安全模型包括以下五个安全概念。

  • 配对:创建一个或多个共享密钥的过程;
  • 绑定:存储在配对过程中创建的密钥的操作,以便在后续连接中使用,以形成受信任的设备对;
  • 设备身份验证:验证两个设备具有相同的密钥(验证设备身份);
  • 加密:使消息保密。Bluetooth LE中的加密使用AES-CCM加密,并在Controller中执行。
  • 消息完整性:防止消息伪造。

BLE使用四种关联模型,具体取决于设备的I/O能力。

  • Just Works:适用于至少其中一台设备没有能显示六位数字的显示器,也没有能输入六位数字的键盘的场景。
  • 数值比较:适用于两台设备都能够显示六位数字并且两台设备都能够让用户输入“是”或“否”的情况。这种模式的一个很好的例子是手机/PC场景。
  • 带外:适用于使用带外机制来发现设备以及交换或传输在配对过程中使用的密码的场景。
  • 密码输入:适用于以下情况,一台设备具有输入功能,但不具有显示六位数字的能力,而另一台设备具有输出功能。 PC和键盘方案就是这种模型的一个很好的例子。

密钥生成

在每个LE设备上Bluetooth LE中用于所有目的的密钥是由host生成的,并独立于任何其他LE设备执行。

隐私功能

BLE在连接模式和连接过程期间支持的可选功能,该功能通过频繁更改蓝牙设备地址来降低一段时间内其他设备跟踪设备的能力。

隐私功能有两种变体。

  • 在第一种变体中,私有地址由host解析和生成。
  • 在第二变体中,在host提供controller设备身份信息之后,controller在不涉及host的情况下解析并生成私有地址。host可以向controller提供完整的解析列表或解析列表的子集。在第二个变体中,当在Controller中执行地址解析时,可以进行设备过滤,因为可以在检查对等方的设备标识地址是否在白名单中之前对其进行解析。

Mesh介绍

Bluetooth Mesh是Bluetooth SIG于2017年发布的新标准。它支持多对多设备通信(与BLE中的点对点方法相对),并针对诸如楼宇自动化或传感器网络等大规模网络进行了优化。它利用基于泛洪管理的方法,其中只有主电源节点可以中继消息,从而使其具有很高的能效(由电池供电的低功率节点不中继消息,可以在Mesh网络中运行多年)。

Bluetooth Mesh是蓝牙规范的补充,并且仅要求4.0版本以后的功能。这允许使用市场上已有的硬件来部署网络。

Bluetooth Mesh是物联网空间连接的一个很好的补充,并为物联网空间连接打开了许多新的可能性。 NimBLE完全支持以下Bluetooth Mesh功能:

  • 广播和GATT承载层
  • PB-GATT和PB-ADV 配置
  • 基础模型(服务器角色)
  • 中继支持
  • GATT代理

使用说明

NimBLE初始化

NimBLE大多数功能的初始化是由nimble_port_oneos_init()自动完成的。本节介绍应用程序中必须手动执行的初始化的一些步骤。

配置controller时钟

NimBLE协议栈使用OS cputime调度controller内部的各种事件(OS cputime可参考 http://mynewt.apache.org/latest/os/core_os/cputime/os_cputime.html )。由于controller的代码已优化为与32768 Hz时钟一起使用,因此必须相应配置OS cputime。

为了使NimBLE controller正常工作,需要配置以下内容:

  • OS cputime频率应设置为32768 Hz;
  • OS cputime计时器源应设置为32768 Hz时钟源;
  • 如果应用程序不使用默认的1 MHz时钟源,默认的1 MHz时钟源需关闭;
  • 必须启用32768 Hz时钟源;
  • 晶振稳定时间应设置为非零值。

例如,在nRF52平台上,RTC0可用作32768 Hz时钟的源。在应用中相应设置为:

#ifndef MYNEWT_VAL_TIMER_5
#define MYNEWT_VAL_TIMER_5 (1)
#endif

#define MYNEWT_VAL_OS_CPUTIME_TIMER_NUM (5)

配置晶体稳定时间

controller使用配置变量BLE_XTAL_SETTLE_TIME在蓝牙事件(广播,扫描,连接等)之前打开无线电和相关外围设备必要的时钟源。对于nRF5x平台,需要在使用无线电之前打开HFXO,并且必须将BLE_XTAL_SETTLE_TIME设置为等待打开完成所需时间。所需时间取决于主板,因此用户必须表征其硬件并相应地设置BLE_XTAL_SETTLE_TIME。当前的1500微秒值是一个相当长的时间,并且旨在用于大多数(如果不是全部)平台。

请注意,更改此时间将影响电池寿命,具体取决于应用程序。 HFXO在运行时会消耗相当大的电流,因此,将时间保持尽可能短将减少总的电流消耗。

配置设备地址

有几种方法可以为NimBLE设备分配地址。

方法1:使用nRF硬配置的公共地址

当NimBLE在Nordic nRF平台上运行时,NimBLE controller将尝试从开发板的FICR或UICR寄存器中读取一个公共地址。尝试从硬件读取地址时,controller使用以下逻辑:

  1. 如果DEVICEADDRTYPE FICR寄存器已写入了值,则读取在DEVICEADDR[0]和DEVICEADDR[1] FICR寄存器中编程的地址;
  2. 否则,如果CUSTOMER[1] UICR寄存器的高16位为0,则读取CUSTOMER[0]和CUSTOMER[1] UCI寄存器中编程的地址;
  3. 否则,没有可用的地址。

方法2:在NimBLE协议栈中直接对公共地址进行编码设置

NimBLE controller软件包会导出名为BLE_PUBLIC_DEV_ADDR的设置项。可以在应用程序或目标级别覆盖此设置,以配置公共蓝牙地址。例如,目标可以按以下方式分配公共地址 11:22:33:44:55:66,

#ifndef MYNEWT_VAL_BLE_PUBLIC_DEV_ADDR
#define MYNEWT_VAL_BLE_PUBLIC_DEV_ADDR (((uint8_t[6]){0xcc, 0xbb, 0xaa, 0x33, 0x22, 0x11}))
#endif

注意:此方法优先于方法1。无论写入BLE_PUBLIC_DEV_ADDR设置如何,都是所使用的地址。

方法3:在运行时配置一个随机地址

通过NimBLE host配置随机地址。在随机地址配置中使用以下两个功能:

  • ble_hs_id_gen_rnd:生成一个新的随机地址。
  • ble_hs_id_set_rnd:设置设备的随机地址。

响应同步和重置事件

同步

当host和controller不同步时,NimBLE堆栈不可操作。在host与controller结合的单芯片应用程序中,同步在启动时立即发生。当host和controller分开时,同步通常在应用程序启动后不到一秒钟的时间内发生。应用程序通过配置host的同步回调:ble_hs_cfg.sync_cb来了解何时实现同步。只要捕获到同步,host就会调用同步回调。同步回调具有以下形式:

typedef void ble_hs_sync_fn(void);

由于NimBLE堆栈开始于未同步状态,因此应用程序应延迟所有BLE操作,直到调用了同步回调。

重置

由host指示的另一个事件是controller复位。当发生灾难性错误(例如host与controller之间的通信丢失)时,NimBLE协议栈会自行重置。重置后,host将丢弃所有BLE连接,并失去与controller的同步。重置后,应用程序应避免使用host,直到通过同步回调再次发出同步信号为止。

应用程序通过配置host的重置回调来了解host重置:ble_hs_cfg.reset_cb。该回调具有以下形式:

typedef void ble_hs_reset_fn(int reason);

'reason'参数是NimBLE host返回码。


源码目录结构

Nimble源代码目录主要结构如下所示:

.
├── apps    原协议栈示例
├── docs    文档
├── ext     加密组件源码
├── nimble  协议栈源码
│   ├── controller  协议栈controller源码
│   ├── drivers     蓝牙硬件相关源码
│   ├── host        协议栈host源码
│   │   ├── include
│   │   ├── mesh    mesh源码
│   │   ├── pts
│   │   ├── services    内建服务源码
│   │   ├── src
│   │   ├── store
│   │   ├── test
│   │   ├── tools
│   │   └── util
│   ├── include
│   └── transport   hci接口源码
├── porting     
│   ├── examples
│   ├── nimble
│   ├── npl         os移植相关源码
│   │   ├── dummy
│   │   ├── freertos
│   │   ├── linux
│   │   ├── mynewt
│   │   ├── oneos
│   │   └── riot
│   └── targets
└── targets

配置指南

打开menuconfig,进入'Componentsk→BLE',然后使能'Enable BLE stack'项以使能NimBLE协议栈。

[*] Enable BLE stack
        BLE stack choose (NimBLE)  --->
        NimBLE  --->

进入'Components→BLE→NimBLE',配置协议栈主要的特性。

[*] Enables the Broadcaster bluetooth role. (0/1)
[*] Enables the Peripheral bluetooth role. (0/1)
[*] Enables the Observer bluetooth role. (0/1)
[*] Enables the Central bluetooth role. (0/1)
(1) The maximum number of concurrent connections.
(1) The maximum number of concurrent periodic syncs that can  be created
[*] Enables the BLE whitelist for controlling who to connect to or accept a connection from. (0/1)
(0) This is the number of multi-advertising instances
[ ] This enables extended advertising feature.
[ ] This enables periodic advertising feature.
[ ] This enables Periodic Advertising Sync Transfer Feature.
(31) This allows to configure maximum size of advertising data and scan response data used in LE Advertising Extensions
(50) This allows to configure supported Bluetooth Core version
[ ] This enables LE Isochronous Channels as per Bluetooth v5.2
[ ] Enables BLE ISO Testing commands
(12) Nimble memory system 1 block count.
(292) Nimble memory system 1 block size.
(0) Nimble memory system 2 block count.
(0) Nimble memory system 2 block size.
    HOST  --->
    Controller  --->
    Transport  --->
    Drivers  --->
[*] NimBLE use tinycrypt in SM.

进入'Components→BLE→NimBLE→HOST',使能'Indicates that a BLE host is present'项以使能BLE HOST的功能,使能后配置HOST相关的特性。

[*] Indicates that a BLE host is present.
(1024)  BLE host thread stack size
(5)     BLE host thread priority
(1)     Causes the BLE host to automatically start during system     initialization.
[ ]     Enables extra runtime assertions.
(0)     Rather than wait for HCI acknowledgements from a controller, the host simulates incoming acks
(1)     Specifies whether the host can depend on the kernel being present
[ ]     Enables monitor interface over UART
(uart0) Monitor interface UART device
(1000000) Baudrate for monitor interface UART
(64)    Monitor interface ringbuffer size for UART. This value should be a power of 2.
[ ]     Enables monitor interface over RTT
(btmonitor) Monitor interface upstream buffer name
(256)   Monitor interface upstream buffer size
[*]     Enables buffering when using monitor interface over RTT
(128)   Size of internal buffer for console output. Any line exceeding this length value will be split.
(3)     The number of L2CAP channels to allocate
(1)     The maximum number of concurrent L2CAP signal procedures.
[*]     Whether to collapse incoming L2CAP fragments into a minimal set of mbufs
(30000) Expiry time for incoming data packets (ms)
(0)     Defines maximum number of LE Connection Oriented Channels channels
(292)   Defines the MPS of L2CAP COC module. The default value was 'MYNEWT_VAL_MSYS_1_BLOCK_SIZE-8' before stack ported.
......

进入'Components→BLE→NimBLE→Controller',使能'Indicates that NimBLE controller is present...'项以使能BLE Controller的功能,使能后配置Controller相关的特性。

[*] Indicates that NimBLE controller is present. The default value forthis setting shall not be overriden.
(2048)  BLE controller thread stack size
(4)     BLE controller thread priority
[*]     Used to enable hardware white list
[ ]     Enable SystemView tracing module for controller.
(0)     The priority of the LL task
(60)    Sleep clock accuracy of our device (in ppm)
(0)     Transmit power level.
(2000)  Determines the interval at which the controller will send the number of completed packets event to the host
(0xFFFF) Manufacturer ID. Should be set to unique ID per manufacturer.
(8)     The number of duplicate advertisers stored.
(8)     The number of advertisers from which we have heard a scan response
(8)     Size of the LL whitelist.
(4)     Size of the resolving list.
(251)   The maximum PDU size that can be sent/received
(251)   The maximum supported received PDU size
(251)   The maximum supported transmit PDU size
(27)    Used to set the initial maximum transmit PDU size in a connection
(4)     This is the number of 'slots' allocated to a connection when scheduling connections
......

注意事项

  1. 使用Nrf52系列平台并且使能controller时,协议栈会使用RTC0和Timer0,所以在menuconfig里不能使能Drivers->HAL下面的timer0和rtc。
  2. 如果选择keil编译,keil arm compiler版本需支持version 6,并在'Options->Target'下选择'Use default compiler version 6',并取消对'Use MicroLIB'的勾选。

Nimble API

API说明

Nimble协议栈提供的接口较多,此文档仅列出部分常用接口,详细信息请访问官网。

API列表

接口 说明
ble_hs_id_gen_rnd 生成新的随机设备地址
ble_hs_id_set_rnd 将设备地址设置为随机设备地址
ble_gap_adv_set_fields 配置广播中Payload的字段。
ble_gap_adv_start 开始广播。此功能配置并启动广播过程。
ble_svc_gap_device_name_set 设置gap服务中的设备名称。
ble_hs_adv_parse_fields 对广播包及扫描应答包中的payload数据进行解析。
ble_gap_disc 执行有限或通用发现过程。
ble_gap_terminate 终止已建立的连接。
ble_uuid_cmp 比较两个uuid值是否相等。
ble_gap_disc_cancel 取消当前正在进行的发现过程。
ble_gap_connect 启动连接过程。
ble_hs_util_ensure_addr 确定设备将使用的地址。
ble_hs_id_infer_auto 获取设备将使用的地址类型。
ble_gap_adv_rsp_set_fields 配置扫描应答中的payload字段。
ble_svc_gap_device_appearance 设置gap服务中设备类型。
ble_gattc_indicate_custom 发送“自由格式”特性指示。
ble_gattc_notify_custom 发送“自由格式”特性通知。
ble_gatts_count_cfg 调整主机配置对象的设置,以适应指定的'服务组'。
ble_gatts_add_svcs 对'服务组'进行排队以进行注册。
ble_gap_ext_adv_configure 配置扩展广播实例。
ble_gap_ext_adv_set_addr 为配置的广播实例设置随机地址。
ble_hs_adv_set_fields 将广播数据信息结构转换为广播数据队列。
ble_gap_ext_adv_set_data 配置数据以包含在指定广播实例的广播包中。
ble_gap_ext_adv_rsp_set_data 配置数据以包含在指定广播实例的后续扫描响应中。
ble_gap_ext_adv_start 启动广播实例。
ble_gap_ext_disc 执行有限或通用扩展发现程序。

API详情

ble_hs_id_gen_rnd

生成新的随机设备地址。

int ble_hs_id_gen_rnd(int nrpa, ble_addr_t *out_addr);
参数 说明
nrpa 是否设为不可解析私有地址,1-不可解析私有地址,非1-可解析私有地址
out_addr 存放生成的地址
返回 说明
运行结果。0-成功,非0-错误码

ble_hs_id_set_rnd

int ble_hs_id_set_rnd(const uint8_t *rnd_addr);

将设备地址设置为随机设备地址。

参数 说明
rnd_addr 需要设置的随机设备地址数组(ble_addr_t.val)
返回 说明
运行结果。0-成功,非0-错误码

ble_gap_adv_set_fields

int ble_gap_adv_set_fields(const struct ble_hs_adv_fields *adv_fields);

配置广播中Payload的字段。这是ble_gap_adv_set_data()的便捷包装。

参数 说明
adv_fields 指定广播数据
返回 说明
设置结果。0-成功;BLE_HS_EBUSY-当前正在进行广播,失败;BLE_HS_EMSGSIZE-指定数据太大而不能容纳,失败;其他-错误代码。

ble_gap_adv_start

int ble_gap_adv_start(uint8_t own_addr_type,
                      const ble_addr_t *direct_addr,
                      int32_t duration_ms,
                      const struct ble_gap_adv_params *adv_params,
                      ble_gap_event_fn *cb,
                      void *cb_arg);

开始广播。此功能配置并启动广播过程。

参数 说明
own_addr_type 堆栈需使用的地址类型。有效值为:BLE_OWN_ADDR_PUBLIC /BLE_OWN_ADDR_RANDOM /BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT /BLE_OWN_ADDR_RPA_RANDOM_DEFAULT
direct_addr 定向广播的目的地址。如果使用定向广播,则此参数不得为NULL。
duration_ms 广播过程的持续时间。时间到期时,过程结束,并报告BLE_GAP_EVENT_ADV_COMPLETE事件。单位是毫秒。指定值BLE_HS_FOREVER以永不过期。
adv_params 指定广播过程细节的其他参数。
cb 与该广播过程关联的回调。如果广播结束,则通过此回调报告事件。如果广播导致建立连接,则该连接将继承此回调作为其事件报告机制。
cb_arg 传递给回调函数的可选参数。
返回 说明
操作结果。0-成功,非0-错误码。

ble_svc_gap_device_name_set

int ble_svc_gap_device_name_set(const char *name);

设置gap服务中的设备名称。

参数 说明
name 设备名称
返回 说明
运行结果。0-成功,非0-错误码。

ble_hs_adv_parse_fields

int ble_hs_adv_parse_fields(struct ble_hs_adv_fields *adv_fields,
                            const uint8_t *src,
                            uint8_t src_len);

对广播包及扫描应答包中的payload数据进行解析。

参数 说明
adv_fields 存放解析后获得的信息。
src payload数据。
src_len payload数据长度。
返回 说明
运行结果。0-成功,非0-错误码。

ble_gap_disc

int ble_gap_disc(uint8_t own_addr_type,
                 int32_t duration_ms,
                 const struct ble_gap_disc_params *disc_params,
                 ble_gap_event_fn *cb,
                 void *cb_arg);

执行有限或通用发现过程。

参数 说明
own_addr_type 发送扫描请求时,堆栈需使用的地址类型。有效值为: BLE_ADDR_TYPE_PUBLIC /BLE_ADDR_TYPE_RANDOM /BLE_ADDR_TYPE_RPA_PUB_DEFAULT /BLE_ADDR_TYPE_RPA_RND_DEFAULT(除非使用主动扫描,否则将忽略此参数。)
duration_ms 发现过程的持续时间。时间到期时,过程结束,并报告BLE_GAP_EVENT_DISC_COMPLETE事件。单位是毫秒。指定值BLE_HS_FOREVER以永不过期。指定值0以使用堆栈中的默认值。
disc_params 指定发现过程中的细节。
cb 与该发现过程关联的回调。通过此回调报告广播报告和发现终止事件。
cb_arg 传递给回调函数的可选参数。
返回 说明
运行结果。0-成功,非0-错误码。

ble_gap_terminate

int ble_gap_terminate(uint16_t conn_handle, uint8_t hci_reason);

终止已建立的连接。

参数 说明
conn_handle 终止连接所对应的句柄。
hci_reason 指示终止原因的HCI错误代码。
返回 说明
运行结果。0-成功;BLE_HS_ENOTCONN-指定的句柄没有连接; 其他-错误码。

ble_uuid_cmp

int ble_uuid_cmp(const ble_uuid_t *uuid1, const ble_uuid_t *uuid2);

比较两个uuid值是否相等。

参数 说明
uuid1
uuid2
返回 说明
比较结果。0-相等,非0-不相等。

ble_gap_disc_cancel

int ble_gap_disc_cancel(void);

取消当前正在进行的发现过程。Return成功码表示扫描已完全中止; 可以立即启动新的发现或连接过程。

参数 说明
None
返回 说明
运行结果。0-操作成功;BLE_HS_EALREADY-没有发现过程可取消; 其他-意外错误的错误码。

ble_gap_connect

int ble_gap_connect(uint8_t own_addr_type,
                    const ble_addr_t *peer_addr,
                    int32_t duration_ms,
                    const struct ble_gap_conn_params *conn_params,
                    ble_gap_event_fn *cb,
                    void *cb_arg);

启动连接过程。

参数 说明
own_addr_type 连接建立期间堆栈应使用的地址类型: BLE_OWN_ADDR_PUBLIC /BLE_OWN_ADDR_RANDOM /BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT /BLE_OWN_ADDR_RPA_RANDOM_DEFAULT
peer_addr 要连接的对端设备的地址。如果此参数为NULL,则使用白名单。
duration_ms 发现过程的持续时间。时间到期时,过程结束,并报告BLE_GAP_EVENT_DISC_COMPLETE事件。单位是毫秒。
conn_params 指定连接过程细节。指定null使用默认值。
cb 与该连接过程关联的回调函数。连接过程完成后,将通过此回调报告结果。如果连接成功,则连接将继承此回调作为其事件报告机制。
cb_arg 传递给回调函数的可选参数。
返回 说明
运行结果。0-操作成功;BLE_HS_EALREADY-已经在进行连接尝试;BLE_HS_EBUSY-正在进行扫描而无法启动连接;BLE_HS_EDONE-指定的对等点已经连接;其他-错误码。

ble_hs_util_ensure_addr

int ble_hs_util_ensure_addr(int prefer_random);

确定设备将使用的地址。

参数 说明
prefer_random 是否倾向使用随机设备地址,1 是,非1 不是。
返回 说明
运行结果。0-成功,非0-错误码

ble_hs_id_infer_auto

int ble_hs_id_infer_auto(int privacy, uint8_t *out_addr_type);

获取设备将使用的地址类型。

参数 说明
privacy 1 使用私有地址, 非1 使用公共地址。
out_addr_type 保存设备将使用的地址类型。
返回 说明
运行结果。0-成功,非0-错误码。

ble_gap_adv_rsp_set_fields

int ble_gap_adv_rsp_set_fields(const struct ble_hs_adv_fields *rsp_fields);

配置扫描应答中的payload字段。这是ble_gap_adv_rsp_set_data()的便捷包装。

参数 说明
adv_fields 指定扫描应答数据。
返回 说明
运行结果。0-成功;BLE_HS_EBUSY-正在进行广播;BLE_HS_EMSGSIZE-指定数据太大而无法容纳扫描响应;其他-错误码。

ble_svc_gap_device_appearance

uint16_t ble_svc_gap_device_appearance(void);

设置gap服务中设备类型。(GAP_APPEARANCE用来表示设备会在对端设备上,比如说手机,显示为什么设备)。

参数 说明
None
返回 说明
返回类型值。

ble_gattc_indicate_custom

int ble_gattc_indicate_custom(uint16_t conn_handle,
                              uint16_t chr_val_handle,
                              struct os_mbuf *txom);

发送“自由格式”特性指示。提供的mbuf包含指示的有效负载。无论结果如何,此函数都会消耗提供的mbuf。

参数 说明
conn_handle 对应连接的句柄。
chr_val_handle 将包含在指示中的特性值的属性句柄。
txom 将包含在指示中的数据。
返回 说明
运行结果。0-成功;非0-错误码。

ble_gattc_notify_custom

int ble_gattc_notify_custom(uint16_t conn_handle,
                            uint16_t chr_val_handle,
                            struct os_mbuf *txom);

发送“自由格式”特性通知。无论结果如何,此函数都会消耗提供的mbuf。

参数 说明
conn_handle 对应连接的句柄。
chr_val_handle 将包含在通知中的属性句柄。
txom 写入特性的值。
返回 说明
运行结果。0-成功;非0-错误码。

ble_gatts_count_cfg

int ble_gatts_count_cfg(const struct ble_gatt_svc_def *defs);

调整主机配置对象的设置,以适应指定的'服务组'。此函数将计数添加到提供的配置对象中的相应字段,而无需先清除它们,因此可以使用不同的输入重复调用以计算总数。 在首次调用此功能之前,请确保将GATT服务器设置归零。

参数 说明
defs 包含要计数的'资源定义'的'服务组'。
返回 说明
运行结果。0-成功;BLE_HS_EINVAL-'服务组'包含无效的'资源定义'。

ble_gatts_add_svcs

int ble_gatts_add_svcs(const struct ble_gatt_svc_def *svcs);

对'服务组'进行排队以进行注册。当调用ble_gatts_start()时,以这种方式排队的所有服务都会被注册。

参数 说明
svcs 要排队注册的'服务组'。 此数组必须以“类型”等于0的条目结尾。
返回 说明
运行结果。0-成功;BLE_HS_ENOMEM-堆耗尽。

ble_gap_ext_adv_configure

int ble_gap_ext_adv_configure(uint8_t instance,
                              const struct ble_gap_ext_adv_params * params,
                              int8_t * selected_tx_power,
                              ble_gap_event_fn * cb,
                              void * cb_arg);

配置扩展广播实例。

参数 说明
instance 实例ID
params 指定广播细节的其他参数
selected_tx_power 如果非NULL,则所选广播的发送功率将存储在该参数中
cb 与该广播过程关联的回调。 通过此回调报告广播完成事件
cb_arg 传递给回调函数的可选参数
返回 说明
配置结果。0-成功,非零-错误码。

ble_gap_ext_adv_set_addr

int ble_gap_ext_adv_set_addr(uint8_t instance,
                             const ble_addr_t * addr);

为配置的广播实例设置随机地址。

参数 说明
instance 实例ID
addr 要设置的随机地址
返回 说明
配置结果。0-成功,非零-错误码。

ble_hs_adv_set_fields

int ble_hs_adv_set_fields(const struct ble_hs_adv_fields * adv_fields,
                          uint8_t * dst,
                          uint8_t * dst_len,
                          uint8_t max_len);

将广播数据信息结构转换为广播数据队列。

参数 说明
adv_fields 广播数据信息结构
dst 转换后存放广播数据的队列
dst_len 转换后存放广播数据长度
max_len 队列长度
返回 说明
转换结果。0-成功,非零-错误码。

ble_gap_ext_adv_set_data

int ble_gap_ext_adv_set_data(uint8_t instance,
                             struct os_mbuf * data);

配置数据以包含在指定广播实例的广播包中。

参数 说明
instance 实例ID
data 包含广播数据的链
返回 说明
配置结果。0-成功,非零-错误码。

ble_gap_ext_adv_rsp_set_data

int ble_gap_ext_adv_rsp_set_data(uint8_t instance,
                                 struct os_mbuf * data);

配置数据以包含在指定广播实例的后续扫描响应中。

参数 说明
instance 实例ID
data 包含数据的链
返回 说明
配置结果。0-成功,非零-错误码。

ble_gap_ext_adv_start

int ble_gap_ext_adv_start(uint8_t instance,
                          int duration,
                          int max_events);

启动广播实例。

参数 说明
instance 实例ID
duration 广播过程的持续时间。到期时,过程结束,并报告BLE_GAP_EVENT_ADV_COMPLETE事件。单位为10毫秒。指定0为无到期时间。
max_events 广播结束之前应发送的广播事件数,并报告BLE_GAP_EVENT_ADV_COMPLETE事件。 0-无限制地。
返回 说明
操作结果。0-成功,非零-错误码。

ble_gap_ext_disc

int ble_gap_ext_disc(uint8_t own_addr_type,
                     uint16_t duration,
                     uint16_t period,
                     uint8_t filter_duplicates,
                     uint8_t filter_policy,
                     uint8_t limited,
                     const struct ble_gap_ext_disc_params * uncoded_params,
                     const struct ble_gap_ext_disc_params * coded_params,
                     ble_gap_event_fn * cb,
                     void * cb_arg);

执行有限或通用扩展发现程序。

参数 说明
own_addr_type 发送扫描请求时,堆栈应使用的地址类型。有效值为:BLE_ADDR_TYPE_PUBLIC /BLE_ADDR_TYPE_RANDOM /BLE_ADDR_TYPE_RPA_PUB_DEFAULT /BLE_ADDR_TYPE_RPA_RND_DEFAULT(除非使用主动扫描,否则将忽略此参数)。
duration 发现过程的持续时间。到期时,如果将period设置为0,则过程结束,并报告BLE_GAP_EVENT_DISC_COMPLETE事件。单位为10毫秒。指定0为无到期时间。
period 从控制器开始其上一个扫描间隙(Scan Duration)到随后开始的扫描间隙的时间间隔。指定0以连续扫描。单位是1.28秒。
filter_duplicates 是否过滤重复项
filter_policy 过滤策略
limited 是否使用有限发现程序。
uncoded_params 附加参数,用于指定uncoded PHY的发现过程的细节。如果提供NULL,则不会对此PHY执行任何扫描。
coded_params 附加参数,用于指定coded PHY的发现过程的详细信息。如果提供NULL,则不会对此PHY执行任何扫描。
cb 与该发现过程关联的回调。通过此回调报告广播报告和发现终止事件。
cb_arg 传递给回调函数的可选参数。
返回 说明
操作结果。0-成功,非零-错误码。

示例

外围设备BLE Cycling Speed and Cadence peripheral app例程(application.csc)

该例程具有gatt服务,在手机上使用APP即可连接设备并使用服务。在ios上使用‘LightBlue’即可。在APP内可以搜索到‘blecsc_sensor’设备,点击连接。

进入后点击‘Cycling Speed and Cadence’下面的‘0x2A5B’特性进行设置,点击‘Listen for notification’后即可接收信息。

进入‘0x2A55’特性进行设置,点击‘Listen for notification’,然后点击‘Write new value’,输入‘0388’并确定,设备输出‘SC Control Point; opcode=3 SC Control Point; Sensor location update =136’,同时在手机上将收到提示。

// BLE section in .config
#
# BLE
#
CONFIG_OS_USING_BLE=y
CONFIG_BLE_USING_NIMBLE=y

#
# NimBLE
#
CONFIG_BLE_ROLE_BROADCASTER=y
CONFIG_MYNEWT_VAL_BLE_ROLE_BROADCASTER=1
CONFIG_BLE_ROLE_PERIPHERAL=y
CONFIG_MYNEWT_VAL_BLE_ROLE_PERIPHERAL=1
# CONFIG_BLE_ROLE_OBSERVER is not set
CONFIG_MYNEWT_VAL_BLE_ROLE_OBSERVER=0
# CONFIG_BLE_ROLE_CENTRAL is not set
CONFIG_MYNEWT_VAL_BLE_ROLE_CENTRAL=0
CONFIG_MYNEWT_VAL_BLE_MAX_CONNECTIONS=1
CONFIG_MYNEWT_VAL_BLE_MAX_PERIODIC_SYNCS=1
CONFIG_BLE_WHITELIST=y
CONFIG_MYNEWT_VAL_BLE_WHITELIST=1
CONFIG_MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES=0
# CONFIG_BLE_EXT_ADV is not set
CONFIG_MYNEWT_VAL_BLE_EXT_ADV=0
# CONFIG_BLE_PERIODIC_ADV is not set
CONFIG_MYNEWT_VAL_BLE_PERIODIC_ADV=0
# CONFIG_BLE_PERIODIC_ADV_SYNC_TRANSFER is not set
CONFIG_MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER=0
CONFIG_MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE=31
CONFIG_MYNEWT_VAL_BLE_VERSION=50
# CONFIG_BLE_ISO is not set
CONFIG_MYNEWT_VAL_BLE_ISO=0
# CONFIG_BLE_ISO_TEST is not set
CONFIG_MYNEWT_VAL_BLE_ISO_TEST=0
CONFIG_MYNEWT_VAL_MSYS_1_BLOCK_COUNT=12
CONFIG_MYNEWT_VAL_MSYS_1_BLOCK_SIZE=292
CONFIG_MYNEWT_VAL_MSYS_2_BLOCK_COUNT=0
CONFIG_MYNEWT_VAL_MSYS_2_BLOCK_SIZE=0

#
# HOST
#
CONFIG_OS_USING_NIMBLE_HOST=y
CONFIG_MYNEWT_VAL_BLE_HOST=1
CONFIG_NIMBLE_CFG_HOST=1
CONFIG_MYNEWT_VAL_BLE_HOST_THREAD_STACK_SIZE=2048
CONFIG_MYNEWT_VAL_BLE_HOST_THREAD_PRIORITY=5
CONFIG_MYNEWT_VAL_BLE_HS_AUTO_START=1
# CONFIG_BLE_HS_DEBUG is not set
CONFIG_MYNEWT_VAL_BLE_HS_DEBUG=0
CONFIG_MYNEWT_VAL_BLE_HS_PHONY_HCI_ACKS=0
CONFIG_MYNEWT_VAL_BLE_HS_REQUIRE_OS=1
# CONFIG_BLE_MONITOR_UART is not set
CONFIG_MYNEWT_VAL_BLE_MONITOR_UART=0
CONFIG_MYNEWT_VAL_BLE_MONITOR_UART_DEV="uart0"
CONFIG_MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE=1000000
CONFIG_MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE=64
# CONFIG_BLE_MONITOR_RTT is not set
CONFIG_MYNEWT_VAL_BLE_MONITOR_RTT=0
CONFIG_MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME="btmonitor"
CONFIG_MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE=256
CONFIG_BLE_MONITOR_RTT_BUFFERED=y
CONFIG_MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED=1
CONFIG_MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE=128
CONFIG_MYNEWT_VAL_BLE_L2CAP_MAX_CHANS=3
CONFIG_MYNEWT_VAL_BLE_L2CAP_SIG_MAX_PROCS=1
CONFIG_BLE_L2CAP_JOIN_RX_FRAGS=y
CONFIG_MYNEWT_VAL_BLE_L2CAP_JOIN_RX_FRAGS=1
CONFIG_MYNEWT_VAL_BLE_L2CAP_RX_FRAG_TIMEOUT=30000
CONFIG_MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM=0
CONFIG_MYNEWT_VAL_BLE_L2CAP_COC_MPS=292
# CONFIG_BLE_L2CAP_ENHANCED_COC is not set
CONFIG_MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC=0
CONFIG_MYNEWT_VAL_BLE_SM_LEGACY=1
# CONFIG_BLE_SM_SC is not set
CONFIG_MYNEWT_VAL_BLE_SM_SC=0
CONFIG_MYNEWT_VAL_BLE_SM_MAX_PROCS=1
CONFIG_MYNEWT_VAL_BLE_SM_IO_CAP=0x03
# CONFIG_BLE_SM_OOB_DATA_FLAG is not set
CONFIG_MYNEWT_VAL_BLE_SM_OOB_DATA_FLAG=0
# CONFIG_BLE_SM_BONDING is not set
CONFIG_MYNEWT_VAL_BLE_SM_BONDING=0
# CONFIG_BLE_SM_MITM is not set
CONFIG_MYNEWT_VAL_BLE_SM_MITM=0
# CONFIG_BLE_SM_KEYPRESS is not set
CONFIG_MYNEWT_VAL_BLE_SM_KEYPRESS=0
CONFIG_MYNEWT_VAL_BLE_SM_OUR_KEY_DIST=0
CONFIG_MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST=0
# CONFIG_BLE_SM_SC_DEBUG_KEYS is not set
CONFIG_MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS=0
CONFIG_MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE=1
# CONFIG_BLE_GATT_DISC_ALL_SVCS is not set
CONFIG_MYNEWT_VAL_BLE_GATT_DISC_ALL_SVCS=0
# CONFIG_BLE_GATT_DISC_SVC_UUID is not set
CONFIG_MYNEWT_VAL_BLE_GATT_DISC_SVC_UUID=0
# CONFIG_BLE_GATT_FIND_INC_SVCS is not set
CONFIG_MYNEWT_VAL_BLE_GATT_FIND_INC_SVCS=0
# CONFIG_BLE_GATT_DISC_ALL_CHRS is not set
CONFIG_MYNEWT_VAL_BLE_GATT_DISC_ALL_CHRS=0
# CONFIG_BLE_GATT_DISC_CHR_UUID is not set
CONFIG_MYNEWT_VAL_BLE_GATT_DISC_CHR_UUID=0
# CONFIG_BLE_GATT_DISC_ALL_DSCS is not set
CONFIG_MYNEWT_VAL_BLE_GATT_DISC_ALL_DSCS=0
# CONFIG_BLE_GATT_READ is not set
CONFIG_MYNEWT_VAL_BLE_GATT_READ=0
# CONFIG_BLE_GATT_READ_UUID is not set
CONFIG_MYNEWT_VAL_BLE_GATT_READ_UUID=0
# CONFIG_BLE_GATT_READ_LONG is not set
CONFIG_MYNEWT_VAL_BLE_GATT_READ_LONG=0
# CONFIG_BLE_GATT_READ_MULT is not set
CONFIG_MYNEWT_VAL_BLE_GATT_READ_MULT=0
# CONFIG_BLE_GATT_WRITE_NO_RSP is not set
CONFIG_MYNEWT_VAL_BLE_GATT_WRITE_NO_RSP=0
# CONFIG_BLE_GATT_SIGNED_WRITE is not set
CONFIG_MYNEWT_VAL_BLE_GATT_SIGNED_WRITE=0
# CONFIG_BLE_GATT_WRITE is not set
CONFIG_MYNEWT_VAL_BLE_GATT_WRITE=0
# CONFIG_BLE_GATT_WRITE_LONG is not set
CONFIG_MYNEWT_VAL_BLE_GATT_WRITE_LONG=0
# CONFIG_BLE_GATT_WRITE_RELIABLE is not set
CONFIG_MYNEWT_VAL_BLE_GATT_WRITE_RELIABLE=0
CONFIG_BLE_GATT_NOTIFY=y
CONFIG_MYNEWT_VAL_BLE_GATT_NOTIFY=1
CONFIG_BLE_GATT_INDICATE=y
CONFIG_MYNEWT_VAL_BLE_GATT_INDICATE=1
CONFIG_MYNEWT_VAL_BLE_GATT_READ_MAX_ATTRS=8
CONFIG_MYNEWT_VAL_BLE_GATT_WRITE_MAX_ATTRS=4
CONFIG_MYNEWT_VAL_BLE_GATT_MAX_PROCS=4
CONFIG_MYNEWT_VAL_BLE_GATT_RESUME_RATE=1000
CONFIG_BLE_ATT_SVR_FIND_INFO=y
CONFIG_MYNEWT_VAL_BLE_ATT_SVR_FIND_INFO=1
CONFIG_BLE_ATT_SVR_FIND_TYPE=y
CONFIG_MYNEWT_VAL_BLE_ATT_SVR_FIND_TYPE=1
CONFIG_BLE_ATT_SVR_READ_TYPE=y
CONFIG_MYNEWT_VAL_BLE_ATT_SVR_READ_TYPE=1
CONFIG_BLE_ATT_SVR_READ=y
CONFIG_MYNEWT_VAL_BLE_ATT_SVR_READ=1
CONFIG_BLE_ATT_SVR_READ_BLOB=y
CONFIG_MYNEWT_VAL_BLE_ATT_SVR_READ_BLOB=1
CONFIG_BLE_ATT_SVR_READ_MULT=y
CONFIG_MYNEWT_VAL_BLE_ATT_SVR_READ_MULT=1
CONFIG_BLE_ATT_SVR_READ_GROUP_TYPE=y
CONFIG_MYNEWT_VAL_BLE_ATT_SVR_READ_GROUP_TYPE=1
CONFIG_BLE_ATT_SVR_WRITE=y
CONFIG_MYNEWT_VAL_BLE_ATT_SVR_WRITE=1
CONFIG_BLE_ATT_SVR_WRITE_NO_RSP=y
CONFIG_MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP=1
CONFIG_BLE_ATT_SVR_SIGNED_WRITE=y
CONFIG_MYNEWT_VAL_BLE_ATT_SVR_SIGNED_WRITE=1
CONFIG_BLE_ATT_SVR_QUEUED_WRITE=y
CONFIG_MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE=1
CONFIG_BLE_ATT_SVR_NOTIFY=y
CONFIG_MYNEWT_VAL_BLE_ATT_SVR_NOTIFY=1
CONFIG_BLE_ATT_SVR_INDICATE=y
CONFIG_MYNEWT_VAL_BLE_ATT_SVR_INDICATE=1
CONFIG_MYNEWT_VAL_BLE_ATT_PREFERRED_MTU=256
CONFIG_MYNEWT_VAL_BLE_ATT_SVR_MAX_PREP_ENTRIES=64
CONFIG_MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE_TMO=30000
CONFIG_MYNEWT_VAL_BLE_RPA_TIMEOUT=300
CONFIG_MYNEWT_VAL_BLE_STORE_MAX_BONDS=3
CONFIG_MYNEWT_VAL_BLE_STORE_MAX_CCCDS=8
# CONFIG_BLE_MESH is not set
CONFIG_MYNEWT_VAL_BLE_MESH=0
# CONFIG_BLE_HS_FLOW_CTRL is not set
CONFIG_MYNEWT_VAL_BLE_HS_FLOW_CTRL=0
CONFIG_MYNEWT_VAL_BLE_HS_FLOW_CTRL_ITVL=1000
CONFIG_MYNEWT_VAL_BLE_HS_FLOW_CTRL_THRESH=2
CONFIG_MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT=0
CONFIG_MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN=1
CONFIG_MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT=2000
CONFIG_MYNEWT_VAL_BLE_HS_SYSINIT_STAGE=200
CONFIG_MYNEWT_VAL_BLE_HS_LOG_MOD=4
CONFIG_MYNEWT_VAL_BLE_HS_LOG_LVL=1

#
# Services
#

#
# ans
#
CONFIG_MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT=0
CONFIG_MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT=0
CONFIG_MYNEWT_VAL_BLE_SVC_ANS_SYSINIT_STAGE=303
# end of ans

#
# bas
#
CONFIG_MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_READ_PERM=0
CONFIG_MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE=1
CONFIG_MYNEWT_VAL_BLE_SVC_BAS_SYSINIT_STAGE=303
# end of bas

#
# bleuart
#
CONFIG_MYNEWT_VAL_BLEUART_MAX_INPUT=120
CONFIG_MYNEWT_VAL_BLEUART_SYSINIT_STAGE=500
# end of bleuart

#
# dis
#
CONFIG_MYNEWT_VAL_BLE_SVC_DIS_DEFAULT_READ_PERM=-1
CONFIG_MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_READ_PERM=0
CONFIG_MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT="Apache Mynewt NimBLE"
CONFIG_MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_READ_PERM=-1
CONFIG_MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_DEFAULT="notset"
CONFIG_MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_READ_PERM=-1
CONFIG_MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_DEFAULT="notset"
CONFIG_MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM=-1
CONFIG_MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_DEFAULT="notset"
CONFIG_MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_READ_PERM=-1
CONFIG_MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_DEFAULT="notset"
CONFIG_MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_READ_PERM=-1
CONFIG_MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_DEFAULT="notset"
CONFIG_MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM=-1
CONFIG_MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_DEFAULT="notset"
CONFIG_MYNEWT_VAL_BLE_SVC_DIS_SYSINIT_STAGE=303
# end of dis

#
# gap
#
CONFIG_MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME="nimble"
CONFIG_MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_WRITE_PERM=-1
CONFIG_MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH=31
CONFIG_MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE=1157
CONFIG_MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE_WRITE_PERM=-1
CONFIG_MYNEWT_VAL_BLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL=0
CONFIG_MYNEWT_VAL_BLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL=0
CONFIG_MYNEWT_VAL_BLE_SVC_GAP_PPCP_SLAVE_LATENCY=0
CONFIG_MYNEWT_VAL_BLE_SVC_GAP_PPCP_SUPERVISION_TMO=0
CONFIG_MYNEWT_VAL_BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION=-1
CONFIG_MYNEWT_VAL_BLE_SVC_GAP_SYSINIT_STAGE=301
# end of gap

#
# gatt
#
CONFIG_MYNEWT_VAL_BLE_SVC_GATT_SYSINIT_STAGE=302
# end of gatt

#
# ias
#
CONFIG_MYNEWT_VAL_BLE_SVC_IAS_SYSINIT_STAGE=303
# end of ias

#
# ipss
#
CONFIG_MYNEWT_VAL_BLE_SVC_IPSS_SYSINIT_STAGE=303
# end of ipss

#
# lls
#
CONFIG_MYNEWT_VAL_BLE_SVC_LLS_SYSINIT_STAGE=303
# end of lls

#
# tps
#
CONFIG_MYNEWT_VAL_BLE_SVC_TPS_SYSINIT_STAGE=303
# end of tps
# end of Services

#
# Store
#

#
# config
#
CONFIG_MYNEWT_VAL_BLE_STORE_CONFIG_PERSIST=1
CONFIG_MYNEWT_VAL_BLE_STORE_SYSINIT_STAGE=500
# end of config

#
# ram
#
CONFIG_MYNEWT_VAL_BLE_STORE_RAM_SYSINIT_STAGE=500
CONFIG_MYNEWT_VAL_BLE_STORE_RAM_DEPRECATED_FLAG=0
# end of ram
# end of Store

#
# Mesh
#
# CONFIG_BLE_HOST_MESH is not set
# end of Mesh
# end of HOST

#
# Controller
#
CONFIG_OS_USING_NIMBLE_CONTROLLER=y
CONFIG_MYNEWT_VAL_BLE_CONTROLLER=1
CONFIG_NIMBLE_CFG_CONTROLLER=1
CONFIG_MYNEWT_VAL_BLE_CTLR_THREAD_STACK_SIZE=2048
CONFIG_MYNEWT_VAL_BLE_CTLR_THREAD_PRIORITY=4
CONFIG_BLE_HW_WHITELIST_ENABLE=y
CONFIG_MYNEWT_VAL_BLE_HW_WHITELIST_ENABLE=1
# CONFIG_BLE_LL_SYSVIEW is not set
CONFIG_MYNEWT_VAL_BLE_LL_SYSVIEW=0
CONFIG_MYNEWT_VAL_BLE_LL_PRIO=0
CONFIG_MYNEWT_VAL_BLE_LL_SCA=60
CONFIG_MYNEWT_VAL_BLE_LL_TX_PWR_DBM=0
CONFIG_MYNEWT_VAL_BLE_LL_NUM_COMP_PKT_ITVL_MS=2000
CONFIG_MYNEWT_VAL_BLE_LL_MFRG_ID=0xFFFF
CONFIG_MYNEWT_VAL_BLE_LL_NUM_SCAN_DUP_ADVS=8
CONFIG_MYNEWT_VAL_BLE_LL_NUM_SCAN_RSP_ADVS=8
CONFIG_MYNEWT_VAL_BLE_LL_WHITELIST_SIZE=8
CONFIG_MYNEWT_VAL_BLE_LL_RESOLV_LIST_SIZE=4
CONFIG_MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE=251
CONFIG_MYNEWT_VAL_BLE_LL_SUPP_MAX_RX_BYTES=251
CONFIG_MYNEWT_VAL_BLE_LL_SUPP_MAX_TX_BYTES=251
CONFIG_MYNEWT_VAL_BLE_LL_CONN_INIT_MAX_TX_BYTES=27
CONFIG_MYNEWT_VAL_BLE_LL_CONN_INIT_SLOTS=4
CONFIG_MYNEWT_VAL_BLE_LL_CONN_INIT_MIN_WIN_OFFSET=0
CONFIG_MYNEWT_VAL_BLE_LL_STRICT_CONN_SCHEDULING=0
CONFIG_MYNEWT_VAL_BLE_LL_ADD_STRICT_SCHED_PERIODS=0
CONFIG_MYNEWT_VAL_BLE_LL_USECS_PER_PERIOD=3250
CONFIG_MYNEWT_VAL_BLE_LL_RNG_BUFSIZE=32
CONFIG_MYNEWT_VAL_BLE_LL_RFMGMT_ENABLE_TIME=0
CONFIG_BLE_LL_CFG_FEAT_LE_ENCRYPTION=y
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION=1
CONFIG_BLE_LL_CFG_FEAT_CONN_PARAM_REQ=y
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_CONN_PARAM_REQ=1
CONFIG_BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG=y
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG=1
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_PING=1
CONFIG_BLE_LL_CFG_FEAT_DATA_LEN_EXT=y
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_DATA_LEN_EXT=1
CONFIG_BLE_LL_CFG_FEAT_LL_PRIVACY=y
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PRIVACY=1
# CONFIG_BLE_LL_CFG_FEAT_LE_CSA2 is not set
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CSA2=0
# CONFIG_BLE_LL_CFG_FEAT_LE_2M_PHY is not set
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_2M_PHY=0
# CONFIG_BLE_LL_CFG_FEAT_LE_CODED_PHY is not set
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CODED_PHY=0
# CONFIG_BLE_LL_CFG_FEAT_LL_EXT_ADV is not set
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_EXT_ADV=0
# CONFIG_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV is not set
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV=0
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_CNT=1
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_LIST_CNT=1
# CONFIG_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER is not set
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER=0
# CONFIG_BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL is not set
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL=0
# CONFIG_BLE_LL_CFG_FEAT_LL_SCA_UPDATE is not set
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_SCA_UPDATE=0
# CONFIG_BLE_LL_CFG_FEAT_LL_ISO is not set
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_ISO=0
# CONFIG_BLE_LL_CFG_FEAT_LL_ISO_TEST is not set
CONFIG_MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_ISO_TEST=0
CONFIG_MYNEWT_VAL_BLE_LL_EXT_ADV_AUX_PTR_CNT=0
# CONFIG_BLE_LL_DTM is not set
CONFIG_MYNEWT_VAL_BLE_LL_DTM=0
# CONFIG_BLE_LL_DTM_EXTENSIONS is not set
CONFIG_MYNEWT_VAL_BLE_LL_DTM_EXTENSIONS=0
CONFIG_BLE_LL_VND_EVENT_ON_ASSERT=y
CONFIG_MYNEWT_VAL_BLE_LL_VND_EVENT_ON_ASSERT=1
CONFIG_MYNEWT_VAL_BLE_LL_SYSINIT_STAGE=250
CONFIG_MYNEWT_VAL_BLE_LL_DEBUG_GPIO_HCI_CMD=-1
CONFIG_MYNEWT_VAL_BLE_LL_DEBUG_GPIO_HCI_EV=-1
CONFIG_MYNEWT_VAL_BLE_LL_DEBUG_GPIO_SCHED_RUN=-1
CONFIG_MYNEWT_VAL_BLE_LL_DEBUG_GPIO_SCHED_ITEM_CB=-1
CONFIG_MYNEWT_VAL_BLE_LL_SCHED_AUX_MAFS_DELAY=0
CONFIG_MYNEWT_VAL_BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY=0
CONFIG_MYNEWT_VAL_BLE_LL_SCHED_SCAN_AUX_PDU_LEN=41
CONFIG_MYNEWT_VAL_BLE_LL_SCHED_SCAN_SYNC_PDU_LEN=32
# end of Controller

#
# Transport
#
CONFIG_BLE_USING_RAM=y
# CONFIG_BLE_USING_UART is not set
# CONFIG_BLE_USING_SOCKET is not set
# CONFIG_BLE_USING_USB is not set
# end of Transport

#
# Drivers
#

#
# Nrf52
#
# CONFIG_BLE_PHY_SYSVIEW is not set
CONFIG_MYNEWT_VAL_BLE_PHY_SYSVIEW=0
CONFIG_MYNEWT_VAL_BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN=0
CONFIG_MYNEWT_VAL_BLE_PHY_DBG_TIME_TXRXEN_READY_PIN=-1
CONFIG_MYNEWT_VAL_BLE_PHY_DBG_TIME_ADDRESS_END_PIN=-1
CONFIG_MYNEWT_VAL_BLE_PHY_DBG_TIME_WFR_PIN=-1
# CONFIG_BLE_PHY_NRF52840_ERRATA_164 is not set
CONFIG_MYNEWT_VAL_BLE_PHY_NRF52840_ERRATA_164=0
CONFIG_BLE_PHY_NRF52840_ERRATA_191=y
CONFIG_MYNEWT_VAL_BLE_PHY_NRF52840_ERRATA_191=1
# end of Nrf52
# end of Drivers

CONFIG_NIMBLE_CFG_TINYCRYPT=y
# end of NimBLE
# end of BLE
/* app_cfg.h */
#ifndef _APP_CFG_H_
#define _APP_CFG_H_

#ifndef MYNEWT_VAL_BLE_PUBLIC_DEV_ADDR
#define MYNEWT_VAL_BLE_PUBLIC_DEV_ADDR (((uint8_t[6]){0xcc, 0xbb, 0xaa, 0x33, 0x22, 0x11}))
#endif

#ifndef MYNEWT_VAL_TIMER_5
#define MYNEWT_VAL_TIMER_5 (1)
#endif

#define MYNEWT_VAL_OS_CPUTIME_TIMER_NUM (5)
#endif
/* blecsc_sens.h */
#ifndef H_BLECSC_SENSOR_
#define H_BLECSC_SENSOR_

#include "modlog/modlog.h"
#include "nimble/ble.h"
#include "nimble-console/console.h"

#ifdef __cplusplus
extern "C" {
#endif

#define MODLOG_DFLT(ml_lvl_, ...) console_printf(__VA_ARGS__)

/* Cycling Speed and Cadence configuration */
#define GATT_CSC_UUID                           0x1816
#define GATT_CSC_MEASUREMENT_UUID               0x2A5B
#define GATT_CSC_FEATURE_UUID                   0x2A5C
#define GATT_SENSOR_LOCATION_UUID               0x2A5D
#define GATT_SC_CONTROL_POINT_UUID              0x2A55
/* Device Information configuration */
#define GATT_DEVICE_INFO_UUID                   0x180A
#define GATT_MANUFACTURER_NAME_UUID             0x2A29
#define GATT_MODEL_NUMBER_UUID                  0x2A24

/*CSC Measurement flags*/
#define CSC_MEASUREMENT_WHEEL_REV_PRESENT       0x01
#define CSC_MEASUREMENT_CRANK_REV_PRESENT       0x02

/* CSC feature flags */
#define CSC_FEATURE_WHEEL_REV_DATA              0x01
#define CSC_FEATURE_CRANK_REV_DATA              0x02
#define CSC_FEATURE_MULTIPLE_SENSOR_LOC         0x04

/* Sensor location enum */
#define SENSOR_LOCATION_OTHER                   0
#define SENSOR_LOCATION_TOP_OF_SHOE             1
#define SENSOR_LOCATION_IN_SHOE                 2
#define SENSOR_LOCATION_HIP                     3
#define SENSOR_LOCATION_FRONT_WHEEL             4
#define SENSOR_LOCATION_LEFT_CRANK              5
#define SENSOR_LOCATION_RIGHT_CRANK             6
#define SENSOR_LOCATION_LEFT_PEDAL              7
#define SENSOR_LOCATION_RIGHT_PEDAL             8
#define SENSOR_LOCATION_FROT_HUB                9
#define SENSOR_LOCATION_REAR_DROPOUT            10
#define SENSOR_LOCATION_CHAINSTAY               11
#define SENSOR_LOCATION_REAR_WHEEL              12
#define SENSOR_LOCATION_REAR_HUB                13
#define SENSOR_LOCATION_CHEST                   14
#define SENSOR_LOCATION_SPIDER                  15
#define SENSOR_LOCATION_CHAIN_RING              16

/* SC Control Point op codes */
#define SC_CP_OP_SET_CUMULATIVE_VALUE           1
#define SC_CP_OP_START_SENSOR_CALIBRATION       2
#define SC_CP_OP_UPDATE_SENSOR_LOCATION         3
#define SC_CP_OP_REQ_SUPPORTED_SENSOR_LOCATIONS 4
#define SC_CP_OP_RESPONSE                       16

/*SC Control Point response values */
#define SC_CP_RESPONSE_SUCCESS                  1
#define SC_CP_RESPONSE_OP_NOT_SUPPORTED         2
#define SC_CP_RESPONSE_INVALID_PARAM            3
#define SC_CP_RESPONSE_OP_FAILED                4

/* CSC simulation configuration */
#define CSC_FEATURES                         (CSC_FEATURE_WHEEL_REV_DATA | \
                                              CSC_FEATURE_CRANK_REV_DATA |\
                                              CSC_FEATURE_MULTIPLE_SENSOR_LOC)

struct ble_csc_measurement_state {
    uint32_t cumulative_wheel_rev;
    uint16_t last_wheel_evt_time;
    uint16_t cumulative_crank_rev;
    uint16_t last_crank_evt_time;
};

extern uint16_t csc_measurement_handle;
extern uint16_t csc_control_point_handle;

int gatt_svr_init(struct ble_csc_measurement_state * csc_measurement_state);
int gatt_svr_chr_notify_csc_measurement(uint16_t conn_handle);
void gatt_svr_set_cp_indicate(uint8_t indication_status);

#ifdef __cplusplus
}
#endif

#endif
/* gatt_svr.c */
#include <os_assert.h>
#include <stdio.h>
#include <string.h>
#include "os/os.h"
#include "host/ble_hs.h"
#include "host/ble_uuid.h"
#include "blecsc_sens.h"


#define CSC_ERR_CCC_DESC_IMPROPERLY_CONFIGURED  0x81

static const char *manuf_name = "Apache Mynewt";
static const char *model_num = "Mynewt CSC Sensor";

static const uint8_t csc_supported_sensor_locations[] = {
    SENSOR_LOCATION_FRONT_WHEEL,
    SENSOR_LOCATION_REAR_DROPOUT,
    SENSOR_LOCATION_CHAINSTAY,
    SENSOR_LOCATION_REAR_WHEEL
};

static uint8_t sensor_location = SENSOR_LOCATION_REAR_DROPOUT;
static struct ble_csc_measurement_state * measurement_state;
uint16_t csc_measurement_handle;
uint16_t csc_control_point_handle;
uint8_t csc_cp_indication_status;

static int
gatt_svr_chr_access_csc_measurement(uint16_t conn_handle,
                                    uint16_t attr_handle,
                                    struct ble_gatt_access_ctxt *ctxt,
                                    void *arg);

static int
gatt_svr_chr_access_csc_feature(uint16_t conn_handle,
                                uint16_t attr_handle,
                                struct ble_gatt_access_ctxt *ctxt,
                                void *arg);

static int
gatt_svr_chr_access_sensor_location(uint16_t conn_handle,
                                    uint16_t attr_handle,
                                    struct ble_gatt_access_ctxt *ctxt,
                                    void *arg);

static int
gatt_svr_chr_access_sc_control_point(uint16_t conn_handle,
                                     uint16_t attr_handle,
                                     struct ble_gatt_access_ctxt *ctxt,
                                     void *arg);

static int
gatt_svr_chr_access_device_info(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: Cycling Speed and Cadence */
        .type = BLE_GATT_SVC_TYPE_PRIMARY,
        .uuid = BLE_UUID16_DECLARE(GATT_CSC_UUID),
        .characteristics = (struct ble_gatt_chr_def[]) { {
            /* Characteristic: Cycling Speed and Cadence Measurement */
            .uuid = BLE_UUID16_DECLARE(GATT_CSC_MEASUREMENT_UUID),
            .access_cb = gatt_svr_chr_access_csc_measurement,
            .val_handle = &csc_measurement_handle,
            .flags = BLE_GATT_CHR_F_NOTIFY,
        }, {
            /* Characteristic: Cycling Speed and Cadence features */
            .uuid = BLE_UUID16_DECLARE(GATT_CSC_FEATURE_UUID),
            .access_cb = gatt_svr_chr_access_csc_feature,
            .flags = BLE_GATT_CHR_F_READ,
        }, {
            /* Characteristic: Sensor Location */
            .uuid = BLE_UUID16_DECLARE(GATT_SENSOR_LOCATION_UUID),
            .access_cb = gatt_svr_chr_access_sensor_location,
            .flags = BLE_GATT_CHR_F_READ,
        }, {
            /* Characteristic: SC Control Point*/
            .uuid = BLE_UUID16_DECLARE(GATT_SC_CONTROL_POINT_UUID),
            .access_cb = gatt_svr_chr_access_sc_control_point,
            .val_handle = &csc_control_point_handle,
            .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_INDICATE,
        }, {
            0, /* No more characteristics in this service */
        }, }
    },

    {
        /* Service: Device Information */
        .type = BLE_GATT_SVC_TYPE_PRIMARY,
        .uuid = BLE_UUID16_DECLARE(GATT_DEVICE_INFO_UUID),
        .characteristics = (struct ble_gatt_chr_def[]) { {
            /* Characteristic: * Manufacturer name */
            .uuid = BLE_UUID16_DECLARE(GATT_MANUFACTURER_NAME_UUID),
            .access_cb = gatt_svr_chr_access_device_info,
            .flags = BLE_GATT_CHR_F_READ,
        }, {
            /* Characteristic: Model number string */
            .uuid = BLE_UUID16_DECLARE(GATT_MODEL_NUMBER_UUID),
            .access_cb = gatt_svr_chr_access_device_info,
            .flags = BLE_GATT_CHR_F_READ,
        }, {
            0, /* No more characteristics in this service */
        }, }
    },

    {
        0, /* No more services */
    },
};

static int
gatt_svr_chr_access_csc_measurement(uint16_t conn_handle, uint16_t attr_handle,
                                  struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    return BLE_ATT_ERR_READ_NOT_PERMITTED;
}

static int
gatt_svr_chr_access_csc_feature(uint16_t conn_handle, uint16_t attr_handle,
                                struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    static const uint16_t csc_feature = CSC_FEATURES;
    int rc;

    OS_ASSERT(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
    rc = os_mbuf_append(ctxt->om, &csc_feature, sizeof(csc_feature));

    return (rc == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}

static int
gatt_svr_chr_access_sensor_location(uint16_t conn_handle, uint16_t attr_handle,
                                  struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    int rc;

    OS_ASSERT(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
    rc = os_mbuf_append(ctxt->om, &sensor_location, sizeof(sensor_location));

    return (rc == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}

static int
gatt_svr_chr_access_sc_control_point(uint16_t conn_handle,
                                     uint16_t attr_handle,
                                     struct ble_gatt_access_ctxt *ctxt,
                                     void *arg)
{
    uint8_t op_code;
    uint8_t new_sensor_location;
    uint8_t new_cumulative_wheel_rev_arr[4];
    struct os_mbuf *om_indication;
    uint8_t response = SC_CP_RESPONSE_OP_NOT_SUPPORTED;
    int ii;
    int rc;

    OS_ASSERT(ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR);

    if (!csc_cp_indication_status) {
        MODLOG_DFLT(INFO, "SC Control Point; CCC descriptor "
                          "improperly configured");
        return CSC_ERR_CCC_DESC_IMPROPERLY_CONFIGURED;
    }

    /* Read control point op code*/
    rc = os_mbuf_copydata(ctxt->om, 0, sizeof(op_code), &op_code);
    if (rc != 0){
        return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
    }
    MODLOG_DFLT(INFO, "SC Control Point; opcode=%d\n", op_code);

    /* Allocate response buffer */
    om_indication = ble_hs_mbuf_att_pkt();

    switch(op_code){
#if (CSC_FEATURES & CSC_FEATURE_WHEEL_REV_DATA)
    case SC_CP_OP_SET_CUMULATIVE_VALUE:
        /* Read new cumulative wheel revolutions value*/
        rc = os_mbuf_copydata(ctxt->om, 1,
                              sizeof(new_cumulative_wheel_rev_arr),
                              new_cumulative_wheel_rev_arr);
        if (rc != 0){
            return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
        }

        measurement_state->cumulative_wheel_rev =
                           get_le32(new_cumulative_wheel_rev_arr);

        MODLOG_DFLT(INFO, "SC Control Point; Set cumulative value = %d\n",
                    measurement_state->cumulative_wheel_rev);

        response = SC_CP_RESPONSE_SUCCESS;
        break;
#endif

#if (CSC_FEATURES & CSC_FEATURE_MULTIPLE_SENSOR_LOC)
    case SC_CP_OP_UPDATE_SENSOR_LOCATION:
        /* Read new sensor location value*/
        rc = os_mbuf_copydata(ctxt->om, 1, 1, &new_sensor_location);
        if (rc != 0){
          return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
        }

        MODLOG_DFLT(INFO, "SC Control Point; Sensor location update = %d\n",
                    new_sensor_location);

        /* Verify if requested new location is on supported locations list */
        response = SC_CP_RESPONSE_INVALID_PARAM;
        for (ii = 0; ii < sizeof(csc_supported_sensor_locations); ii++){
            if (new_sensor_location == csc_supported_sensor_locations[ii]){
                sensor_location = new_sensor_location;
                response = SC_CP_RESPONSE_SUCCESS;
                break;
            }
        }
        break;

    case SC_CP_OP_REQ_SUPPORTED_SENSOR_LOCATIONS:
        response = SC_CP_RESPONSE_SUCCESS;
        break;
#endif

    default:
        break;
    }

    /* Append response value */
    rc = os_mbuf_append(om_indication, &response, sizeof(response));

    if (rc != 0){
      return BLE_ATT_ERR_INSUFFICIENT_RES;
    }

#if (CSC_FEATURES & CSC_FEATURE_MULTIPLE_SENSOR_LOC)
    /* In case of supported locations request append locations list */
    if (op_code == SC_CP_OP_REQ_SUPPORTED_SENSOR_LOCATIONS){
      rc = os_mbuf_append(om_indication, &csc_supported_sensor_locations,
                          sizeof(csc_supported_sensor_locations));
    }

    if (rc != 0){
      return BLE_ATT_ERR_INSUFFICIENT_RES;
    }
#endif

    rc = ble_gattc_indicate_custom(conn_handle, csc_control_point_handle,
                                   om_indication);

    return rc;
}

static int
gatt_svr_chr_access_device_info(uint16_t conn_handle, uint16_t attr_handle,
                                struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    uint16_t uuid;
    int rc;

    uuid = ble_uuid_u16(ctxt->chr->uuid);

    if (uuid == GATT_MODEL_NUMBER_UUID) {
        rc = os_mbuf_append(ctxt->om, model_num, strlen(model_num));
        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
    }

    if (uuid == GATT_MANUFACTURER_NAME_UUID) {
        rc = os_mbuf_append(ctxt->om, manuf_name, strlen(manuf_name));
        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
    }

    OS_ASSERT(0);
    return BLE_ATT_ERR_UNLIKELY;
}

int
gatt_svr_chr_notify_csc_measurement(uint16_t conn_handle)
{
    int rc;
    struct os_mbuf *om;
    uint8_t data_buf[11];
    uint8_t data_offset = 1;

    memset(data_buf, 0, sizeof(data_buf));

#if (CSC_FEATURES & CSC_FEATURE_WHEEL_REV_DATA)
    data_buf[0] |= CSC_MEASUREMENT_WHEEL_REV_PRESENT;
    put_le16(&(data_buf[5]), measurement_state->last_wheel_evt_time);
    put_le32(&(data_buf[1]), measurement_state->cumulative_wheel_rev);
    data_offset += 6;
#endif

#if (CSC_FEATURES & CSC_FEATURE_CRANK_REV_DATA)
    data_buf[0] |= CSC_MEASUREMENT_CRANK_REV_PRESENT;
    put_le16(&(data_buf[data_offset]),
             measurement_state->cumulative_crank_rev);
    put_le16(&(data_buf[data_offset + 2]),
             measurement_state->last_crank_evt_time);
    data_offset += 4;
#endif

    om = ble_hs_mbuf_from_flat(data_buf, data_offset);

    rc = ble_gattc_notify_custom(conn_handle, csc_measurement_handle, om);
    return rc;
}

void
gatt_svr_set_cp_indicate(uint8_t indication_status)
{
  csc_cp_indication_status = indication_status;
}

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:
        OS_ASSERT(0);
        break;
    }
}

int
gatt_svr_init(struct ble_csc_measurement_state * csc_measurement_state)
{
    int rc;

    rc = ble_gatts_count_cfg(gatt_svr_svcs);
    if (rc != 0) {
        return rc;
    }

    rc = ble_gatts_add_svcs(gatt_svr_svcs);
    if (rc != 0) {
        return rc;
    }

    measurement_state = csc_measurement_state;

    return 0;
}
/* main.c */
#include <os_assert.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

#include <oneos_config.h>
#include "os/os.h"
#include "nimble-console/console.h"
#include "nimble/ble.h"
#include "host/ble_hs.h"
#include "services/gap/ble_svc_gap.h"
#include "blecsc_sens.h"


#define OS_TICKS_PER_SEC 100

/* Wheel size for simulation calculations */
#define CSC_SIM_WHEEL_CIRCUMFERENCE_MM 2000
/* Simulated cadence lower limit */
#define CSC_SIM_CRANK_RPM_MIN 20
/* Simulated cadence upper limit */
#define CSC_SIM_CRANK_RPM_MAX 100
/* Simulated speed lower limit */
#define CSC_SIM_SPEED_KPH_MIN 0
/* Simulated speed upper limit */
#define CSC_SIM_SPEED_KPH_MAX 35

/* Noticication status */
static bool notify_state = false;

/* Connection handle */
static uint16_t conn_handle;

static uint8_t blecsc_addr_type;

/* Advertised device name  */
static const char *device_name = "blecsc_sensor";

/* Measurement and notification timer */
// static struct os_callout blecsc_measure_timer;
static struct ble_npl_callout blecsc_measure_timer;

/* Variable holds current CSC measurement state */
static struct ble_csc_measurement_state csc_measurement_state;

/* Variable holds simulted speed (kilometers per hour) */
static uint16_t csc_sim_speed_kph = CSC_SIM_SPEED_KPH_MIN;

/* Variable holds simulated cadence (RPM) */
static uint8_t csc_sim_crank_rpm = CSC_SIM_CRANK_RPM_MIN;

static int blecsc_gap_event(struct ble_gap_event *event, void *arg);

/*
 * Enables advertising with parameters:
 *     o General discoverable mode
 *     o Undirected connectable mode
 */
static void
blecsc_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;

    /*
     * Set appearance.
     */
    fields.appearance = ble_svc_gap_device_appearance();
    fields.appearance_is_present = 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(blecsc_addr_type, NULL, BLE_HS_FOREVER,
                           &adv_params, blecsc_gap_event, NULL);
    if (rc != 0)
    {
        MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
        return;
    }
}

/* Update simulated CSC measurements.
 * Each call increments wheel and crank revolution counters by one and
 * computes last event time in order to match simulated candence and speed.
 * Last event time is expressedd in 1/1024th of second units.
 *
 *                 60 * 1024
 * crank_dt =    --------------
 *                cadence[RPM]
 *
 *
 *                circumference[mm] * 1024 * 60 * 60
 * wheel_dt =    -------------------------------------
 *                         10^6 * speed [kph]
 */
static void
blecsc_simulate_speed_and_cadence(void)
{
    uint16_t wheel_rev_period;
    uint16_t crank_rev_period;

    /* Update simulated crank and wheel rotation speed */
    csc_sim_speed_kph++;
    if (csc_sim_speed_kph >= CSC_SIM_SPEED_KPH_MAX)
    {
        csc_sim_speed_kph = CSC_SIM_SPEED_KPH_MIN;
    }

    csc_sim_crank_rpm++;
    if (csc_sim_crank_rpm >= CSC_SIM_CRANK_RPM_MAX)
    {
        csc_sim_crank_rpm = CSC_SIM_CRANK_RPM_MIN;
    }

    /* Calculate simulated measurement values */
    if (csc_sim_speed_kph > 0)
    {
        wheel_rev_period = (36 * 64 * CSC_SIM_WHEEL_CIRCUMFERENCE_MM) /
                           (625 * csc_sim_speed_kph);
        csc_measurement_state.cumulative_wheel_rev++;
        csc_measurement_state.last_wheel_evt_time += wheel_rev_period;
    }

    if (csc_sim_crank_rpm > 0)
    {
        crank_rev_period = (60 * 1024) / csc_sim_crank_rpm;
        csc_measurement_state.cumulative_crank_rev++;
        csc_measurement_state.last_crank_evt_time += crank_rev_period;
    }

    MODLOG_DFLT(INFO, "CSC simulated values: speed = %d kph, cadence = %d \n",
                csc_sim_speed_kph, csc_sim_crank_rpm);
}

/* Run CSC measurement simulation and notify it to the client */
static void
blecsc_measurement(struct ble_npl_event *ev)
{
    int rc;

    rc = ble_npl_callout_reset(&blecsc_measure_timer, OS_TICKS_PER_SEC);
    OS_ASSERT(rc == 0);

    blecsc_simulate_speed_and_cadence();

    if (notify_state)
    {
        rc = gatt_svr_chr_notify_csc_measurement(conn_handle);
        OS_ASSERT(rc == 0);
    }
}

static int
blecsc_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 */
            blecsc_advertise();
            conn_handle = 0;
        }
        else
        {
            conn_handle = event->connect.conn_handle;
        }
        break;

    case BLE_GAP_EVENT_DISCONNECT:
        MODLOG_DFLT(INFO, "disconnect; reason=%d\n", event->disconnect.reason);
        conn_handle = 0;
        /* Connection terminated; resume advertising */
        blecsc_advertise();
        break;

    case BLE_GAP_EVENT_ADV_COMPLETE:
        MODLOG_DFLT(INFO, "adv complete\n");
        break;

    case BLE_GAP_EVENT_SUBSCRIBE:
        MODLOG_DFLT(INFO, "subscribe event attr_handle=%d\n",
                    event->subscribe.attr_handle);

        if (event->subscribe.attr_handle == csc_measurement_handle)
        {
            notify_state = event->subscribe.cur_notify;
            MODLOG_DFLT(INFO, "csc measurement notify state = %d\n",
                        notify_state);
        }
        else if (event->subscribe.attr_handle == csc_control_point_handle)
        {
            gatt_svr_set_cp_indicate(event->subscribe.cur_indicate);
            MODLOG_DFLT(INFO, "csc control point indicate state = %d\n",
                        event->subscribe.cur_indicate);
        }
        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
blecsc_on_sync(void)
{
    int rc;

    /* Figure out address to use while advertising (no privacy) */
    rc = ble_hs_id_infer_auto(0, &blecsc_addr_type);
    OS_ASSERT(rc == 0);

    /* Begin advertising */
    blecsc_advertise();
}

/*
 * main
 *
 * The main task for the project. This function initializes the packages,
 * then starts serving events from default event queue.
 *
 * @return int NOTE: this function should never return!
 */
int main(void)
{
    int rc;

    /* Initialize OS */
    nimble_port_oneos_init();

    /* Initialize the NimBLE host configuration */
    ble_hs_cfg.sync_cb = blecsc_on_sync;

    /* Initialize measurement and notification timer */
    ble_npl_callout_init(&blecsc_measure_timer, nimble_port_get_dflt_eventq(),
                         blecsc_measurement, NULL);
    rc = ble_npl_callout_reset(&blecsc_measure_timer, OS_TICKS_PER_SEC);
    OS_ASSERT(rc == 0);

    rc = gatt_svr_init(&csc_measurement_state);
    OS_ASSERT(rc == 0);

    /* Set the default device name */
    rc = ble_svc_gap_device_name_set(device_name);
    OS_ASSERT(rc == 0);

    /* As the last thing, process events from default event queue */
    ble_hs_task_startup();

    while (1)
    {
        os_task_mdelay(100);
    }

    return 0;
}

results matching ""

    No results matching ""