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