xref: /btstack/example/le_credit_based_flow_control_mode_client.c (revision 2e80d8ec7f9a0e72d07ddbd1709e7cf2f475cf99)
1284d66bcSMatthias Ringwald /*
2284d66bcSMatthias Ringwald  * Copyright (C) 2018 BlueKitchen GmbH
3284d66bcSMatthias Ringwald  *
4284d66bcSMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5284d66bcSMatthias Ringwald  * modification, are permitted provided that the following conditions
6284d66bcSMatthias Ringwald  * are met:
7284d66bcSMatthias Ringwald  *
8284d66bcSMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9284d66bcSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10284d66bcSMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11284d66bcSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12284d66bcSMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13284d66bcSMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14284d66bcSMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15284d66bcSMatthias Ringwald  *    from this software without specific prior written permission.
16284d66bcSMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17284d66bcSMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18284d66bcSMatthias Ringwald  *    monetary gain.
19284d66bcSMatthias Ringwald  *
20284d66bcSMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21284d66bcSMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22284d66bcSMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23284d66bcSMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24284d66bcSMatthias Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25284d66bcSMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26284d66bcSMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27284d66bcSMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28284d66bcSMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29284d66bcSMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30284d66bcSMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31284d66bcSMatthias Ringwald  * SUCH DAMAGE.
32284d66bcSMatthias Ringwald  *
33284d66bcSMatthias Ringwald  * Please inquire about commercial licensing options at
34284d66bcSMatthias Ringwald  * [email protected]
35284d66bcSMatthias Ringwald  *
36284d66bcSMatthias Ringwald  */
37284d66bcSMatthias Ringwald 
38284d66bcSMatthias Ringwald #define BTSTACK_FILE__ "le_credit_based_flow_control_mode_client.c"
39284d66bcSMatthias Ringwald 
40284d66bcSMatthias Ringwald // *****************************************************************************
41284d66bcSMatthias Ringwald /* EXAMPLE_START(le_credit_based_flow_control_mode_client): LE Credit-Based Flow-Control Mode Client - Send Data over L2CAP
42284d66bcSMatthias Ringwald  *
43284d66bcSMatthias Ringwald  * @text Connects to 'LE CBM Server' and streams data
44284d66bcSMatthias Ringwald  * via L2CAP Channel in LE Credit-Based Flow-Control Mode (CBM)
45284d66bcSMatthias Ringwald  */
46284d66bcSMatthias Ringwald // *****************************************************************************
47284d66bcSMatthias Ringwald 
48284d66bcSMatthias Ringwald #include <inttypes.h>
49284d66bcSMatthias Ringwald #include <stdint.h>
50284d66bcSMatthias Ringwald #include <stdio.h>
51284d66bcSMatthias Ringwald #include <stdlib.h>
52284d66bcSMatthias Ringwald #include <string.h>
53284d66bcSMatthias Ringwald 
54284d66bcSMatthias Ringwald #include "btstack.h"
55284d66bcSMatthias Ringwald 
56284d66bcSMatthias Ringwald #define TEST_STREAM_DATA
57284d66bcSMatthias Ringwald #define TEST_PACKET_SIZE 1000
58284d66bcSMatthias Ringwald 
59284d66bcSMatthias Ringwald static enum {
60284d66bcSMatthias Ringwald     TC_OFF,
61284d66bcSMatthias Ringwald     TC_IDLE,
62284d66bcSMatthias Ringwald     TC_W4_SCAN_RESULT,
63284d66bcSMatthias Ringwald     TC_W4_CONNECT,
64284d66bcSMatthias Ringwald     TC_W4_CHANNEL,
65284d66bcSMatthias Ringwald     TC_TEST_DATA
66284d66bcSMatthias Ringwald } state = TC_OFF;
67284d66bcSMatthias Ringwald 
68284d66bcSMatthias Ringwald const uint16_t TSPX_le_psm = 0x25;
69284d66bcSMatthias Ringwald 
70284d66bcSMatthias Ringwald static bd_addr_t cmdline_addr;
71284d66bcSMatthias Ringwald static int cmdline_addr_found = 0;
72284d66bcSMatthias Ringwald 
73284d66bcSMatthias Ringwald // addr and type of device with correct name
74284d66bcSMatthias Ringwald static bd_addr_t      le_cbm_server_addr;
75284d66bcSMatthias Ringwald static bd_addr_type_t le_cbm_server_addr_type;
76284d66bcSMatthias Ringwald 
77284d66bcSMatthias Ringwald static hci_con_handle_t connection_handle;
78284d66bcSMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
79284d66bcSMatthias Ringwald static btstack_packet_callback_registration_t sm_event_callback_registration;
80284d66bcSMatthias Ringwald 
81284d66bcSMatthias Ringwald static uint8_t cbm_receive_buffer[TEST_PACKET_SIZE];
82284d66bcSMatthias Ringwald 
83284d66bcSMatthias Ringwald /*
84284d66bcSMatthias Ringwald  * @section Track throughput
85284d66bcSMatthias Ringwald  * @text We calculate the throughput by setting a start time and measuring the amount of
86284d66bcSMatthias Ringwald  * data sent. After a configurable REPORT_INTERVAL_MS, we print the throughput in kB/s
87284d66bcSMatthias Ringwald  * and reset the counter and start time.
88284d66bcSMatthias Ringwald  */
89284d66bcSMatthias Ringwald 
90284d66bcSMatthias Ringwald /* LISTING_START(tracking): Tracking throughput */
91284d66bcSMatthias Ringwald 
92284d66bcSMatthias Ringwald #define REPORT_INTERVAL_MS 3000
93284d66bcSMatthias Ringwald 
94284d66bcSMatthias Ringwald // support for multiple clients
95284d66bcSMatthias Ringwald typedef struct {
96284d66bcSMatthias Ringwald     char name;
97284d66bcSMatthias Ringwald     hci_con_handle_t connection_handle;
98284d66bcSMatthias Ringwald     uint16_t cid;
99284d66bcSMatthias Ringwald     int  counter;
100284d66bcSMatthias Ringwald     char test_data[TEST_PACKET_SIZE];
101284d66bcSMatthias Ringwald     int  test_data_len;
102284d66bcSMatthias Ringwald     uint32_t test_data_sent;
103284d66bcSMatthias Ringwald     uint32_t test_data_start;
104284d66bcSMatthias Ringwald } le_cbm_connection_t;
105284d66bcSMatthias Ringwald 
106284d66bcSMatthias Ringwald static le_cbm_connection_t le_cbm_connection;
107284d66bcSMatthias Ringwald 
test_reset(le_cbm_connection_t * context)108284d66bcSMatthias Ringwald static void test_reset(le_cbm_connection_t * context){
109284d66bcSMatthias Ringwald     context->test_data_start = btstack_run_loop_get_time_ms();
110284d66bcSMatthias Ringwald     context->test_data_sent = 0;
111284d66bcSMatthias Ringwald }
112284d66bcSMatthias Ringwald 
test_track_data(le_cbm_connection_t * context,int bytes_transferred)113284d66bcSMatthias Ringwald static void test_track_data(le_cbm_connection_t * context, int bytes_transferred){
114284d66bcSMatthias Ringwald     context->test_data_sent += bytes_transferred;
115284d66bcSMatthias Ringwald     // evaluate
116284d66bcSMatthias Ringwald     uint32_t now = btstack_run_loop_get_time_ms();
117284d66bcSMatthias Ringwald     uint32_t time_passed = now - context->test_data_start;
118284d66bcSMatthias Ringwald     if (time_passed < REPORT_INTERVAL_MS) return;
119284d66bcSMatthias Ringwald     // print speed
120284d66bcSMatthias Ringwald     int bytes_per_second = context->test_data_sent * 1000 / time_passed;
121284d66bcSMatthias Ringwald     printf("%c: %"PRIu32" bytes -> %u.%03u kB/s\n", context->name, context->test_data_sent, bytes_per_second / 1000, bytes_per_second % 1000);
122284d66bcSMatthias Ringwald 
123284d66bcSMatthias Ringwald     // restart
124284d66bcSMatthias Ringwald     context->test_data_start = now;
125284d66bcSMatthias Ringwald     context->test_data_sent  = 0;
126284d66bcSMatthias Ringwald }
127284d66bcSMatthias Ringwald /* LISTING_END(tracking): Tracking throughput */
128284d66bcSMatthias Ringwald 
129284d66bcSMatthias Ringwald 
1305d81be33SMatthias Ringwald // returns true if name is found in advertisement
advertisement_report_contains_name(const char * name,uint8_t * advertisement_report)1315d81be33SMatthias Ringwald static bool advertisement_report_contains_name(const char * name, uint8_t * advertisement_report){
132284d66bcSMatthias Ringwald     // get advertisement from report event
133284d66bcSMatthias Ringwald     const uint8_t * adv_data = gap_event_advertising_report_get_data(advertisement_report);
1340801ef92SMatthias Ringwald     uint8_t         adv_len  = gap_event_advertising_report_get_data_length(advertisement_report);
1350801ef92SMatthias Ringwald     uint16_t        name_len = (uint16_t) strlen(name);
136284d66bcSMatthias Ringwald 
137284d66bcSMatthias Ringwald     // iterate over advertisement data
138284d66bcSMatthias Ringwald     ad_context_t context;
139284d66bcSMatthias Ringwald     for (ad_iterator_init(&context, adv_len, adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)){
140284d66bcSMatthias Ringwald         uint8_t data_type    = ad_iterator_get_data_type(&context);
141284d66bcSMatthias Ringwald         uint8_t data_size    = ad_iterator_get_data_len(&context);
142284d66bcSMatthias Ringwald         const uint8_t * data = ad_iterator_get_data(&context);
143284d66bcSMatthias Ringwald         switch (data_type){
144284d66bcSMatthias Ringwald             case BLUETOOTH_DATA_TYPE_SHORTENED_LOCAL_NAME:
145284d66bcSMatthias Ringwald             case BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME:
146284d66bcSMatthias Ringwald                 // compare prefix
147284d66bcSMatthias Ringwald                 if (data_size < name_len) break;
1485d81be33SMatthias Ringwald                 if (memcmp(data, name, name_len) == 0) return true;
1495d81be33SMatthias Ringwald                 break;
150284d66bcSMatthias Ringwald             default:
151284d66bcSMatthias Ringwald                 break;
152284d66bcSMatthias Ringwald         }
153284d66bcSMatthias Ringwald     }
154284d66bcSMatthias Ringwald     return 0;
155284d66bcSMatthias Ringwald }
156284d66bcSMatthias Ringwald 
157284d66bcSMatthias Ringwald #ifdef TEST_STREAM_DATA
158284d66bcSMatthias Ringwald /* LISTING_END */
159284d66bcSMatthias Ringwald /*
160284d66bcSMatthias Ringwald  * @section Streamer
161284d66bcSMatthias Ringwald  *
162284d66bcSMatthias Ringwald  * @text The streamer function checks if notifications are enabled and if a notification can be sent now.
163284d66bcSMatthias Ringwald  * It creates some test data - a single letter that gets increased every time - and tracks the data sent.
164284d66bcSMatthias Ringwald  */
165284d66bcSMatthias Ringwald 
166284d66bcSMatthias Ringwald  /* LISTING_START(streamer): Streaming code */
streamer(void)167284d66bcSMatthias Ringwald static void streamer(void){
168284d66bcSMatthias Ringwald 
169284d66bcSMatthias Ringwald     // create test data
170284d66bcSMatthias Ringwald     le_cbm_connection.counter++;
171284d66bcSMatthias Ringwald     if (le_cbm_connection.counter > 'Z') le_cbm_connection.counter = 'A';
172284d66bcSMatthias Ringwald     memset(le_cbm_connection.test_data, le_cbm_connection.counter, le_cbm_connection.test_data_len);
173284d66bcSMatthias Ringwald 
174284d66bcSMatthias Ringwald     // send
175f062abd6SMatthias Ringwald     l2cap_send(le_cbm_connection.cid, (uint8_t *) le_cbm_connection.test_data, le_cbm_connection.test_data_len);
176284d66bcSMatthias Ringwald 
177284d66bcSMatthias Ringwald     // track
178284d66bcSMatthias Ringwald     test_track_data(&le_cbm_connection, le_cbm_connection.test_data_len);
179284d66bcSMatthias Ringwald 
180284d66bcSMatthias Ringwald     // request another packet
181f062abd6SMatthias Ringwald     l2cap_request_can_send_now_event(le_cbm_connection.cid);
182284d66bcSMatthias Ringwald }
183284d66bcSMatthias Ringwald /* LISTING_END */
184284d66bcSMatthias Ringwald #endif
185284d66bcSMatthias Ringwald 
186284d66bcSMatthias Ringwald // Either connect to remote specified on command line or start scan for device with "LE CBM Server" in advertisement
le_cbm_client_start(void)187284d66bcSMatthias Ringwald static void le_cbm_client_start(void){
188284d66bcSMatthias Ringwald     if (cmdline_addr_found){
189284d66bcSMatthias Ringwald         printf("Connect to %s\n", bd_addr_to_str(cmdline_addr));
190284d66bcSMatthias Ringwald         state = TC_W4_CONNECT;
191284d66bcSMatthias Ringwald         gap_connect(cmdline_addr, 0);
192284d66bcSMatthias Ringwald     } else {
193284d66bcSMatthias Ringwald         printf("Start scanning!\n");
194284d66bcSMatthias Ringwald         state = TC_W4_SCAN_RESULT;
195284d66bcSMatthias Ringwald         gap_set_scan_parameters(0,0x0030, 0x0030);
196284d66bcSMatthias Ringwald         gap_start_scan();
197284d66bcSMatthias Ringwald     }
198284d66bcSMatthias Ringwald }
199284d66bcSMatthias Ringwald 
packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)200284d66bcSMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
201284d66bcSMatthias Ringwald     UNUSED(channel);
202284d66bcSMatthias Ringwald     UNUSED(size);
203284d66bcSMatthias Ringwald 
204284d66bcSMatthias Ringwald     bd_addr_t event_address;
205284d66bcSMatthias Ringwald     uint16_t psm;
206284d66bcSMatthias Ringwald     uint16_t cid;
207284d66bcSMatthias Ringwald     uint16_t conn_interval;
208284d66bcSMatthias Ringwald     hci_con_handle_t handle;
209284d66bcSMatthias Ringwald     uint8_t status;
210284d66bcSMatthias Ringwald 
211284d66bcSMatthias Ringwald     switch (packet_type) {
212284d66bcSMatthias Ringwald         case HCI_EVENT_PACKET:
213284d66bcSMatthias Ringwald             switch (hci_event_packet_get_type(packet)) {
214284d66bcSMatthias Ringwald                 case BTSTACK_EVENT_STATE:
215284d66bcSMatthias Ringwald                     // BTstack activated, get started
216284d66bcSMatthias Ringwald                     if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING) {
217284d66bcSMatthias Ringwald                         le_cbm_client_start();
218284d66bcSMatthias Ringwald                     } else {
219284d66bcSMatthias Ringwald                         state = TC_OFF;
220284d66bcSMatthias Ringwald                     }
221284d66bcSMatthias Ringwald                     break;
222284d66bcSMatthias Ringwald                 case GAP_EVENT_ADVERTISING_REPORT:
223284d66bcSMatthias Ringwald                     if (state != TC_W4_SCAN_RESULT) return;
224284d66bcSMatthias Ringwald                     // check name in advertisement
225284d66bcSMatthias Ringwald                     if (!advertisement_report_contains_name("LE CBM Server", packet)) return;
226284d66bcSMatthias Ringwald                     // store address and type
227284d66bcSMatthias Ringwald                     gap_event_advertising_report_get_address(packet, le_cbm_server_addr);
228284d66bcSMatthias Ringwald                     le_cbm_server_addr_type = gap_event_advertising_report_get_address_type(packet);
229284d66bcSMatthias Ringwald                     // stop scanning, and connect to the device
230284d66bcSMatthias Ringwald                     state = TC_W4_CONNECT;
231284d66bcSMatthias Ringwald                     gap_stop_scan();
232284d66bcSMatthias Ringwald                     printf("Stop scan. Connect to device with addr %s.\n", bd_addr_to_str(le_cbm_server_addr));
233284d66bcSMatthias Ringwald                     gap_connect(le_cbm_server_addr, le_cbm_server_addr_type);
234284d66bcSMatthias Ringwald                     break;
235bba48196SMatthias Ringwald                 case HCI_EVENT_META_GAP:
236284d66bcSMatthias Ringwald                     // wait for connection complete
237bba48196SMatthias Ringwald                     if (hci_event_gap_meta_get_subevent_code(packet) != GAP_SUBEVENT_LE_CONNECTION_COMPLETE) break;
238284d66bcSMatthias Ringwald                     if (state != TC_W4_CONNECT) return;
239bba48196SMatthias Ringwald                     connection_handle = gap_subevent_le_connection_complete_get_connection_handle(packet);
240284d66bcSMatthias Ringwald                     // print connection parameters (without using float operations)
241bba48196SMatthias Ringwald                     conn_interval = gap_subevent_le_connection_complete_get_conn_interval(packet);
242284d66bcSMatthias Ringwald                     printf("Connection Interval: %u.%02u ms\n", conn_interval * 125 / 100, 25 * (conn_interval & 3));
243bba48196SMatthias Ringwald                     printf("Connection Latency: %u\n", gap_subevent_le_connection_complete_get_conn_latency(packet));
244284d66bcSMatthias Ringwald                     // initialize gatt client context with handle, and add it to the list of active clients
245284d66bcSMatthias Ringwald                     // query primary services
246284d66bcSMatthias Ringwald                     printf("Connect to performance test service.\n");
247284d66bcSMatthias Ringwald                     state = TC_W4_CHANNEL;
248284d66bcSMatthias Ringwald                     l2cap_cbm_create_channel(&packet_handler, connection_handle, TSPX_le_psm, cbm_receive_buffer,
249284d66bcSMatthias Ringwald                                              sizeof(cbm_receive_buffer), L2CAP_LE_AUTOMATIC_CREDITS, LEVEL_0, &le_cbm_connection.cid);
250284d66bcSMatthias Ringwald                     break;
251284d66bcSMatthias Ringwald                 case HCI_EVENT_DISCONNECTION_COMPLETE:
252284d66bcSMatthias Ringwald                     if (cmdline_addr_found){
253284d66bcSMatthias Ringwald                         printf("Disconnected %s\n", bd_addr_to_str(cmdline_addr));
254284d66bcSMatthias Ringwald                         return;
255284d66bcSMatthias Ringwald                     }
256284d66bcSMatthias Ringwald                     printf("Disconnected %s\n", bd_addr_to_str(le_cbm_server_addr));
257284d66bcSMatthias Ringwald                     if (state == TC_OFF) break;
258284d66bcSMatthias Ringwald                     le_cbm_client_start();
259284d66bcSMatthias Ringwald                     break;
260284d66bcSMatthias Ringwald                 case L2CAP_EVENT_CBM_CHANNEL_OPENED:
261284d66bcSMatthias Ringwald                     // inform about new l2cap connection
262feadaffdSMatthias Ringwald                     l2cap_event_cbm_channel_opened_get_address(packet, event_address);
263feadaffdSMatthias Ringwald                     psm = l2cap_event_cbm_channel_opened_get_psm(packet);
264feadaffdSMatthias Ringwald                     cid = l2cap_event_cbm_channel_opened_get_local_cid(packet);
265feadaffdSMatthias Ringwald                     handle = l2cap_event_cbm_channel_opened_get_handle(packet);
266feadaffdSMatthias Ringwald                     status = l2cap_event_cbm_channel_opened_get_status(packet);
267284d66bcSMatthias Ringwald                     if (status == ERROR_CODE_SUCCESS) {
268fcd55a0bSMilanka Ringwald                         printf("L2CAP: CBM Channel successfully opened: %s, handle 0x%04x, psm 0x%02x, local cid 0x%02x, remote cid 0x%02x\n",
269284d66bcSMatthias Ringwald                                bd_addr_to_str(event_address), handle, psm, cid,  little_endian_read_16(packet, 15));
270284d66bcSMatthias Ringwald                         le_cbm_connection.cid = cid;
271284d66bcSMatthias Ringwald                         le_cbm_connection.connection_handle = handle;
272feadaffdSMatthias Ringwald                         le_cbm_connection.test_data_len = btstack_min(l2cap_event_cbm_channel_opened_get_remote_mtu(packet), sizeof(le_cbm_connection.test_data));
273284d66bcSMatthias Ringwald                         state = TC_TEST_DATA;
274284d66bcSMatthias Ringwald                         printf("Test packet size: %u\n", le_cbm_connection.test_data_len);
275284d66bcSMatthias Ringwald                         test_reset(&le_cbm_connection);
276284d66bcSMatthias Ringwald #ifdef TEST_STREAM_DATA
277f062abd6SMatthias Ringwald                         l2cap_request_can_send_now_event(le_cbm_connection.cid);
278284d66bcSMatthias Ringwald #endif
279284d66bcSMatthias Ringwald                     } else {
280284d66bcSMatthias Ringwald                         printf("L2CAP: Connection to device %s failed. status code 0x%02x\n", bd_addr_to_str(event_address), status);
281284d66bcSMatthias Ringwald                     }
282284d66bcSMatthias Ringwald                     break;
283284d66bcSMatthias Ringwald 
284284d66bcSMatthias Ringwald #ifdef TEST_STREAM_DATA
28501f33f4aSMatthias Ringwald                 case L2CAP_EVENT_CAN_SEND_NOW:
286284d66bcSMatthias Ringwald                     streamer();
287284d66bcSMatthias Ringwald                     break;
288284d66bcSMatthias Ringwald #endif
289284d66bcSMatthias Ringwald 
29001f33f4aSMatthias Ringwald                 case L2CAP_EVENT_CHANNEL_CLOSED:
291feadaffdSMatthias Ringwald                     cid = l2cap_event_channel_closed_get_local_cid(packet);
292284d66bcSMatthias Ringwald                     printf("L2CAP: Channel closed 0x%02x\n", cid);
293284d66bcSMatthias Ringwald                     break;
294284d66bcSMatthias Ringwald 
295284d66bcSMatthias Ringwald                 default:
296284d66bcSMatthias Ringwald                     break;
297284d66bcSMatthias Ringwald             }
298284d66bcSMatthias Ringwald             break;
299284d66bcSMatthias Ringwald 
300284d66bcSMatthias Ringwald         case L2CAP_DATA_PACKET:
301284d66bcSMatthias Ringwald             test_track_data(&le_cbm_connection, size);
302284d66bcSMatthias Ringwald             break;
303284d66bcSMatthias Ringwald 
304284d66bcSMatthias Ringwald         default:
305284d66bcSMatthias Ringwald             break;
306284d66bcSMatthias Ringwald     }
307284d66bcSMatthias Ringwald }
308284d66bcSMatthias Ringwald 
309284d66bcSMatthias Ringwald /*
310284d66bcSMatthias Ringwald  * @section SM Packet Handler
311284d66bcSMatthias Ringwald  *
312284d66bcSMatthias Ringwald  * @text The packet handler is used to handle pairing requests
313284d66bcSMatthias Ringwald  */
sm_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)314284d66bcSMatthias Ringwald static void sm_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
315284d66bcSMatthias Ringwald     UNUSED(channel);
316284d66bcSMatthias Ringwald     UNUSED(size);
317284d66bcSMatthias Ringwald 
318284d66bcSMatthias Ringwald     if (packet_type != HCI_EVENT_PACKET) return;
319284d66bcSMatthias Ringwald 
320284d66bcSMatthias Ringwald     switch (hci_event_packet_get_type(packet)) {
321284d66bcSMatthias Ringwald         case SM_EVENT_JUST_WORKS_REQUEST:
322284d66bcSMatthias Ringwald             printf("Just Works requested\n");
323284d66bcSMatthias Ringwald             sm_just_works_confirm(sm_event_just_works_request_get_handle(packet));
324284d66bcSMatthias Ringwald             break;
325284d66bcSMatthias Ringwald         case SM_EVENT_NUMERIC_COMPARISON_REQUEST:
326284d66bcSMatthias Ringwald             printf("Confirming numeric comparison: %"PRIu32"\n", sm_event_numeric_comparison_request_get_passkey(packet));
327284d66bcSMatthias Ringwald             sm_numeric_comparison_confirm(sm_event_passkey_display_number_get_handle(packet));
328284d66bcSMatthias Ringwald             break;
329284d66bcSMatthias Ringwald         case SM_EVENT_PASSKEY_DISPLAY_NUMBER:
330284d66bcSMatthias Ringwald             printf("Display Passkey: %"PRIu32"\n", sm_event_passkey_display_number_get_passkey(packet));
331284d66bcSMatthias Ringwald             break;
332284d66bcSMatthias Ringwald         default:
333284d66bcSMatthias Ringwald             break;
334284d66bcSMatthias Ringwald     }
335284d66bcSMatthias Ringwald }
336284d66bcSMatthias Ringwald 
337284d66bcSMatthias Ringwald #ifdef HAVE_BTSTACK_STDIN
usage(const char * name)338284d66bcSMatthias Ringwald static void usage(const char *name){
339284d66bcSMatthias Ringwald     fprintf(stderr, "Usage: %s [-a|--address aa:bb:cc:dd:ee:ff]\n", name);
340284d66bcSMatthias Ringwald     fprintf(stderr, "If no argument is provided, LE CBM Client will start scanning and connect to the first device named 'LE CBM Server'.\n");
341284d66bcSMatthias Ringwald     fprintf(stderr, "To connect to a specific device use argument [-a].\n\n");
342284d66bcSMatthias Ringwald }
343284d66bcSMatthias Ringwald #endif
344284d66bcSMatthias Ringwald 
345284d66bcSMatthias Ringwald int btstack_main(int argc, const char * argv[]);
btstack_main(int argc,const char * argv[])346284d66bcSMatthias Ringwald int btstack_main(int argc, const char * argv[]){
347284d66bcSMatthias Ringwald 
348284d66bcSMatthias Ringwald #ifdef HAVE_BTSTACK_STDIN
349*2e80d8ecSSteven Buytaert     int arg;
350284d66bcSMatthias Ringwald     cmdline_addr_found = 0;
351284d66bcSMatthias Ringwald 
352*2e80d8ecSSteven Buytaert     for (arg = 1; arg < argc; arg++) {
353284d66bcSMatthias Ringwald         if(!strcmp(argv[arg], "-a") || !strcmp(argv[arg], "--address")){
354*2e80d8ecSSteven Buytaert             if (arg + 1 < argc) {
355284d66bcSMatthias Ringwald                 arg++;
356284d66bcSMatthias Ringwald                 cmdline_addr_found = sscanf_bd_addr(argv[arg], cmdline_addr);
357284d66bcSMatthias Ringwald             }
358*2e80d8ecSSteven Buytaert             if (!cmdline_addr_found) {
359284d66bcSMatthias Ringwald                 usage(argv[0]);
360*2e80d8ecSSteven Buytaert                 return 1;
361*2e80d8ecSSteven Buytaert             }
362*2e80d8ecSSteven Buytaert         }
363*2e80d8ecSSteven Buytaert     }
364*2e80d8ecSSteven Buytaert     if (!cmdline_addr_found) {
365*2e80d8ecSSteven Buytaert         fprintf(stderr, "No specific address specified or found; start scanning for 'LE Streamer' advertisement.\n");
366284d66bcSMatthias Ringwald     }
367284d66bcSMatthias Ringwald #else
368284d66bcSMatthias Ringwald     (void)argc;
369284d66bcSMatthias Ringwald     (void)argv;
370284d66bcSMatthias Ringwald #endif
371284d66bcSMatthias Ringwald 
372284d66bcSMatthias Ringwald     l2cap_init();
373284d66bcSMatthias Ringwald 
374284d66bcSMatthias Ringwald     sm_init();
375284d66bcSMatthias Ringwald     sm_set_io_capabilities(IO_CAPABILITY_NO_INPUT_NO_OUTPUT);
376284d66bcSMatthias Ringwald 
377284d66bcSMatthias Ringwald     hci_event_callback_registration.callback = &packet_handler;
378284d66bcSMatthias Ringwald     hci_add_event_handler(&hci_event_callback_registration);
379284d66bcSMatthias Ringwald 
380284d66bcSMatthias Ringwald     sm_event_callback_registration.callback = &sm_packet_handler;
381284d66bcSMatthias Ringwald     sm_add_event_handler(&sm_event_callback_registration);
382284d66bcSMatthias Ringwald 
383284d66bcSMatthias Ringwald     // turn on!
384284d66bcSMatthias Ringwald     hci_power_control(HCI_POWER_ON);
385284d66bcSMatthias Ringwald 
386284d66bcSMatthias Ringwald     return 0;
387284d66bcSMatthias Ringwald }
388284d66bcSMatthias Ringwald /* EXAMPLE_END */
389