xref: /nrf52832-nimble/packages/NimBLE-latest/apps/bleprph/src/bleprph.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 #include <errno.h>
24 
25 #include <rtthread.h>
26 
27 /* BLE */
28 #include "nimble/ble.h"
29 #include "host/ble_hs.h"
30 #include "host/util/util.h"
31 #include "services/gap/ble_svc_gap.h"
32 
33 /* Application-specified header. */
34 #include "bleprph.h"
35 
36 static int bleprph_gap_event(struct ble_gap_event *event, void *arg);
37 
38 /**
39  * Logs information about a connection to the console.
40  */
41 static void
bleprph_print_conn_desc(struct ble_gap_conn_desc * desc)42 bleprph_print_conn_desc(struct ble_gap_conn_desc *desc)
43 {
44     MODLOG_DFLT(INFO, "handle=%d our_ota_addr_type=%d our_ota_addr=",
45                 desc->conn_handle, desc->our_ota_addr.type);
46     print_addr(desc->our_ota_addr.val);
47     MODLOG_DFLT(INFO, " our_id_addr_type=%d our_id_addr=",
48                 desc->our_id_addr.type);
49     print_addr(desc->our_id_addr.val);
50     MODLOG_DFLT(INFO, " peer_ota_addr_type=%d peer_ota_addr=",
51                 desc->peer_ota_addr.type);
52     print_addr(desc->peer_ota_addr.val);
53     MODLOG_DFLT(INFO, " peer_id_addr_type=%d peer_id_addr=",
54                 desc->peer_id_addr.type);
55     print_addr(desc->peer_id_addr.val);
56     MODLOG_DFLT(INFO, " conn_itvl=%d conn_latency=%d supervision_timeout=%d "
57                 "encrypted=%d authenticated=%d bonded=%d\n",
58                 desc->conn_itvl, desc->conn_latency,
59                 desc->supervision_timeout,
60                 desc->sec_state.encrypted,
61                 desc->sec_state.authenticated,
62                 desc->sec_state.bonded);
63 }
64 
65 /**
66  * Enables advertising with the following parameters:
67  *     o General discoverable mode.
68  *     o Undirected connectable mode.
69  */
70 static void
bleprph_advertise(void)71 bleprph_advertise(void)
72 {
73     uint8_t own_addr_type;
74     struct ble_gap_adv_params adv_params;
75     struct ble_hs_adv_fields fields;
76     const char *name;
77     int rc;
78 
79     /* Figure out address to use while advertising (no privacy for now) */
80     rc = ble_hs_id_infer_auto(0, &own_addr_type);
81     if (rc != 0) {
82         MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
83         return;
84     }
85 
86     /**
87      *  Set the advertisement data included in our advertisements:
88      *     o Flags (indicates advertisement type and other general info).
89      *     o Advertising tx power.
90      *     o Device name.
91      *     o 16-bit service UUIDs (alert notifications).
92      */
93 
94     memset(&fields, 0, sizeof fields);
95 
96     /* Advertise two flags:
97      *     o Discoverability in forthcoming advertisement (general)
98      *     o BLE-only (BR/EDR unsupported).
99      */
100     fields.flags = BLE_HS_ADV_F_DISC_GEN |
101                    BLE_HS_ADV_F_BREDR_UNSUP;
102 
103     /* Indicate that the TX power level field should be included; have the
104      * stack fill this value automatically.  This is done by assiging the
105      * special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
106      */
107     fields.tx_pwr_lvl_is_present = 1;
108     fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
109 
110     name = ble_svc_gap_device_name();
111     fields.name = (uint8_t *)name;
112     fields.name_len = strlen(name);
113     fields.name_is_complete = 1;
114 
115     fields.uuids16 = (ble_uuid16_t[]){
116         BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID)
117     };
118     fields.num_uuids16 = 1;
119     fields.uuids16_is_complete = 1;
120 
121     rc = ble_gap_adv_set_fields(&fields);
122     if (rc != 0) {
123         MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
124         return;
125     }
126 
127     /* Begin advertising. */
128     memset(&adv_params, 0, sizeof adv_params);
129     adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
130     adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
131     rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER,
132                            &adv_params, bleprph_gap_event, NULL);
133     if (rc != 0) {
134         MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
135         return;
136     }
137 }
138 
139 /**
140  * The nimble host executes this callback when a GAP event occurs.  The
141  * application associates a GAP event callback with each connection that forms.
142  * bleprph uses the same callback for all connections.
143  *
144  * @param event                 The type of event being signalled.
145  * @param ctxt                  Various information pertaining to the event.
146  * @param arg                   Application-specified argument; unuesd by
147  *                                  bleprph.
148  *
149  * @return                      0 if the application successfully handled the
150  *                                  event; nonzero on failure.  The semantics
151  *                                  of the return code is specific to the
152  *                                  particular GAP event being signalled.
153  */
154 static int
bleprph_gap_event(struct ble_gap_event * event,void * arg)155 bleprph_gap_event(struct ble_gap_event *event, void *arg)
156 {
157     struct ble_gap_conn_desc desc;
158     int rc;
159 
160     switch (event->type) {
161     case BLE_GAP_EVENT_CONNECT:
162         /* A new connection was established or a connection attempt failed. */
163         MODLOG_DFLT(INFO, "connection %s; status=%d ",
164                     event->connect.status == 0 ? "established" : "failed",
165                     event->connect.status);
166         if (event->connect.status == 0) {
167             rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
168             assert(rc == 0);
169             bleprph_print_conn_desc(&desc);
170 
171 #if MYNEWT_VAL(BLEPRPH_LE_PHY_SUPPORT)
172             phy_conn_changed(event->connect.conn_handle);
173 #endif
174         }
175         MODLOG_DFLT(INFO, "\n");
176 
177         if (event->connect.status != 0) {
178             /* Connection failed; resume advertising. */
179             bleprph_advertise();
180         }
181         return 0;
182 
183     case BLE_GAP_EVENT_DISCONNECT:
184         MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason);
185         bleprph_print_conn_desc(&event->disconnect.conn);
186         MODLOG_DFLT(INFO, "\n");
187 
188 #if MYNEWT_VAL(BLEPRPH_LE_PHY_SUPPORT)
189         phy_conn_changed(CONN_HANDLE_INVALID);
190 #endif
191 
192         /* Connection terminated; resume advertising. */
193         bleprph_advertise();
194         return 0;
195 
196     case BLE_GAP_EVENT_CONN_UPDATE:
197         /* The central has updated the connection parameters. */
198         MODLOG_DFLT(INFO, "connection updated; status=%d ",
199                     event->conn_update.status);
200         rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
201         assert(rc == 0);
202         bleprph_print_conn_desc(&desc);
203         MODLOG_DFLT(INFO, "\n");
204         return 0;
205 
206     case BLE_GAP_EVENT_ADV_COMPLETE:
207         MODLOG_DFLT(INFO, "advertise complete; reason=%d",
208                     event->adv_complete.reason);
209         bleprph_advertise();
210         return 0;
211 
212     case BLE_GAP_EVENT_ENC_CHANGE:
213         /* Encryption has been enabled or disabled for this connection. */
214         MODLOG_DFLT(INFO, "encryption change event; status=%d ",
215                     event->enc_change.status);
216         rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
217         assert(rc == 0);
218         bleprph_print_conn_desc(&desc);
219         MODLOG_DFLT(INFO, "\n");
220         return 0;
221 
222     case BLE_GAP_EVENT_SUBSCRIBE:
223         MODLOG_DFLT(INFO, "subscribe event; conn_handle=%d attr_handle=%d "
224                           "reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
225                     event->subscribe.conn_handle,
226                     event->subscribe.attr_handle,
227                     event->subscribe.reason,
228                     event->subscribe.prev_notify,
229                     event->subscribe.cur_notify,
230                     event->subscribe.prev_indicate,
231                     event->subscribe.cur_indicate);
232         return 0;
233 
234     case BLE_GAP_EVENT_MTU:
235         MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d cid=%d mtu=%d\n",
236                     event->mtu.conn_handle,
237                     event->mtu.channel_id,
238                     event->mtu.value);
239         return 0;
240 
241     case BLE_GAP_EVENT_REPEAT_PAIRING:
242         /* We already have a bond with the peer, but it is attempting to
243          * establish a new secure link.  This app sacrifices security for
244          * convenience: just throw away the old bond and accept the new link.
245          */
246 
247         /* Delete the old bond. */
248         rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
249         assert(rc == 0);
250         ble_store_util_delete_peer(&desc.peer_id_addr);
251 
252         /* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
253          * continue with the pairing operation.
254          */
255         return BLE_GAP_REPEAT_PAIRING_RETRY;
256 
257 #if MYNEWT_VAL(BLEPRPH_LE_PHY_SUPPORT)
258     case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE:
259         /* XXX: assume symmetric phy for now */
260         phy_update(event->phy_updated.tx_phy);
261         return 0;
262 #endif
263     }
264 
265     return 0;
266 }
267 
268 static void
bleprph_on_reset(int reason)269 bleprph_on_reset(int reason)
270 {
271     MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
272 }
273 
274 static void
bleprph_on_sync(void)275 bleprph_on_sync(void)
276 {
277     int rc;
278 
279     /* Make sure we have proper identity address set (public preferred) */
280     rc = ble_hs_util_ensure_addr(0);
281     assert(rc == 0);
282 
283     /* Begin advertising. */
284     bleprph_advertise();
285 }
286 
287 /**
288  * main
289  *
290  * The main task for the project. This function initializes the packages,
291  * then starts serving events from default event queue.
292  *
293  * @return int NOTE: this function should never return!
294  */
bleprph_entry(void)295 int bleprph_entry(void)
296 {
297     int rc;
298 
299     /* Initialize the NimBLE host configuration. */
300     ble_hs_cfg.reset_cb = bleprph_on_reset;
301     ble_hs_cfg.sync_cb = bleprph_on_sync;
302     ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
303     ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
304 
305     rc = gatt_svr_init();
306     assert(rc == 0);
307 
308     /* Set the default device name. */
309     rc = ble_svc_gap_device_name_set("nimble-bleprph");
310     assert(rc == 0);
311 
312 #if MYNEWT_VAL(BLEPRPH_LE_PHY_SUPPORT)
313     phy_init();
314 #endif
315 
316     /* startup bluetooth host stack*/
317     ble_hs_thread_startup();
318 }
319 
320 MSH_CMD_EXPORT_ALIAS(bleprph_entry, bleprph, "bluetooth peripheral role sample");
321