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