xref: /nrf52832-nimble/packages/NimBLE-latest/apps/blehr/src/blehr.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1*042d53a7SEvalZero /*
2*042d53a7SEvalZero  * Licensed to the Apache Software Foundation (ASF) under one
3*042d53a7SEvalZero  * or more contributor license agreements.  See the NOTICE file
4*042d53a7SEvalZero  * distributed with this work for additional information
5*042d53a7SEvalZero  * regarding copyright ownership.  The ASF licenses this file
6*042d53a7SEvalZero  * to you under the Apache License, Version 2.0 (the
7*042d53a7SEvalZero  * "License"); you may not use this file except in compliance
8*042d53a7SEvalZero  * with the License.  You may obtain a copy of the License at
9*042d53a7SEvalZero  *
10*042d53a7SEvalZero  *  http://www.apache.org/licenses/LICENSE-2.0
11*042d53a7SEvalZero  *
12*042d53a7SEvalZero  * Unless required by applicable law or agreed to in writing,
13*042d53a7SEvalZero  * software distributed under the License is distributed on an
14*042d53a7SEvalZero  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15*042d53a7SEvalZero  * KIND, either express or implied.  See the License for the
16*042d53a7SEvalZero  * specific language governing permissions and limitations
17*042d53a7SEvalZero  * under the License.
18*042d53a7SEvalZero  */
19*042d53a7SEvalZero 
20*042d53a7SEvalZero #include <assert.h>
21*042d53a7SEvalZero #include <string.h>
22*042d53a7SEvalZero #include <stdio.h>
23*042d53a7SEvalZero 
24*042d53a7SEvalZero #include <rtthread.h>
25*042d53a7SEvalZero 
26*042d53a7SEvalZero #include "nimble/ble.h"
27*042d53a7SEvalZero #include "host/ble_hs.h"
28*042d53a7SEvalZero #include "services/gap/ble_svc_gap.h"
29*042d53a7SEvalZero #include "blehr_sens.h"
30*042d53a7SEvalZero 
31*042d53a7SEvalZero static bool notify_state;
32*042d53a7SEvalZero static uint16_t notify_conn_handle;
33*042d53a7SEvalZero 
34*042d53a7SEvalZero static const char *device_name = "blehr_sensor";
35*042d53a7SEvalZero 
36*042d53a7SEvalZero static int blehr_gap_event(struct ble_gap_event *event, void *arg);
37*042d53a7SEvalZero 
38*042d53a7SEvalZero static uint8_t blehr_addr_type;
39*042d53a7SEvalZero 
40*042d53a7SEvalZero /* Sending notify data timer */
41*042d53a7SEvalZero static struct ble_npl_callout blehr_tx_timer;
42*042d53a7SEvalZero 
43*042d53a7SEvalZero /* Variable to simulate heart beats */
44*042d53a7SEvalZero static uint8_t heartrate = 90;
45*042d53a7SEvalZero 
46*042d53a7SEvalZero /*
47*042d53a7SEvalZero  * Enables advertising with parameters:
48*042d53a7SEvalZero  *     o General discoverable mode
49*042d53a7SEvalZero  *     o Undirected connectable mode
50*042d53a7SEvalZero  */
51*042d53a7SEvalZero static void
blehr_advertise(void)52*042d53a7SEvalZero blehr_advertise(void)
53*042d53a7SEvalZero {
54*042d53a7SEvalZero     struct ble_gap_adv_params adv_params;
55*042d53a7SEvalZero     struct ble_hs_adv_fields fields;
56*042d53a7SEvalZero     int rc;
57*042d53a7SEvalZero 
58*042d53a7SEvalZero     /*
59*042d53a7SEvalZero      *  Set the advertisement data included in our advertisements:
60*042d53a7SEvalZero      *     o Flags (indicates advertisement type and other general info)
61*042d53a7SEvalZero      *     o Advertising tx power
62*042d53a7SEvalZero      *     o Device name
63*042d53a7SEvalZero      */
64*042d53a7SEvalZero     memset(&fields, 0, sizeof(fields));
65*042d53a7SEvalZero 
66*042d53a7SEvalZero     /*
67*042d53a7SEvalZero      * Advertise two flags:
68*042d53a7SEvalZero      *      o Discoverability in forthcoming advertisement (general)
69*042d53a7SEvalZero      *      o BLE-only (BR/EDR unsupported)
70*042d53a7SEvalZero      */
71*042d53a7SEvalZero     fields.flags = BLE_HS_ADV_F_DISC_GEN |
72*042d53a7SEvalZero                     BLE_HS_ADV_F_BREDR_UNSUP;
73*042d53a7SEvalZero 
74*042d53a7SEvalZero     /*
75*042d53a7SEvalZero      * Indicate that the TX power level field should be included; have the
76*042d53a7SEvalZero      * stack fill this value automatically.  This is done by assigning the
77*042d53a7SEvalZero      * special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
78*042d53a7SEvalZero      */
79*042d53a7SEvalZero     fields.tx_pwr_lvl_is_present = 1;
80*042d53a7SEvalZero     fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
81*042d53a7SEvalZero 
82*042d53a7SEvalZero     fields.name = (uint8_t *)device_name;
83*042d53a7SEvalZero     fields.name_len = strlen(device_name);
84*042d53a7SEvalZero     fields.name_is_complete = 1;
85*042d53a7SEvalZero 
86*042d53a7SEvalZero     rc = ble_gap_adv_set_fields(&fields);
87*042d53a7SEvalZero     if (rc != 0) {
88*042d53a7SEvalZero         MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
89*042d53a7SEvalZero         return;
90*042d53a7SEvalZero     }
91*042d53a7SEvalZero 
92*042d53a7SEvalZero     /* Begin advertising */
93*042d53a7SEvalZero     memset(&adv_params, 0, sizeof(adv_params));
94*042d53a7SEvalZero     adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
95*042d53a7SEvalZero     adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
96*042d53a7SEvalZero     rc = ble_gap_adv_start(blehr_addr_type, NULL, BLE_HS_FOREVER,
97*042d53a7SEvalZero                            &adv_params, blehr_gap_event, NULL);
98*042d53a7SEvalZero     if (rc != 0) {
99*042d53a7SEvalZero         MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
100*042d53a7SEvalZero         return;
101*042d53a7SEvalZero     }
102*042d53a7SEvalZero }
103*042d53a7SEvalZero 
104*042d53a7SEvalZero static void
blehr_tx_hrate_stop(void)105*042d53a7SEvalZero blehr_tx_hrate_stop(void)
106*042d53a7SEvalZero {
107*042d53a7SEvalZero     ble_npl_callout_stop(&blehr_tx_timer);
108*042d53a7SEvalZero }
109*042d53a7SEvalZero 
110*042d53a7SEvalZero /* Reset heartrate measurment */
111*042d53a7SEvalZero static void
blehr_tx_hrate_reset(void)112*042d53a7SEvalZero blehr_tx_hrate_reset(void)
113*042d53a7SEvalZero {
114*042d53a7SEvalZero     int rc;
115*042d53a7SEvalZero 
116*042d53a7SEvalZero     rc = ble_npl_callout_reset(&blehr_tx_timer, RT_TICK_PER_SECOND);
117*042d53a7SEvalZero     assert(rc == 0);
118*042d53a7SEvalZero }
119*042d53a7SEvalZero 
120*042d53a7SEvalZero /* This functions simulates heart beat and notifies it to the client */
121*042d53a7SEvalZero static void
blehr_tx_hrate(struct ble_npl_event * ev)122*042d53a7SEvalZero blehr_tx_hrate(struct ble_npl_event *ev)
123*042d53a7SEvalZero {
124*042d53a7SEvalZero     static uint8_t hrm[2];
125*042d53a7SEvalZero     int rc;
126*042d53a7SEvalZero     struct os_mbuf *om;
127*042d53a7SEvalZero 
128*042d53a7SEvalZero     if (!notify_state) {
129*042d53a7SEvalZero         blehr_tx_hrate_stop();
130*042d53a7SEvalZero         heartrate = 90;
131*042d53a7SEvalZero         return;
132*042d53a7SEvalZero     }
133*042d53a7SEvalZero 
134*042d53a7SEvalZero     hrm[0] = 0x06; /* contact of a sensor */
135*042d53a7SEvalZero     hrm[1] = heartrate; /* storing dummy data */
136*042d53a7SEvalZero 
137*042d53a7SEvalZero     /* Simulation of heart beats */
138*042d53a7SEvalZero     heartrate++;
139*042d53a7SEvalZero     if (heartrate == 160) {
140*042d53a7SEvalZero         heartrate = 90;
141*042d53a7SEvalZero     }
142*042d53a7SEvalZero 
143*042d53a7SEvalZero     om = ble_hs_mbuf_from_flat(hrm, sizeof(hrm));
144*042d53a7SEvalZero 
145*042d53a7SEvalZero     rc = ble_gattc_notify_custom(notify_conn_handle, hrs_hrm_handle, om);
146*042d53a7SEvalZero 
147*042d53a7SEvalZero     assert(rc == 0);
148*042d53a7SEvalZero     blehr_tx_hrate_reset();
149*042d53a7SEvalZero }
150*042d53a7SEvalZero 
151*042d53a7SEvalZero static int
blehr_gap_event(struct ble_gap_event * event,void * arg)152*042d53a7SEvalZero blehr_gap_event(struct ble_gap_event *event, void *arg)
153*042d53a7SEvalZero {
154*042d53a7SEvalZero     switch (event->type) {
155*042d53a7SEvalZero     case BLE_GAP_EVENT_CONNECT:
156*042d53a7SEvalZero         /* A new connection was established or a connection attempt failed */
157*042d53a7SEvalZero         MODLOG_DFLT(INFO, "connection %s; status=%d\n",
158*042d53a7SEvalZero                     event->connect.status == 0 ? "established" : "failed",
159*042d53a7SEvalZero                     event->connect.status);
160*042d53a7SEvalZero 
161*042d53a7SEvalZero         if (event->connect.status != 0) {
162*042d53a7SEvalZero             /* Connection failed; resume advertising */
163*042d53a7SEvalZero             blehr_advertise();
164*042d53a7SEvalZero         }
165*042d53a7SEvalZero         break;
166*042d53a7SEvalZero 
167*042d53a7SEvalZero     case BLE_GAP_EVENT_DISCONNECT:
168*042d53a7SEvalZero         MODLOG_DFLT(INFO, "disconnect; reason=%d\n", event->disconnect.reason);
169*042d53a7SEvalZero 
170*042d53a7SEvalZero         /* Connection terminated; resume advertising */
171*042d53a7SEvalZero         blehr_advertise();
172*042d53a7SEvalZero         break;
173*042d53a7SEvalZero 
174*042d53a7SEvalZero     case BLE_GAP_EVENT_ADV_COMPLETE:
175*042d53a7SEvalZero         MODLOG_DFLT(INFO, "adv complete\n");
176*042d53a7SEvalZero         blehr_advertise();
177*042d53a7SEvalZero         break;
178*042d53a7SEvalZero 
179*042d53a7SEvalZero     case BLE_GAP_EVENT_SUBSCRIBE:
180*042d53a7SEvalZero         MODLOG_DFLT(INFO, "subscribe event; cur_notify=%d\n value handle; "
181*042d53a7SEvalZero                           "val_handle=%d\n",
182*042d53a7SEvalZero                     event->subscribe.cur_notify, hrs_hrm_handle);
183*042d53a7SEvalZero         if (event->subscribe.attr_handle == hrs_hrm_handle) {
184*042d53a7SEvalZero             notify_state = event->subscribe.cur_notify;
185*042d53a7SEvalZero             notify_conn_handle = event->subscribe.conn_handle;
186*042d53a7SEvalZero             blehr_tx_hrate_reset();
187*042d53a7SEvalZero         } else if (event->subscribe.attr_handle != hrs_hrm_handle) {
188*042d53a7SEvalZero             notify_state = event->subscribe.cur_notify;
189*042d53a7SEvalZero             notify_conn_handle = 0;
190*042d53a7SEvalZero             blehr_tx_hrate_stop();
191*042d53a7SEvalZero         }
192*042d53a7SEvalZero         break;
193*042d53a7SEvalZero 
194*042d53a7SEvalZero     case BLE_GAP_EVENT_MTU:
195*042d53a7SEvalZero         MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d mtu=%d\n",
196*042d53a7SEvalZero                     event->mtu.conn_handle,
197*042d53a7SEvalZero                     event->mtu.value);
198*042d53a7SEvalZero         break;
199*042d53a7SEvalZero 
200*042d53a7SEvalZero     }
201*042d53a7SEvalZero 
202*042d53a7SEvalZero     return 0;
203*042d53a7SEvalZero }
204*042d53a7SEvalZero 
205*042d53a7SEvalZero static void
blehr_on_sync(void)206*042d53a7SEvalZero blehr_on_sync(void)
207*042d53a7SEvalZero {
208*042d53a7SEvalZero     int rc;
209*042d53a7SEvalZero 
210*042d53a7SEvalZero     /* Use privacy */
211*042d53a7SEvalZero     rc = ble_hs_id_infer_auto(0, &blehr_addr_type);
212*042d53a7SEvalZero     assert(rc == 0);
213*042d53a7SEvalZero 
214*042d53a7SEvalZero     /* Begin advertising */
215*042d53a7SEvalZero     blehr_advertise();
216*042d53a7SEvalZero }
217*042d53a7SEvalZero 
218*042d53a7SEvalZero extern int nimble_ble_enable(void);
219*042d53a7SEvalZero extern struct ble_npl_eventq *nimble_port_get_dflt_eventq(void);
ble_hr(void)220*042d53a7SEvalZero static int ble_hr(void)
221*042d53a7SEvalZero {
222*042d53a7SEvalZero     int rc;
223*042d53a7SEvalZero     static int init_flag = 0;
224*042d53a7SEvalZero 
225*042d53a7SEvalZero     if (init_flag)
226*042d53a7SEvalZero         return 0;
227*042d53a7SEvalZero     init_flag = 1;
228*042d53a7SEvalZero 
229*042d53a7SEvalZero     /* Initialize the NimBLE host configuration */
230*042d53a7SEvalZero     ble_hs_cfg.sync_cb = blehr_on_sync;
231*042d53a7SEvalZero 
232*042d53a7SEvalZero     ble_npl_callout_init(&blehr_tx_timer, nimble_port_get_dflt_eventq(),
233*042d53a7SEvalZero                     blehr_tx_hrate, NULL);
234*042d53a7SEvalZero 
235*042d53a7SEvalZero     rc = gatt_svr_init();
236*042d53a7SEvalZero 
237*042d53a7SEvalZero     /* Set the default device name */
238*042d53a7SEvalZero     rc = ble_svc_gap_device_name_set(device_name);
239*042d53a7SEvalZero     RT_ASSERT(rc == 0);
240*042d53a7SEvalZero 
241*042d53a7SEvalZero     /* startup bluetooth host stack*/
242*042d53a7SEvalZero     ble_hs_thread_startup();
243*042d53a7SEvalZero 
244*042d53a7SEvalZero     return 0;
245*042d53a7SEvalZero }
246*042d53a7SEvalZero MSH_CMD_EXPORT_ALIAS(ble_hr, ble_hr, "bluetoooth heartrate senson sample");
247