xref: /btstack/port/renesas-tb-s1ja-cc256x/template/btstack_example/src/example.c (revision 73a7b814a17455082ed4829a4c7f4f4c3ee853b7)
13b5c872aSMatthias Ringwald /*
23b5c872aSMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
33b5c872aSMatthias Ringwald  *
43b5c872aSMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
53b5c872aSMatthias Ringwald  * modification, are permitted provided that the following conditions
63b5c872aSMatthias Ringwald  * are met:
73b5c872aSMatthias Ringwald  *
83b5c872aSMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
93b5c872aSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
103b5c872aSMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
113b5c872aSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
123b5c872aSMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
133b5c872aSMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
143b5c872aSMatthias Ringwald  *    contributors may be used to endorse or promote products derived
153b5c872aSMatthias Ringwald  *    from this software without specific prior written permission.
163b5c872aSMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
173b5c872aSMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
183b5c872aSMatthias Ringwald  *    monetary gain.
193b5c872aSMatthias Ringwald  *
203b5c872aSMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
213b5c872aSMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
223b5c872aSMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
232fca4dadSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
253b5c872aSMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
263b5c872aSMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
273b5c872aSMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
283b5c872aSMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
293b5c872aSMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
303b5c872aSMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
313b5c872aSMatthias Ringwald  * SUCH DAMAGE.
323b5c872aSMatthias Ringwald  *
333b5c872aSMatthias Ringwald  * Please inquire about commercial licensing options at
343b5c872aSMatthias Ringwald  * [email protected]
353b5c872aSMatthias Ringwald  *
363b5c872aSMatthias Ringwald  */
373b5c872aSMatthias Ringwald 
383b5c872aSMatthias Ringwald #define BTSTACK_FILE__ "gatt_streamer.c"
393b5c872aSMatthias Ringwald 
403b5c872aSMatthias Ringwald // *****************************************************************************
413b5c872aSMatthias Ringwald /* EXAMPLE_START(le_streamer): LE Streamer - Stream data over GATT.
423b5c872aSMatthias Ringwald  *
433b5c872aSMatthias Ringwald  * @text All newer operating systems provide GATT Client functionality.
443b5c872aSMatthias Ringwald  * This example shows how to get a maximal throughput via BLE:
453b5c872aSMatthias Ringwald  * - send whenever possible,
463b5c872aSMatthias Ringwald  * - use the max ATT MTU.
473b5c872aSMatthias Ringwald  *
483b5c872aSMatthias Ringwald  * @text In theory, we should also update the connection parameters, but we already get
493b5c872aSMatthias Ringwald  * a connection interval of 30 ms and there's no public way to use a shorter
503b5c872aSMatthias Ringwald  * interval with iOS (if we're not implementing an HID device).
513b5c872aSMatthias Ringwald  *
523b5c872aSMatthias Ringwald  * @text Note: To start the streaming, run the example.
533b5c872aSMatthias Ringwald  * On remote device use some GATT Explorer, e.g. LightBlue, BLExplr to enable notifications.
543b5c872aSMatthias Ringwald  */
553b5c872aSMatthias Ringwald  // *****************************************************************************
563b5c872aSMatthias Ringwald 
573b5c872aSMatthias Ringwald #include <inttypes.h>
583b5c872aSMatthias Ringwald #include <stdint.h>
593b5c872aSMatthias Ringwald #include <stdio.h>
603b5c872aSMatthias Ringwald #include <stdlib.h>
613b5c872aSMatthias Ringwald #include <string.h>
623b5c872aSMatthias Ringwald 
633b5c872aSMatthias Ringwald #include "btstack.h"
643b5c872aSMatthias Ringwald 
653b5c872aSMatthias Ringwald // le_streamer.gatt contains the declaration of the provided GATT Services + Characteristics
663b5c872aSMatthias Ringwald // le_streamer.h    contains the binary representation of le_streamer.gatt
673b5c872aSMatthias Ringwald // it is generated by the build system by calling: $BTSTACK_ROOT/tool/compile_gatt.py le_streamer.gatt le_streamer.h
683b5c872aSMatthias Ringwald // it needs to be regenerated when the GATT Database declared in le_streamer.gatt file is modified
693b5c872aSMatthias Ringwald #include "gatt_streamer_server.h"
703b5c872aSMatthias Ringwald 
713b5c872aSMatthias Ringwald #define REPORT_INTERVAL_MS 3000
723b5c872aSMatthias Ringwald #define MAX_NR_CONNECTIONS 3
733b5c872aSMatthias Ringwald 
743b5c872aSMatthias Ringwald 
753b5c872aSMatthias Ringwald static void  hci_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
763b5c872aSMatthias Ringwald static void  att_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
773b5c872aSMatthias Ringwald static int   att_write_callback(hci_con_handle_t con_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size);
783b5c872aSMatthias Ringwald static void  streamer(void);
793b5c872aSMatthias Ringwald 
803b5c872aSMatthias Ringwald const uint8_t adv_data[] = {
813b5c872aSMatthias Ringwald     // Flags general discoverable, BR/EDR not supported
823b5c872aSMatthias Ringwald     0x02, BLUETOOTH_DATA_TYPE_FLAGS, 0x06,
833b5c872aSMatthias Ringwald     // Name
843b5c872aSMatthias Ringwald     0x0c, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, 'L', 'E', ' ', 'S', 't', 'r', 'e', 'a', 'm', 'e', 'r',
853b5c872aSMatthias Ringwald     // Incomplete List of 16-bit Service Class UUIDs -- FF10 - only valid for testing!
863b5c872aSMatthias Ringwald     0x03, BLUETOOTH_DATA_TYPE_INCOMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS, 0x10, 0xff,
873b5c872aSMatthias Ringwald };
883b5c872aSMatthias Ringwald const uint8_t adv_data_len = sizeof(adv_data);
893b5c872aSMatthias Ringwald 
903b5c872aSMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
913b5c872aSMatthias Ringwald 
923b5c872aSMatthias Ringwald // support for multiple clients
933b5c872aSMatthias Ringwald typedef struct {
943b5c872aSMatthias Ringwald     char name;
953b5c872aSMatthias Ringwald     int le_notification_enabled;
963b5c872aSMatthias Ringwald     uint16_t value_handle;
973b5c872aSMatthias Ringwald     hci_con_handle_t connection_handle;
983b5c872aSMatthias Ringwald     int  counter;
993b5c872aSMatthias Ringwald     char test_data[200];
1003b5c872aSMatthias Ringwald     int  test_data_len;
1013b5c872aSMatthias Ringwald     uint32_t test_data_sent;
1023b5c872aSMatthias Ringwald     uint32_t test_data_start;
1033b5c872aSMatthias Ringwald } le_streamer_connection_t;
1043b5c872aSMatthias Ringwald static le_streamer_connection_t le_streamer_connections[MAX_NR_CONNECTIONS];
1053b5c872aSMatthias Ringwald 
1063b5c872aSMatthias Ringwald // round robin sending
1073b5c872aSMatthias Ringwald static int connection_index;
1083b5c872aSMatthias Ringwald 
1093b5c872aSMatthias Ringwald #ifdef ENABLE_GATT_OVER_CLASSIC
1103b5c872aSMatthias Ringwald static uint8_t gatt_service_buffer[70];
1113b5c872aSMatthias Ringwald #endif
1123b5c872aSMatthias Ringwald 
init_connections(void)1133b5c872aSMatthias Ringwald static void init_connections(void){
1143b5c872aSMatthias Ringwald     // track connections
1153b5c872aSMatthias Ringwald     int i;
1163b5c872aSMatthias Ringwald     for (i=0;i<MAX_NR_CONNECTIONS;i++){
1173b5c872aSMatthias Ringwald         le_streamer_connections[i].connection_handle = HCI_CON_HANDLE_INVALID;
1183b5c872aSMatthias Ringwald         le_streamer_connections[i].name = 'A' + i;
1193b5c872aSMatthias Ringwald     }
1203b5c872aSMatthias Ringwald }
1213b5c872aSMatthias Ringwald 
connection_for_conn_handle(hci_con_handle_t conn_handle)1223b5c872aSMatthias Ringwald static le_streamer_connection_t * connection_for_conn_handle(hci_con_handle_t conn_handle){
1233b5c872aSMatthias Ringwald     int i;
1243b5c872aSMatthias Ringwald     for (i=0;i<MAX_NR_CONNECTIONS;i++){
1253b5c872aSMatthias Ringwald         if (le_streamer_connections[i].connection_handle == conn_handle) return &le_streamer_connections[i];
1263b5c872aSMatthias Ringwald     }
1273b5c872aSMatthias Ringwald     return NULL;
1283b5c872aSMatthias Ringwald }
1293b5c872aSMatthias Ringwald 
next_connection_index(void)1303b5c872aSMatthias Ringwald static void next_connection_index(void){
1313b5c872aSMatthias Ringwald     connection_index++;
1323b5c872aSMatthias Ringwald     if (connection_index == MAX_NR_CONNECTIONS){
1333b5c872aSMatthias Ringwald         connection_index = 0;
1343b5c872aSMatthias Ringwald     }
1353b5c872aSMatthias Ringwald }
1363b5c872aSMatthias Ringwald 
1373b5c872aSMatthias Ringwald /* @section Main Application Setup
1383b5c872aSMatthias Ringwald  *
1393b5c872aSMatthias Ringwald  * @text Listing MainConfiguration shows main application code.
1403b5c872aSMatthias Ringwald  * It initializes L2CAP, the Security Manager, and configures the ATT Server with the pre-compiled
1413b5c872aSMatthias Ringwald  * ATT Database generated from $le_streamer.gatt$. Finally, it configures the advertisements
1423b5c872aSMatthias Ringwald  * and boots the Bluetooth stack.
1433b5c872aSMatthias Ringwald  */
1443b5c872aSMatthias Ringwald 
1453b5c872aSMatthias Ringwald /* LISTING_START(MainConfiguration): Init L2CAP, SM, ATT Server, and enable advertisements */
1463b5c872aSMatthias Ringwald 
le_streamer_setup(void)1473b5c872aSMatthias Ringwald static void le_streamer_setup(void){
1483b5c872aSMatthias Ringwald 
1493b5c872aSMatthias Ringwald     l2cap_init();
1503b5c872aSMatthias Ringwald 
1513b5c872aSMatthias Ringwald     // setup le device db
1523b5c872aSMatthias Ringwald     le_device_db_init();
1533b5c872aSMatthias Ringwald 
1543b5c872aSMatthias Ringwald     // setup SM: Display only
1553b5c872aSMatthias Ringwald     sm_init();
1563b5c872aSMatthias Ringwald 
1573b5c872aSMatthias Ringwald #ifdef ENABLE_GATT_OVER_CLASSIC
1583b5c872aSMatthias Ringwald     // init SDP, create record for GATT and register with SDP
1593b5c872aSMatthias Ringwald     sdp_init();
1603b5c872aSMatthias Ringwald     memset(gatt_service_buffer, 0, sizeof(gatt_service_buffer));
1613b5c872aSMatthias Ringwald     gatt_create_sdp_record(gatt_service_buffer, 0x10001, ATT_SERVICE_GATT_SERVICE_START_HANDLE, ATT_SERVICE_GATT_SERVICE_END_HANDLE);
1623b5c872aSMatthias Ringwald     sdp_register_service(gatt_service_buffer);
1633b5c872aSMatthias Ringwald     printf("SDP service record size: %u\n", de_get_len(gatt_service_buffer));
1643b5c872aSMatthias Ringwald 
1653b5c872aSMatthias Ringwald     // configure Classic GAP
1663b5c872aSMatthias Ringwald     gap_set_local_name("GATT Streamer BR/EDR 00:00:00:00:00:00");
1673b5c872aSMatthias Ringwald     gap_ssp_set_io_capability(SSP_IO_CAPABILITY_DISPLAY_YES_NO);
1683b5c872aSMatthias Ringwald     gap_discoverable_control(1);
1693b5c872aSMatthias Ringwald #endif
1703b5c872aSMatthias Ringwald 
1713b5c872aSMatthias Ringwald     // setup ATT server
1723b5c872aSMatthias Ringwald     att_server_init(profile_data, NULL, att_write_callback);
1733b5c872aSMatthias Ringwald 
1743b5c872aSMatthias Ringwald     // register for HCI events
1753b5c872aSMatthias Ringwald     hci_event_callback_registration.callback = &hci_packet_handler;
1763b5c872aSMatthias Ringwald     hci_add_event_handler(&hci_event_callback_registration);
1773b5c872aSMatthias Ringwald 
1783b5c872aSMatthias Ringwald     // register for ATT events
1793b5c872aSMatthias Ringwald     att_server_register_packet_handler(att_packet_handler);
1803b5c872aSMatthias Ringwald 
1813b5c872aSMatthias Ringwald     // setup advertisements
1823b5c872aSMatthias Ringwald     uint16_t adv_int_min = 0x0030;
1833b5c872aSMatthias Ringwald     uint16_t adv_int_max = 0x0030;
1843b5c872aSMatthias Ringwald     uint8_t adv_type = 0;
1853b5c872aSMatthias Ringwald     bd_addr_t null_addr;
1863b5c872aSMatthias Ringwald     memset(null_addr, 0, 6);
1873b5c872aSMatthias Ringwald     gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00);
1883b5c872aSMatthias Ringwald     gap_advertisements_set_data(adv_data_len, (uint8_t*) adv_data);
1893b5c872aSMatthias Ringwald     gap_advertisements_enable(1);
1903b5c872aSMatthias Ringwald 
1913b5c872aSMatthias Ringwald     // init client state
1923b5c872aSMatthias Ringwald     init_connections();
1933b5c872aSMatthias Ringwald }
1943b5c872aSMatthias Ringwald /* LISTING_END */
1953b5c872aSMatthias Ringwald 
1963b5c872aSMatthias Ringwald /*
1973b5c872aSMatthias Ringwald  * @section Track throughput
1983b5c872aSMatthias Ringwald  * @text We calculate the throughput by setting a start time and measuring the amount of
1993b5c872aSMatthias Ringwald  * data sent. After a configurable REPORT_INTERVAL_MS, we print the throughput in kB/s
2003b5c872aSMatthias Ringwald  * and reset the counter and start time.
2013b5c872aSMatthias Ringwald  */
2023b5c872aSMatthias Ringwald 
2033b5c872aSMatthias Ringwald /* LISTING_START(tracking): Tracking throughput */
2043b5c872aSMatthias Ringwald 
test_reset(le_streamer_connection_t * context)2053b5c872aSMatthias Ringwald static void test_reset(le_streamer_connection_t * context){
2063b5c872aSMatthias Ringwald     context->test_data_start = btstack_run_loop_get_time_ms();
2073b5c872aSMatthias Ringwald     context->test_data_sent = 0;
2083b5c872aSMatthias Ringwald }
2093b5c872aSMatthias Ringwald 
test_track_sent(le_streamer_connection_t * context,int bytes_sent)2103b5c872aSMatthias Ringwald static void test_track_sent(le_streamer_connection_t * context, int bytes_sent){
2113b5c872aSMatthias Ringwald     context->test_data_sent += bytes_sent;
2123b5c872aSMatthias Ringwald     // evaluate
2133b5c872aSMatthias Ringwald     uint32_t now = btstack_run_loop_get_time_ms();
2143b5c872aSMatthias Ringwald     uint32_t time_passed = now - context->test_data_start;
2153b5c872aSMatthias Ringwald     if (time_passed < REPORT_INTERVAL_MS) return;
2163b5c872aSMatthias Ringwald     // print speed
2173b5c872aSMatthias Ringwald     int bytes_per_second = context->test_data_sent * 1000 / time_passed;
2183b5c872aSMatthias 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);
2193b5c872aSMatthias Ringwald 
2203b5c872aSMatthias Ringwald     // restart
2213b5c872aSMatthias Ringwald     context->test_data_start = now;
2223b5c872aSMatthias Ringwald     context->test_data_sent  = 0;
2233b5c872aSMatthias Ringwald }
2243b5c872aSMatthias Ringwald /* LISTING_END(tracking): Tracking throughput */
2253b5c872aSMatthias Ringwald 
2263b5c872aSMatthias Ringwald /*
2273b5c872aSMatthias Ringwald  * @section HCI Packet Handler
2283b5c872aSMatthias Ringwald  *
2293b5c872aSMatthias Ringwald  * @text The packet handler is used track incoming connections and to stop notifications on disconnect
2303b5c872aSMatthias Ringwald  * It is also a good place to request the connection parameter update as indicated
2313b5c872aSMatthias Ringwald  * in the commented code block.
2323b5c872aSMatthias Ringwald  */
2333b5c872aSMatthias Ringwald 
2343b5c872aSMatthias Ringwald /* LISTING_START(hciPacketHandler): Packet Handler */
hci_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)2353b5c872aSMatthias Ringwald static void hci_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
2363b5c872aSMatthias Ringwald     UNUSED(channel);
2373b5c872aSMatthias Ringwald     UNUSED(size);
2383b5c872aSMatthias Ringwald 
2393b5c872aSMatthias Ringwald     uint16_t conn_interval;
2403b5c872aSMatthias Ringwald     hci_con_handle_t con_handle;
2413b5c872aSMatthias Ringwald     switch (packet_type) {
2423b5c872aSMatthias Ringwald         case HCI_EVENT_PACKET:
2433b5c872aSMatthias Ringwald             switch (hci_event_packet_get_type(packet)) {
2443b5c872aSMatthias Ringwald                 case BTSTACK_EVENT_STATE:
2453b5c872aSMatthias Ringwald                     // BTstack activated, get started
2463b5c872aSMatthias Ringwald                     if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING) {
2473b5c872aSMatthias Ringwald                         printf("To start the streaming, please run the le_streamer_client example on other device, or use some GATT Explorer, e.g. LightBlue, BLExplr.\n");
2483b5c872aSMatthias Ringwald                     }
2493b5c872aSMatthias Ringwald                     break;
2503b5c872aSMatthias Ringwald                 case HCI_EVENT_DISCONNECTION_COMPLETE:
2513b5c872aSMatthias Ringwald                     con_handle = hci_event_disconnection_complete_get_connection_handle(packet);
2523b5c872aSMatthias Ringwald                     printf("- LE Connection %04x: disconnect, reason %02x\n", con_handle, hci_event_disconnection_complete_get_reason(packet));
2533b5c872aSMatthias Ringwald                     break;
254*73a7b814SMatthias Ringwald                 case HCI_EVENT_META_GAP:
255*73a7b814SMatthias Ringwald                     // wait for connection complete
256*73a7b814SMatthias Ringwald                     switch (hci_event_gap_meta_get_subevent_code(packet)) {
257*73a7b814SMatthias Ringwald                         case GAP_SUBEVENT_LE_CONNECTION_COMPLETE:
2583b5c872aSMatthias Ringwald                             // print connection parameters (without using float operations)
259*73a7b814SMatthias Ringwald                             con_handle    = gap_subevent_le_connection_complete_get_connection_handle(packet);
260*73a7b814SMatthias Ringwald                             conn_interval = gap_subevent_le_connection_complete_get_conn_interval(packet);
2613b5c872aSMatthias Ringwald                             printf("- LE Connection %04x: connected - connection interval %u.%02u ms, latency %u\n", con_handle, conn_interval * 125 / 100,
262*73a7b814SMatthias Ringwald                                    25 * (conn_interval & 3), gap_subevent_le_connection_complete_get_conn_latency(packet));
2633b5c872aSMatthias Ringwald                             // request min con interval 15 ms for iOS 11+
2643b5c872aSMatthias Ringwald                             // printf("- LE Connection %04x: request 15 ms connection interval\n", con_handle);
2653b5c872aSMatthias Ringwald                             // gap_request_connection_parameter_update(con_handle, 12, 12, 0, 0x0048);
2663b5c872aSMatthias Ringwald                             break;
267*73a7b814SMatthias Ringwald                         default:
268*73a7b814SMatthias Ringwald                             break;
269*73a7b814SMatthias Ringwald                     }
270*73a7b814SMatthias Ringwald                     break;
271*73a7b814SMatthias Ringwald                 case HCI_EVENT_LE_META:
272*73a7b814SMatthias Ringwald                     switch (hci_event_le_meta_get_subevent_code(packet)) {
2733b5c872aSMatthias Ringwald                         case HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE:
2743b5c872aSMatthias Ringwald                             // print connection parameters (without using float operations)
2753b5c872aSMatthias Ringwald                             con_handle    = hci_subevent_le_connection_update_complete_get_connection_handle(packet);
2763b5c872aSMatthias Ringwald                             conn_interval = hci_subevent_le_connection_update_complete_get_conn_interval(packet);
2773b5c872aSMatthias Ringwald                             printf("- LE Connection %04x: connection update - connection interval %u.%02u ms, latency %u\n", con_handle, conn_interval * 125 / 100,
2783b5c872aSMatthias Ringwald                                 25 * (conn_interval & 3), hci_subevent_le_connection_update_complete_get_conn_latency(packet));
2793b5c872aSMatthias Ringwald                             break;
2803b5c872aSMatthias Ringwald                         default:
2813b5c872aSMatthias Ringwald                             break;
2823b5c872aSMatthias Ringwald                     }
2833b5c872aSMatthias Ringwald                     break;
2843b5c872aSMatthias Ringwald                 default:
2853b5c872aSMatthias Ringwald                     break;
2863b5c872aSMatthias Ringwald             }
2873b5c872aSMatthias Ringwald     }
2883b5c872aSMatthias Ringwald }
2893b5c872aSMatthias Ringwald 
2903b5c872aSMatthias Ringwald /* LISTING_END */
2913b5c872aSMatthias Ringwald 
2923b5c872aSMatthias Ringwald /*
2933b5c872aSMatthias Ringwald  * @section ATT Packet Handler
2943b5c872aSMatthias Ringwald  *
2953b5c872aSMatthias Ringwald  * @text The packet handler is used to track the ATT MTU Exchange and trigger ATT send
2963b5c872aSMatthias Ringwald  */
2973b5c872aSMatthias Ringwald 
2983b5c872aSMatthias Ringwald /* LISTING_START(attPacketHandler): Packet Handler */
att_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)2993b5c872aSMatthias Ringwald static void att_packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
3003b5c872aSMatthias Ringwald     UNUSED(channel);
3013b5c872aSMatthias Ringwald     UNUSED(size);
3023b5c872aSMatthias Ringwald 
3033b5c872aSMatthias Ringwald     int mtu;
3043b5c872aSMatthias Ringwald     le_streamer_connection_t * context;
3053b5c872aSMatthias Ringwald     switch (packet_type) {
3063b5c872aSMatthias Ringwald         case HCI_EVENT_PACKET:
3073b5c872aSMatthias Ringwald             switch (hci_event_packet_get_type(packet)) {
3083b5c872aSMatthias Ringwald                 case ATT_EVENT_CONNECTED:
3093b5c872aSMatthias Ringwald                     // setup new
3103b5c872aSMatthias Ringwald                     context = connection_for_conn_handle(HCI_CON_HANDLE_INVALID);
3113b5c872aSMatthias Ringwald                     if (!context) break;
3123b5c872aSMatthias Ringwald                     context->counter = 'A';
3133b5c872aSMatthias Ringwald                     context->connection_handle = att_event_connected_get_handle(packet);
3143b5c872aSMatthias Ringwald                     context->test_data_len = btstack_min(att_server_get_mtu(context->connection_handle) - 3, sizeof(context->test_data));
3153b5c872aSMatthias Ringwald                     printf("%c: ATT connected, handle %04x, test data len %u\n", context->name, context->connection_handle, context->test_data_len);
3163b5c872aSMatthias Ringwald                     break;
3173b5c872aSMatthias Ringwald                 case ATT_EVENT_MTU_EXCHANGE_COMPLETE:
3183b5c872aSMatthias Ringwald                     mtu = att_event_mtu_exchange_complete_get_MTU(packet) - 3;
3193b5c872aSMatthias Ringwald                     context = connection_for_conn_handle(att_event_mtu_exchange_complete_get_handle(packet));
3203b5c872aSMatthias Ringwald                     if (!context) break;
3213b5c872aSMatthias Ringwald                     context->test_data_len = btstack_min(mtu - 3, sizeof(context->test_data));
3223b5c872aSMatthias Ringwald                     printf("%c: ATT MTU = %u => use test data of len %u\n", context->name, mtu, context->test_data_len);
3233b5c872aSMatthias Ringwald                     break;
3243b5c872aSMatthias Ringwald                 case ATT_EVENT_CAN_SEND_NOW:
3253b5c872aSMatthias Ringwald                     streamer();
3263b5c872aSMatthias Ringwald                     break;
3273b5c872aSMatthias Ringwald                 case ATT_EVENT_DISCONNECTED:
3283b5c872aSMatthias Ringwald                     context = connection_for_conn_handle(att_event_disconnected_get_handle(packet));
3293b5c872aSMatthias Ringwald                     if (!context) break;
3303b5c872aSMatthias Ringwald                     // free connection
3313b5c872aSMatthias Ringwald                     printf("%c: ATT disconnected, handle %04x\n", context->name, context->connection_handle);
3323b5c872aSMatthias Ringwald                     context->le_notification_enabled = 0;
3333b5c872aSMatthias Ringwald                     context->connection_handle = HCI_CON_HANDLE_INVALID;
3343b5c872aSMatthias Ringwald                     break;
3353b5c872aSMatthias Ringwald                 default:
3363b5c872aSMatthias Ringwald                     break;
3373b5c872aSMatthias Ringwald             }
3383b5c872aSMatthias Ringwald             break;
3393b5c872aSMatthias Ringwald         default:
3403b5c872aSMatthias Ringwald             break;
3413b5c872aSMatthias Ringwald     }
3423b5c872aSMatthias Ringwald }
3433b5c872aSMatthias Ringwald /* LISTING_END */
3443b5c872aSMatthias Ringwald 
3453b5c872aSMatthias Ringwald /*
3463b5c872aSMatthias Ringwald  * @section Streamer
3473b5c872aSMatthias Ringwald  *
3483b5c872aSMatthias Ringwald  * @text The streamer function checks if notifications are enabled and if a notification can be sent now.
3493b5c872aSMatthias Ringwald  * It creates some test data - a single letter that gets increased every time - and tracks the data sent.
3503b5c872aSMatthias Ringwald  */
3513b5c872aSMatthias Ringwald 
3523b5c872aSMatthias Ringwald  /* LISTING_START(streamer): Streaming code */
streamer(void)3533b5c872aSMatthias Ringwald static void streamer(void){
3543b5c872aSMatthias Ringwald 
3553b5c872aSMatthias Ringwald     // find next active streaming connection
3563b5c872aSMatthias Ringwald     int old_connection_index = connection_index;
3573b5c872aSMatthias Ringwald     while (1){
3583b5c872aSMatthias Ringwald         // active found?
3593b5c872aSMatthias Ringwald         if ((le_streamer_connections[connection_index].connection_handle != HCI_CON_HANDLE_INVALID) &&
3603b5c872aSMatthias Ringwald             (le_streamer_connections[connection_index].le_notification_enabled)) break;
3613b5c872aSMatthias Ringwald 
3623b5c872aSMatthias Ringwald         // check next
3633b5c872aSMatthias Ringwald         next_connection_index();
3643b5c872aSMatthias Ringwald 
3653b5c872aSMatthias Ringwald         // none found
3663b5c872aSMatthias Ringwald         if (connection_index == old_connection_index) return;
3673b5c872aSMatthias Ringwald     }
3683b5c872aSMatthias Ringwald 
3693b5c872aSMatthias Ringwald     le_streamer_connection_t * context = &le_streamer_connections[connection_index];
3703b5c872aSMatthias Ringwald 
3713b5c872aSMatthias Ringwald     // create test data
3723b5c872aSMatthias Ringwald     context->counter++;
3733b5c872aSMatthias Ringwald     if (context->counter > 'Z') context->counter = 'A';
3743b5c872aSMatthias Ringwald     memset(context->test_data, context->counter, context->test_data_len);
3753b5c872aSMatthias Ringwald 
3763b5c872aSMatthias Ringwald     // send
3773b5c872aSMatthias Ringwald     att_server_notify(context->connection_handle, context->value_handle, (uint8_t*) context->test_data, context->test_data_len);
3783b5c872aSMatthias Ringwald 
3793b5c872aSMatthias Ringwald     // track
3803b5c872aSMatthias Ringwald     test_track_sent(context, context->test_data_len);
3813b5c872aSMatthias Ringwald 
3823b5c872aSMatthias Ringwald     // request next send event
3833b5c872aSMatthias Ringwald     att_server_request_can_send_now_event(context->connection_handle);
3843b5c872aSMatthias Ringwald 
3853b5c872aSMatthias Ringwald     // check next
3863b5c872aSMatthias Ringwald     next_connection_index();
3873b5c872aSMatthias Ringwald }
3883b5c872aSMatthias Ringwald /* LISTING_END */
3893b5c872aSMatthias Ringwald 
3903b5c872aSMatthias Ringwald /*
3913b5c872aSMatthias Ringwald  * @section ATT Write
3923b5c872aSMatthias Ringwald  *
3933b5c872aSMatthias Ringwald  * @text The only valid ATT write in this example is to the Client Characteristic Configuration, which configures notification
3943b5c872aSMatthias Ringwald  * and indication. If the ATT handle matches the client configuration handle, the new configuration value is stored.
3953b5c872aSMatthias Ringwald  * If notifications get enabled, an ATT_EVENT_CAN_SEND_NOW is requested. See Listing attWrite.
3963b5c872aSMatthias Ringwald  */
3973b5c872aSMatthias Ringwald 
3983b5c872aSMatthias Ringwald /* LISTING_START(attWrite): ATT Write */
att_write_callback(hci_con_handle_t con_handle,uint16_t att_handle,uint16_t transaction_mode,uint16_t offset,uint8_t * buffer,uint16_t buffer_size)3993b5c872aSMatthias Ringwald static int att_write_callback(hci_con_handle_t con_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size){
4003b5c872aSMatthias Ringwald     UNUSED(offset);
4013b5c872aSMatthias Ringwald 
4023b5c872aSMatthias Ringwald     // printf("att_write_callback att_handle %04x, transaction mode %u\n", att_handle, transaction_mode);
4033b5c872aSMatthias Ringwald     if (transaction_mode != ATT_TRANSACTION_MODE_NONE) return 0;
4043b5c872aSMatthias Ringwald     le_streamer_connection_t * context = connection_for_conn_handle(con_handle);
4053b5c872aSMatthias Ringwald     switch(att_handle){
4063b5c872aSMatthias Ringwald         case ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_CLIENT_CONFIGURATION_HANDLE:
4073b5c872aSMatthias Ringwald         case ATT_CHARACTERISTIC_0000FF12_0000_1000_8000_00805F9B34FB_01_CLIENT_CONFIGURATION_HANDLE:
4083b5c872aSMatthias Ringwald             context->le_notification_enabled = little_endian_read_16(buffer, 0) == GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION;
4093b5c872aSMatthias Ringwald             printf("%c: Notifications enabled %u\n", context->name, context->le_notification_enabled);
4103b5c872aSMatthias Ringwald             if (context->le_notification_enabled){
4113b5c872aSMatthias Ringwald                 switch (att_handle){
4123b5c872aSMatthias Ringwald                     case ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_CLIENT_CONFIGURATION_HANDLE:
4133b5c872aSMatthias Ringwald                         context->value_handle = ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE;
4143b5c872aSMatthias Ringwald                         break;
4153b5c872aSMatthias Ringwald                     case ATT_CHARACTERISTIC_0000FF12_0000_1000_8000_00805F9B34FB_01_CLIENT_CONFIGURATION_HANDLE:
4163b5c872aSMatthias Ringwald                         context->value_handle = ATT_CHARACTERISTIC_0000FF12_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE;
4173b5c872aSMatthias Ringwald                         break;
4183b5c872aSMatthias Ringwald                     default:
4193b5c872aSMatthias Ringwald                         break;
4203b5c872aSMatthias Ringwald                 }
4213b5c872aSMatthias Ringwald                 att_server_request_can_send_now_event(context->connection_handle);
4223b5c872aSMatthias Ringwald             }
4233b5c872aSMatthias Ringwald             test_reset(context);
4243b5c872aSMatthias Ringwald             break;
4253b5c872aSMatthias Ringwald         case ATT_CHARACTERISTIC_0000FF11_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE:
4263b5c872aSMatthias Ringwald         case ATT_CHARACTERISTIC_0000FF12_0000_1000_8000_00805F9B34FB_01_VALUE_HANDLE:
4273b5c872aSMatthias Ringwald             test_track_sent(context, buffer_size);
4283b5c872aSMatthias Ringwald             break;
4293b5c872aSMatthias Ringwald         default:
4303b5c872aSMatthias Ringwald             printf("Write to 0x%04x, len %u\n", att_handle, buffer_size);
4313b5c872aSMatthias Ringwald     }
4323b5c872aSMatthias Ringwald     return 0;
4333b5c872aSMatthias Ringwald }
4343b5c872aSMatthias Ringwald /* LISTING_END */
4353b5c872aSMatthias Ringwald 
4363b5c872aSMatthias Ringwald int btstack_main(void);
btstack_main(void)4373b5c872aSMatthias Ringwald int btstack_main(void)
4383b5c872aSMatthias Ringwald {
4393b5c872aSMatthias Ringwald     le_streamer_setup();
4403b5c872aSMatthias Ringwald 
4413b5c872aSMatthias Ringwald     // turn on!
4423b5c872aSMatthias Ringwald 	hci_power_control(HCI_POWER_ON);
4433b5c872aSMatthias Ringwald 
4443b5c872aSMatthias Ringwald     return 0;
4453b5c872aSMatthias Ringwald }
4463b5c872aSMatthias Ringwald /* EXAMPLE_END */
447