xref: /btstack/example/nordic_spp_le_streamer.c (revision ebdf3c684b9b7659b2b3d23a00b29177ce5829dc)
1*ebdf3c68SMilanka Ringwald /*
2*ebdf3c68SMilanka Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
3*ebdf3c68SMilanka Ringwald  *
4*ebdf3c68SMilanka Ringwald  * Redistribution and use in source and binary forms, with or without
5*ebdf3c68SMilanka Ringwald  * modification, are permitted provided that the following conditions
6*ebdf3c68SMilanka Ringwald  * are met:
7*ebdf3c68SMilanka Ringwald  *
8*ebdf3c68SMilanka Ringwald  * 1. Redistributions of source code must retain the above copyright
9*ebdf3c68SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer.
10*ebdf3c68SMilanka Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*ebdf3c68SMilanka Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*ebdf3c68SMilanka Ringwald  *    documentation and/or other materials provided with the distribution.
13*ebdf3c68SMilanka Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*ebdf3c68SMilanka Ringwald  *    contributors may be used to endorse or promote products derived
15*ebdf3c68SMilanka Ringwald  *    from this software without specific prior written permission.
16*ebdf3c68SMilanka Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*ebdf3c68SMilanka Ringwald  *    personal benefit and not for any commercial purpose or for
18*ebdf3c68SMilanka Ringwald  *    monetary gain.
19*ebdf3c68SMilanka Ringwald  *
20*ebdf3c68SMilanka Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*ebdf3c68SMilanka Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*ebdf3c68SMilanka Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*ebdf3c68SMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*ebdf3c68SMilanka Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*ebdf3c68SMilanka Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*ebdf3c68SMilanka Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*ebdf3c68SMilanka Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*ebdf3c68SMilanka Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*ebdf3c68SMilanka Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*ebdf3c68SMilanka Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*ebdf3c68SMilanka Ringwald  * SUCH DAMAGE.
32*ebdf3c68SMilanka Ringwald  *
33*ebdf3c68SMilanka Ringwald  * Please inquire about commercial licensing options at
34*ebdf3c68SMilanka Ringwald  * [email protected]
35*ebdf3c68SMilanka Ringwald  *
36*ebdf3c68SMilanka Ringwald  */
37*ebdf3c68SMilanka Ringwald 
38*ebdf3c68SMilanka Ringwald #define __BTSTACK_FILE__ "nordic_spp_le_streamer.c"
39*ebdf3c68SMilanka Ringwald 
40*ebdf3c68SMilanka Ringwald // *****************************************************************************
41*ebdf3c68SMilanka Ringwald /* EXAMPLE_START(nordic_spp_le_streamer): LE Streamer - Stream data over GATT.
42*ebdf3c68SMilanka Ringwald  *
43*ebdf3c68SMilanka Ringwald  * @text All newer operating systems provide GATT Client functionality.
44*ebdf3c68SMilanka Ringwald  * This example shows how to get a maximal throughput via BLE:
45*ebdf3c68SMilanka Ringwald  * - send whenever possible,
46*ebdf3c68SMilanka Ringwald  * - use the max ATT MTU.
47*ebdf3c68SMilanka Ringwald  *
48*ebdf3c68SMilanka Ringwald  * @text In theory, we should also update the connection parameters, but we already get
49*ebdf3c68SMilanka Ringwald  * a connection interval of 30 ms and there's no public way to use a shorter
50*ebdf3c68SMilanka Ringwald  * interval with iOS (if we're not implementing an HID device).
51*ebdf3c68SMilanka Ringwald  *
52*ebdf3c68SMilanka Ringwald  * @text Note: To start the streaming, run the example.
53*ebdf3c68SMilanka Ringwald  * On remote device use some GATT Explorer, e.g. LightBlue, BLExplr to enable notifications.
54*ebdf3c68SMilanka Ringwald  */
55*ebdf3c68SMilanka Ringwald  // *****************************************************************************
56*ebdf3c68SMilanka Ringwald 
57*ebdf3c68SMilanka Ringwald #include <inttypes.h>
58*ebdf3c68SMilanka Ringwald #include <stdint.h>
59*ebdf3c68SMilanka Ringwald #include <stdio.h>
60*ebdf3c68SMilanka Ringwald #include <stdlib.h>
61*ebdf3c68SMilanka Ringwald #include <string.h>
62*ebdf3c68SMilanka Ringwald 
63*ebdf3c68SMilanka Ringwald #include "btstack.h"
64*ebdf3c68SMilanka Ringwald #include "nordic_spp_le_streamer.h"
65*ebdf3c68SMilanka Ringwald #include "ble/gatt-service/nordic_spp_service_server.h"
66*ebdf3c68SMilanka Ringwald 
67*ebdf3c68SMilanka Ringwald #define REPORT_INTERVAL_MS 3000
68*ebdf3c68SMilanka Ringwald #define MAX_NR_CONNECTIONS 3
69*ebdf3c68SMilanka Ringwald 
70*ebdf3c68SMilanka Ringwald static void  packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
71*ebdf3c68SMilanka Ringwald 
72*ebdf3c68SMilanka Ringwald const uint8_t adv_data[] = {
73*ebdf3c68SMilanka Ringwald     // Flags general discoverable, BR/EDR not supported
74*ebdf3c68SMilanka Ringwald     2, BLUETOOTH_DATA_TYPE_FLAGS, 0x06,
75*ebdf3c68SMilanka Ringwald     // Name
76*ebdf3c68SMilanka Ringwald     6, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'A', 'M', 'B', 'E', 'R',
77*ebdf3c68SMilanka Ringwald     // UUID ...
78*ebdf3c68SMilanka Ringwald     17, BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS, 0x6e, 0x40, 0x0, 0x1, 0xc3, 0x52, 0x11, 0xe5, 0x95, 0x3d, 0x0, 0x2, 0xa5, 0xd5, 0xc5, 0x1b,
79*ebdf3c68SMilanka Ringwald };
80*ebdf3c68SMilanka Ringwald const uint8_t adv_data_len = sizeof(adv_data);
81*ebdf3c68SMilanka Ringwald 
82*ebdf3c68SMilanka Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
83*ebdf3c68SMilanka Ringwald 
84*ebdf3c68SMilanka Ringwald // support for multiple clients
85*ebdf3c68SMilanka Ringwald typedef struct {
86*ebdf3c68SMilanka Ringwald     char name;
87*ebdf3c68SMilanka Ringwald     int le_notification_enabled;
88*ebdf3c68SMilanka Ringwald     hci_con_handle_t connection_handle;
89*ebdf3c68SMilanka Ringwald     int  counter;
90*ebdf3c68SMilanka Ringwald     char test_data[200];
91*ebdf3c68SMilanka Ringwald     int  test_data_len;
92*ebdf3c68SMilanka Ringwald     uint32_t test_data_sent;
93*ebdf3c68SMilanka Ringwald     uint32_t test_data_start;
94*ebdf3c68SMilanka Ringwald     btstack_context_callback_registration_t send_request;
95*ebdf3c68SMilanka Ringwald } nordic_spp_le_streamer_connection_t;
96*ebdf3c68SMilanka Ringwald 
97*ebdf3c68SMilanka Ringwald static nordic_spp_le_streamer_connection_t nordic_spp_le_streamer_connections[MAX_NR_CONNECTIONS];
98*ebdf3c68SMilanka Ringwald 
99*ebdf3c68SMilanka Ringwald // round robin sending
100*ebdf3c68SMilanka Ringwald static int connection_index;
101*ebdf3c68SMilanka Ringwald 
102*ebdf3c68SMilanka Ringwald static void init_connections(void){
103*ebdf3c68SMilanka Ringwald     // track connections
104*ebdf3c68SMilanka Ringwald     int i;
105*ebdf3c68SMilanka Ringwald     for (i=0;i<MAX_NR_CONNECTIONS;i++){
106*ebdf3c68SMilanka Ringwald         nordic_spp_le_streamer_connections[i].connection_handle = HCI_CON_HANDLE_INVALID;
107*ebdf3c68SMilanka Ringwald         nordic_spp_le_streamer_connections[i].name = 'A' + i;
108*ebdf3c68SMilanka Ringwald     }
109*ebdf3c68SMilanka Ringwald }
110*ebdf3c68SMilanka Ringwald 
111*ebdf3c68SMilanka Ringwald static nordic_spp_le_streamer_connection_t * connection_for_conn_handle(hci_con_handle_t conn_handle){
112*ebdf3c68SMilanka Ringwald     int i;
113*ebdf3c68SMilanka Ringwald     for (i=0;i<MAX_NR_CONNECTIONS;i++){
114*ebdf3c68SMilanka Ringwald         if (nordic_spp_le_streamer_connections[i].connection_handle == conn_handle) return &nordic_spp_le_streamer_connections[i];
115*ebdf3c68SMilanka Ringwald     }
116*ebdf3c68SMilanka Ringwald     return NULL;
117*ebdf3c68SMilanka Ringwald }
118*ebdf3c68SMilanka Ringwald 
119*ebdf3c68SMilanka Ringwald static void next_connection_index(void){
120*ebdf3c68SMilanka Ringwald     connection_index++;
121*ebdf3c68SMilanka Ringwald     if (connection_index == MAX_NR_CONNECTIONS){
122*ebdf3c68SMilanka Ringwald         connection_index = 0;
123*ebdf3c68SMilanka Ringwald     }
124*ebdf3c68SMilanka Ringwald }
125*ebdf3c68SMilanka Ringwald 
126*ebdf3c68SMilanka Ringwald /*
127*ebdf3c68SMilanka Ringwald  * @section Track throughput
128*ebdf3c68SMilanka Ringwald  * @text We calculate the throughput by setting a start time and measuring the amount of
129*ebdf3c68SMilanka Ringwald  * data sent. After a configurable REPORT_INTERVAL_MS, we print the throughput in kB/s
130*ebdf3c68SMilanka Ringwald  * and reset the counter and start time.
131*ebdf3c68SMilanka Ringwald  */
132*ebdf3c68SMilanka Ringwald 
133*ebdf3c68SMilanka Ringwald /* LISTING_START(tracking): Tracking throughput */
134*ebdf3c68SMilanka Ringwald 
135*ebdf3c68SMilanka Ringwald static void test_reset(nordic_spp_le_streamer_connection_t * context){
136*ebdf3c68SMilanka Ringwald     context->test_data_start = btstack_run_loop_get_time_ms();
137*ebdf3c68SMilanka Ringwald     context->test_data_sent = 0;
138*ebdf3c68SMilanka Ringwald }
139*ebdf3c68SMilanka Ringwald 
140*ebdf3c68SMilanka Ringwald static void test_track_sent(nordic_spp_le_streamer_connection_t * context, int bytes_sent){
141*ebdf3c68SMilanka Ringwald     context->test_data_sent += bytes_sent;
142*ebdf3c68SMilanka Ringwald     // evaluate
143*ebdf3c68SMilanka Ringwald     uint32_t now = btstack_run_loop_get_time_ms();
144*ebdf3c68SMilanka Ringwald     uint32_t time_passed = now - context->test_data_start;
145*ebdf3c68SMilanka Ringwald     if (time_passed < REPORT_INTERVAL_MS) return;
146*ebdf3c68SMilanka Ringwald     // print speed
147*ebdf3c68SMilanka Ringwald     int bytes_per_second = context->test_data_sent * 1000 / time_passed;
148*ebdf3c68SMilanka Ringwald     printf("%c: %"PRIu32" bytes sent-> %u.%03u kB/s\n", context->name, context->test_data_sent, bytes_per_second / 1000, bytes_per_second % 1000);
149*ebdf3c68SMilanka Ringwald 
150*ebdf3c68SMilanka Ringwald     // restart
151*ebdf3c68SMilanka Ringwald     context->test_data_start = now;
152*ebdf3c68SMilanka Ringwald     context->test_data_sent  = 0;
153*ebdf3c68SMilanka Ringwald }
154*ebdf3c68SMilanka Ringwald /* LISTING_END(tracking): Tracking throughput */
155*ebdf3c68SMilanka Ringwald 
156*ebdf3c68SMilanka Ringwald /*
157*ebdf3c68SMilanka Ringwald  * @section Packet Handler
158*ebdf3c68SMilanka Ringwald  *
159*ebdf3c68SMilanka Ringwald  * @text The packet handler is used to stop the notifications and reset the MTU on connect
160*ebdf3c68SMilanka Ringwald  * It would also be a good place to request the connection parameter update as indicated
161*ebdf3c68SMilanka Ringwald  * in the commented code block.
162*ebdf3c68SMilanka Ringwald  */
163*ebdf3c68SMilanka Ringwald 
164*ebdf3c68SMilanka Ringwald /* LISTING_START(packetHandler): Packet Handler */
165*ebdf3c68SMilanka Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
166*ebdf3c68SMilanka Ringwald     UNUSED(channel);
167*ebdf3c68SMilanka Ringwald     UNUSED(size);
168*ebdf3c68SMilanka Ringwald 
169*ebdf3c68SMilanka Ringwald     int mtu;
170*ebdf3c68SMilanka Ringwald     uint16_t conn_interval;
171*ebdf3c68SMilanka Ringwald     nordic_spp_le_streamer_connection_t * context;
172*ebdf3c68SMilanka Ringwald     switch (packet_type) {
173*ebdf3c68SMilanka Ringwald         case HCI_EVENT_PACKET:
174*ebdf3c68SMilanka Ringwald             switch (hci_event_packet_get_type(packet)) {
175*ebdf3c68SMilanka Ringwald                 case BTSTACK_EVENT_STATE:
176*ebdf3c68SMilanka Ringwald                     // BTstack activated, get started
177*ebdf3c68SMilanka Ringwald                     if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING) {
178*ebdf3c68SMilanka Ringwald                         printf("To start the streaming, please run the AMB2621 Toolbox to connect.\n");
179*ebdf3c68SMilanka Ringwald                     }
180*ebdf3c68SMilanka Ringwald                     break;
181*ebdf3c68SMilanka Ringwald                 case HCI_EVENT_DISCONNECTION_COMPLETE:
182*ebdf3c68SMilanka Ringwald                     context = connection_for_conn_handle(hci_event_disconnection_complete_get_connection_handle(packet));
183*ebdf3c68SMilanka Ringwald                     if (!context) break;
184*ebdf3c68SMilanka Ringwald                     // free connection
185*ebdf3c68SMilanka Ringwald                     printf("%c: Disconnect, reason %02x\n", context->name, hci_event_disconnection_complete_get_reason(packet));
186*ebdf3c68SMilanka Ringwald                     context->le_notification_enabled = 0;
187*ebdf3c68SMilanka Ringwald                     context->connection_handle = HCI_CON_HANDLE_INVALID;
188*ebdf3c68SMilanka Ringwald                     break;
189*ebdf3c68SMilanka Ringwald                 case HCI_EVENT_LE_META:
190*ebdf3c68SMilanka Ringwald                     switch (hci_event_le_meta_get_subevent_code(packet)) {
191*ebdf3c68SMilanka Ringwald                         case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
192*ebdf3c68SMilanka Ringwald                             // setup new
193*ebdf3c68SMilanka Ringwald                             context = connection_for_conn_handle(HCI_CON_HANDLE_INVALID);
194*ebdf3c68SMilanka Ringwald                             if (!context) break;
195*ebdf3c68SMilanka Ringwald                             context->counter = 'A';
196*ebdf3c68SMilanka Ringwald                             context->test_data_len = ATT_DEFAULT_MTU - 4;   // -1 for nordic 0x01 packet type
197*ebdf3c68SMilanka Ringwald                             context->connection_handle = hci_subevent_le_connection_complete_get_connection_handle(packet);
198*ebdf3c68SMilanka Ringwald                             // print connection parameters (without using float operations)
199*ebdf3c68SMilanka Ringwald                             conn_interval = hci_subevent_le_connection_complete_get_conn_interval(packet);
200*ebdf3c68SMilanka Ringwald                             printf("%c: Connection Interval: %u.%02u ms\n", context->name, conn_interval * 125 / 100, 25 * (conn_interval & 3));
201*ebdf3c68SMilanka Ringwald                             printf("%c: Connection Latency: %u\n", context->name, hci_subevent_le_connection_complete_get_conn_latency(packet));
202*ebdf3c68SMilanka Ringwald                             break;
203*ebdf3c68SMilanka Ringwald                     }
204*ebdf3c68SMilanka Ringwald                     break;
205*ebdf3c68SMilanka Ringwald                 case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
206*ebdf3c68SMilanka Ringwald                     mtu = att_event_mtu_exchange_complete_get_MTU(packet) - 3;
207*ebdf3c68SMilanka Ringwald                     context = connection_for_conn_handle(att_event_mtu_exchange_complete_get_handle(packet));
208*ebdf3c68SMilanka Ringwald                     if (!context) break;
209*ebdf3c68SMilanka Ringwald                     context->test_data_len = btstack_min(mtu - 3, sizeof(context->test_data));
210*ebdf3c68SMilanka Ringwald                     printf("%c: ATT MTU = %u => use test data of len %u\n", context->name, mtu, context->test_data_len);
211*ebdf3c68SMilanka Ringwald                     break;
212*ebdf3c68SMilanka Ringwald                 default:
213*ebdf3c68SMilanka Ringwald                     break;
214*ebdf3c68SMilanka Ringwald             }
215*ebdf3c68SMilanka Ringwald     }
216*ebdf3c68SMilanka Ringwald }
217*ebdf3c68SMilanka Ringwald 
218*ebdf3c68SMilanka Ringwald /* LISTING_END */
219*ebdf3c68SMilanka Ringwald /*
220*ebdf3c68SMilanka Ringwald  * @section Streamer
221*ebdf3c68SMilanka Ringwald  *
222*ebdf3c68SMilanka Ringwald  * @text The streamer function checks if notifications are enabled and if a notification can be sent now.
223*ebdf3c68SMilanka Ringwald  * It creates some test data - a single letter that gets increased every time - and tracks the data sent.
224*ebdf3c68SMilanka Ringwald  */
225*ebdf3c68SMilanka Ringwald 
226*ebdf3c68SMilanka Ringwald  /* LISTING_START(streamer): Streaming code */
227*ebdf3c68SMilanka Ringwald static void nordic_can_send(void * some_context){
228*ebdf3c68SMilanka Ringwald     UNUSED(some_context);
229*ebdf3c68SMilanka Ringwald 
230*ebdf3c68SMilanka Ringwald     // find next active streaming connection
231*ebdf3c68SMilanka Ringwald     int old_connection_index = connection_index;
232*ebdf3c68SMilanka Ringwald     while (1){
233*ebdf3c68SMilanka Ringwald         // active found?
234*ebdf3c68SMilanka Ringwald         if ((nordic_spp_le_streamer_connections[connection_index].connection_handle != HCI_CON_HANDLE_INVALID) &&
235*ebdf3c68SMilanka Ringwald             (nordic_spp_le_streamer_connections[connection_index].le_notification_enabled)) break;
236*ebdf3c68SMilanka Ringwald 
237*ebdf3c68SMilanka Ringwald         // check next
238*ebdf3c68SMilanka Ringwald         next_connection_index();
239*ebdf3c68SMilanka Ringwald 
240*ebdf3c68SMilanka Ringwald         // none found
241*ebdf3c68SMilanka Ringwald         if (connection_index == old_connection_index) return;
242*ebdf3c68SMilanka Ringwald     }
243*ebdf3c68SMilanka Ringwald 
244*ebdf3c68SMilanka Ringwald     nordic_spp_le_streamer_connection_t * context = &nordic_spp_le_streamer_connections[connection_index];
245*ebdf3c68SMilanka Ringwald 
246*ebdf3c68SMilanka Ringwald     // create test data
247*ebdf3c68SMilanka Ringwald     context->counter++;
248*ebdf3c68SMilanka Ringwald     if (context->counter > 'Z') context->counter = 'A';
249*ebdf3c68SMilanka Ringwald     memset(context->test_data, context->counter, context->test_data_len);
250*ebdf3c68SMilanka Ringwald 
251*ebdf3c68SMilanka Ringwald     // send
252*ebdf3c68SMilanka Ringwald     nordic_spp_service_server_send(context->connection_handle, (uint8_t*) context->test_data, context->test_data_len);
253*ebdf3c68SMilanka Ringwald 
254*ebdf3c68SMilanka Ringwald     // track
255*ebdf3c68SMilanka Ringwald     test_track_sent(context, context->test_data_len);
256*ebdf3c68SMilanka Ringwald 
257*ebdf3c68SMilanka Ringwald     // request next send event
258*ebdf3c68SMilanka Ringwald     nordic_spp_service_server_request_can_send_now(&context->send_request, context->connection_handle);
259*ebdf3c68SMilanka Ringwald 
260*ebdf3c68SMilanka Ringwald     // check next
261*ebdf3c68SMilanka Ringwald     next_connection_index();
262*ebdf3c68SMilanka Ringwald }
263*ebdf3c68SMilanka Ringwald /* LISTING_END */
264*ebdf3c68SMilanka Ringwald 
265*ebdf3c68SMilanka Ringwald static void nordic_data_received(hci_con_handle_t tx_con_handle, const uint8_t * data, uint16_t size){
266*ebdf3c68SMilanka Ringwald     nordic_spp_le_streamer_connection_t * context = connection_for_conn_handle(tx_con_handle);
267*ebdf3c68SMilanka Ringwald 
268*ebdf3c68SMilanka Ringwald     if (!context) return;
269*ebdf3c68SMilanka Ringwald 
270*ebdf3c68SMilanka Ringwald     if (size == 0 && context->le_notification_enabled == 0){
271*ebdf3c68SMilanka Ringwald         context->le_notification_enabled = 1;
272*ebdf3c68SMilanka Ringwald         test_reset(context);
273*ebdf3c68SMilanka Ringwald         context->send_request.callback = &nordic_can_send;
274*ebdf3c68SMilanka Ringwald         nordic_spp_service_server_request_can_send_now(&context->send_request, context->connection_handle);
275*ebdf3c68SMilanka Ringwald     } else {
276*ebdf3c68SMilanka Ringwald         printf("RECV: ");
277*ebdf3c68SMilanka Ringwald         printf_hexdump(data, size);
278*ebdf3c68SMilanka Ringwald         test_track_sent(context, size);
279*ebdf3c68SMilanka Ringwald    }
280*ebdf3c68SMilanka Ringwald }
281*ebdf3c68SMilanka Ringwald 
282*ebdf3c68SMilanka Ringwald int btstack_main(void);
283*ebdf3c68SMilanka Ringwald int btstack_main(void)
284*ebdf3c68SMilanka Ringwald {
285*ebdf3c68SMilanka Ringwald 
286*ebdf3c68SMilanka Ringwald     // register for HCI events
287*ebdf3c68SMilanka Ringwald     hci_event_callback_registration.callback = &packet_handler;
288*ebdf3c68SMilanka Ringwald     hci_add_event_handler(&hci_event_callback_registration);
289*ebdf3c68SMilanka Ringwald 
290*ebdf3c68SMilanka Ringwald     l2cap_init();
291*ebdf3c68SMilanka Ringwald 
292*ebdf3c68SMilanka Ringwald     // setup LE device DB
293*ebdf3c68SMilanka Ringwald     le_device_db_init();
294*ebdf3c68SMilanka Ringwald 
295*ebdf3c68SMilanka Ringwald     // setup SM: Display only
296*ebdf3c68SMilanka Ringwald     sm_init();
297*ebdf3c68SMilanka Ringwald 
298*ebdf3c68SMilanka Ringwald     // setup ATT server
299*ebdf3c68SMilanka Ringwald     att_server_init(profile_data, NULL, NULL);
300*ebdf3c68SMilanka Ringwald 
301*ebdf3c68SMilanka Ringwald     // setup Nordic SPP service
302*ebdf3c68SMilanka Ringwald     nordic_spp_service_server_init(&nordic_data_received);
303*ebdf3c68SMilanka Ringwald 
304*ebdf3c68SMilanka Ringwald     // setup advertisements
305*ebdf3c68SMilanka Ringwald     uint16_t adv_int_min = 0x0030;
306*ebdf3c68SMilanka Ringwald     uint16_t adv_int_max = 0x0030;
307*ebdf3c68SMilanka Ringwald     uint8_t adv_type = 0;
308*ebdf3c68SMilanka Ringwald     bd_addr_t null_addr;
309*ebdf3c68SMilanka Ringwald     memset(null_addr, 0, 6);
310*ebdf3c68SMilanka Ringwald     gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00);
311*ebdf3c68SMilanka Ringwald     gap_advertisements_set_data(adv_data_len, (uint8_t*) adv_data);
312*ebdf3c68SMilanka Ringwald     gap_advertisements_enable(1);
313*ebdf3c68SMilanka Ringwald 
314*ebdf3c68SMilanka Ringwald     // init client state
315*ebdf3c68SMilanka Ringwald     init_connections();
316*ebdf3c68SMilanka Ringwald 
317*ebdf3c68SMilanka Ringwald     // turn on!
318*ebdf3c68SMilanka Ringwald 	hci_power_control(HCI_POWER_ON);
319*ebdf3c68SMilanka Ringwald 
320*ebdf3c68SMilanka Ringwald     return 0;
321*ebdf3c68SMilanka Ringwald }
322*ebdf3c68SMilanka Ringwald /* EXAMPLE_END */
323