1*cee62800SMatthias Ringwald /* 2*cee62800SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 3*cee62800SMatthias Ringwald * 4*cee62800SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5*cee62800SMatthias Ringwald * modification, are permitted provided that the following conditions 6*cee62800SMatthias Ringwald * are met: 7*cee62800SMatthias Ringwald * 8*cee62800SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9*cee62800SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10*cee62800SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*cee62800SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12*cee62800SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13*cee62800SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14*cee62800SMatthias Ringwald * contributors may be used to endorse or promote products derived 15*cee62800SMatthias Ringwald * from this software without specific prior written permission. 16*cee62800SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17*cee62800SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18*cee62800SMatthias Ringwald * monetary gain. 19*cee62800SMatthias Ringwald * 20*cee62800SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21*cee62800SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*cee62800SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23*cee62800SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24*cee62800SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25*cee62800SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26*cee62800SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27*cee62800SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28*cee62800SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29*cee62800SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30*cee62800SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*cee62800SMatthias Ringwald * SUCH DAMAGE. 32*cee62800SMatthias Ringwald * 33*cee62800SMatthias Ringwald * Please inquire about commercial licensing options at 34*cee62800SMatthias Ringwald * [email protected] 35*cee62800SMatthias Ringwald * 36*cee62800SMatthias Ringwald */ 37*cee62800SMatthias Ringwald 38*cee62800SMatthias Ringwald // ***************************************************************************** 39*cee62800SMatthias Ringwald /* EXAMPLE_START(spp_streamer_client): Client for SPP Streamer 40*cee62800SMatthias Ringwald * 41*cee62800SMatthias Ringwald * @text The SPP Streamer Clients connects to SPP Streamer and tracks the 42*cee62800SMatthias Ringwald * amount of received data 43*cee62800SMatthias Ringwald */ 44*cee62800SMatthias Ringwald // ***************************************************************************** 45*cee62800SMatthias Ringwald 46*cee62800SMatthias Ringwald #include <stdint.h> 47*cee62800SMatthias Ringwald #include <stdio.h> 48*cee62800SMatthias Ringwald #include <stdlib.h> 49*cee62800SMatthias Ringwald #include <string.h> 50*cee62800SMatthias Ringwald #include <inttypes.h> 51*cee62800SMatthias Ringwald 52*cee62800SMatthias Ringwald #include "btstack.h" 53*cee62800SMatthias Ringwald 54*cee62800SMatthias Ringwald #define RFCOMM_SERVER_CHANNEL 1 55*cee62800SMatthias Ringwald 56*cee62800SMatthias Ringwald #define TEST_COD 0x1234 57*cee62800SMatthias Ringwald 58*cee62800SMatthias Ringwald typedef enum { 59*cee62800SMatthias Ringwald // SPP 60*cee62800SMatthias Ringwald W4_PEER_COD, 61*cee62800SMatthias Ringwald W4_SCAN_COMPLETE, 62*cee62800SMatthias Ringwald W4_SDP_RESULT, 63*cee62800SMatthias Ringwald W4_SDP_COMPLETE, 64*cee62800SMatthias Ringwald W4_RFCOMM_CHANNEL, 65*cee62800SMatthias Ringwald SENDING, 66*cee62800SMatthias Ringwald DONE 67*cee62800SMatthias Ringwald } state_t; 68*cee62800SMatthias Ringwald 69*cee62800SMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration; 70*cee62800SMatthias Ringwald 71*cee62800SMatthias Ringwald static bd_addr_t peer_addr; 72*cee62800SMatthias Ringwald static state_t state;; 73*cee62800SMatthias Ringwald 74*cee62800SMatthias Ringwald // SPP 75*cee62800SMatthias Ringwald static uint16_t rfcomm_mtu; 76*cee62800SMatthias Ringwald static uint16_t rfcomm_cid = 0; 77*cee62800SMatthias Ringwald // static uint32_t data_to_send = DATA_VOLUME; 78*cee62800SMatthias Ringwald 79*cee62800SMatthias Ringwald 80*cee62800SMatthias Ringwald /** 81*cee62800SMatthias Ringwald * Find remote peer by COD 82*cee62800SMatthias Ringwald */ 83*cee62800SMatthias Ringwald #define INQUIRY_INTERVAL 5 84*cee62800SMatthias Ringwald static void start_scan(void){ 85*cee62800SMatthias Ringwald printf("Starting inquiry scan..\n"); 86*cee62800SMatthias Ringwald hci_send_cmd(&hci_inquiry, HCI_INQUIRY_LAP, INQUIRY_INTERVAL, 0); 87*cee62800SMatthias Ringwald state = W4_PEER_COD; 88*cee62800SMatthias Ringwald } 89*cee62800SMatthias Ringwald static void stop_scan(void){ 90*cee62800SMatthias Ringwald printf("Stopping inquiry scan..\n"); 91*cee62800SMatthias Ringwald hci_send_cmd(&hci_inquiry_cancel); 92*cee62800SMatthias Ringwald state = W4_SCAN_COMPLETE; 93*cee62800SMatthias Ringwald } 94*cee62800SMatthias Ringwald /* 95*cee62800SMatthias Ringwald * @section Track throughput 96*cee62800SMatthias Ringwald * @text We calculate the throughput by setting a start time and measuring the amount of 97*cee62800SMatthias Ringwald * data sent. After a configurable REPORT_INTERVAL_MS, we print the throughput in kB/s 98*cee62800SMatthias Ringwald * and reset the counter and start time. 99*cee62800SMatthias Ringwald */ 100*cee62800SMatthias Ringwald 101*cee62800SMatthias Ringwald /* LISTING_START(tracking): Tracking throughput */ 102*cee62800SMatthias Ringwald #define REPORT_INTERVAL_MS 3000 103*cee62800SMatthias Ringwald static uint32_t test_data_transferred; 104*cee62800SMatthias Ringwald static uint32_t test_data_start; 105*cee62800SMatthias Ringwald 106*cee62800SMatthias Ringwald static void test_reset(void){ 107*cee62800SMatthias Ringwald test_data_start = btstack_run_loop_get_time_ms(); 108*cee62800SMatthias Ringwald test_data_transferred = 0; 109*cee62800SMatthias Ringwald } 110*cee62800SMatthias Ringwald 111*cee62800SMatthias Ringwald static void test_track_transferred(int bytes_sent){ 112*cee62800SMatthias Ringwald test_data_transferred += bytes_sent; 113*cee62800SMatthias Ringwald // evaluate 114*cee62800SMatthias Ringwald uint32_t now = btstack_run_loop_get_time_ms(); 115*cee62800SMatthias Ringwald uint32_t time_passed = now - test_data_start; 116*cee62800SMatthias Ringwald if (time_passed < REPORT_INTERVAL_MS) return; 117*cee62800SMatthias Ringwald // print speed 118*cee62800SMatthias Ringwald int bytes_per_second = test_data_transferred * 1000 / time_passed; 119*cee62800SMatthias Ringwald printf("%u bytes -> %u.%03u kB/s\n", (int) test_data_transferred, (int) bytes_per_second / 1000, bytes_per_second % 1000); 120*cee62800SMatthias Ringwald 121*cee62800SMatthias Ringwald // restart 122*cee62800SMatthias Ringwald test_data_start = now; 123*cee62800SMatthias Ringwald test_data_transferred = 0; 124*cee62800SMatthias Ringwald } 125*cee62800SMatthias Ringwald /* LISTING_END(tracking): Tracking throughput */ 126*cee62800SMatthias Ringwald 127*cee62800SMatthias Ringwald /* 128*cee62800SMatthias Ringwald * @section Packet Handler 129*cee62800SMatthias Ringwald * 130*cee62800SMatthias Ringwald * @text The packet handler of the combined example is just the combination of the individual packet handlers. 131*cee62800SMatthias Ringwald */ 132*cee62800SMatthias Ringwald 133*cee62800SMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 134*cee62800SMatthias Ringwald UNUSED(channel); 135*cee62800SMatthias Ringwald 136*cee62800SMatthias Ringwald bd_addr_t event_addr; 137*cee62800SMatthias Ringwald uint8_t rfcomm_channel_nr; 138*cee62800SMatthias Ringwald uint32_t class_of_device; 139*cee62800SMatthias Ringwald 140*cee62800SMatthias Ringwald switch (packet_type) { 141*cee62800SMatthias Ringwald case HCI_EVENT_PACKET: 142*cee62800SMatthias Ringwald switch (hci_event_packet_get_type(packet)) { 143*cee62800SMatthias Ringwald 144*cee62800SMatthias Ringwald case HCI_EVENT_PIN_CODE_REQUEST: 145*cee62800SMatthias Ringwald // inform about pin code request 146*cee62800SMatthias Ringwald printf("Pin code request - using '0000'\n"); 147*cee62800SMatthias Ringwald hci_event_pin_code_request_get_bd_addr(packet, event_addr); 148*cee62800SMatthias Ringwald gap_pin_code_response(event_addr, "0000"); 149*cee62800SMatthias Ringwald break; 150*cee62800SMatthias Ringwald 151*cee62800SMatthias Ringwald case HCI_EVENT_USER_CONFIRMATION_REQUEST: 152*cee62800SMatthias Ringwald // inform about user confirmation request 153*cee62800SMatthias Ringwald printf("SSP User Confirmation Request with numeric value '%06"PRIu32"'\n", little_endian_read_32(packet, 8)); 154*cee62800SMatthias Ringwald printf("SSP User Confirmation Auto accept\n"); 155*cee62800SMatthias Ringwald break; 156*cee62800SMatthias Ringwald 157*cee62800SMatthias Ringwald case RFCOMM_EVENT_INCOMING_CONNECTION: 158*cee62800SMatthias Ringwald // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16) 159*cee62800SMatthias Ringwald rfcomm_event_incoming_connection_get_bd_addr(packet, event_addr); 160*cee62800SMatthias Ringwald rfcomm_channel_nr = rfcomm_event_incoming_connection_get_server_channel(packet); 161*cee62800SMatthias Ringwald rfcomm_cid = rfcomm_event_incoming_connection_get_rfcomm_cid(packet); 162*cee62800SMatthias Ringwald printf("RFCOMM channel %u requested for %s\n", rfcomm_channel_nr, bd_addr_to_str(event_addr)); 163*cee62800SMatthias Ringwald rfcomm_accept_connection(rfcomm_cid); 164*cee62800SMatthias Ringwald break; 165*cee62800SMatthias Ringwald 166*cee62800SMatthias Ringwald case RFCOMM_EVENT_CHANNEL_OPENED: 167*cee62800SMatthias Ringwald // data: event(8), len(8), status (8), address (48), server channel(8), rfcomm_cid(16), max frame size(16) 168*cee62800SMatthias Ringwald if (rfcomm_event_channel_opened_get_status(packet)) { 169*cee62800SMatthias Ringwald printf("RFCOMM channel open failed, status %u\n", rfcomm_event_channel_opened_get_status(packet)); 170*cee62800SMatthias Ringwald } else { 171*cee62800SMatthias Ringwald rfcomm_cid = rfcomm_event_channel_opened_get_rfcomm_cid(packet); 172*cee62800SMatthias Ringwald rfcomm_mtu = rfcomm_event_channel_opened_get_max_frame_size(packet); 173*cee62800SMatthias Ringwald printf("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n", rfcomm_cid, rfcomm_mtu); 174*cee62800SMatthias Ringwald test_reset(); 175*cee62800SMatthias Ringwald // disable page and inquiry scan 176*cee62800SMatthias Ringwald gap_connectable_control(0); 177*cee62800SMatthias Ringwald } 178*cee62800SMatthias Ringwald break; 179*cee62800SMatthias Ringwald 180*cee62800SMatthias Ringwald case RFCOMM_EVENT_CHANNEL_CLOSED: 181*cee62800SMatthias Ringwald printf("RFCOMM channel closed\n"); 182*cee62800SMatthias Ringwald rfcomm_cid = 0; // re-enable page scan 183*cee62800SMatthias Ringwald gap_connectable_control(1); 184*cee62800SMatthias Ringwald break; 185*cee62800SMatthias Ringwald 186*cee62800SMatthias Ringwald case BTSTACK_EVENT_STATE: 187*cee62800SMatthias Ringwald if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return; 188*cee62800SMatthias Ringwald start_scan(); 189*cee62800SMatthias Ringwald break; 190*cee62800SMatthias Ringwald 191*cee62800SMatthias Ringwald case GAP_EVENT_INQUIRY_RESULT: 192*cee62800SMatthias Ringwald class_of_device = gap_event_inquiry_result_get_class_of_device(packet); 193*cee62800SMatthias Ringwald gap_event_inquiry_result_get_bd_addr(packet, event_addr); 194*cee62800SMatthias Ringwald if (class_of_device == TEST_COD){ 195*cee62800SMatthias Ringwald memcpy(peer_addr, event_addr, 6); 196*cee62800SMatthias Ringwald printf("Peer found: %s\n", bd_addr_to_str(peer_addr)); 197*cee62800SMatthias Ringwald stop_scan(); 198*cee62800SMatthias Ringwald 199*cee62800SMatthias Ringwald printf("Start to connect\n"); 200*cee62800SMatthias Ringwald state = W4_RFCOMM_CHANNEL; 201*cee62800SMatthias Ringwald rfcomm_create_channel(packet_handler, peer_addr, RFCOMM_SERVER_CHANNEL, NULL); 202*cee62800SMatthias Ringwald } else { 203*cee62800SMatthias Ringwald printf("Device found: %s with COD: 0x%06x\n", bd_addr_to_str(event_addr), (int) class_of_device); 204*cee62800SMatthias Ringwald } 205*cee62800SMatthias Ringwald break; 206*cee62800SMatthias Ringwald 207*cee62800SMatthias Ringwald case HCI_EVENT_INQUIRY_COMPLETE: 208*cee62800SMatthias Ringwald printf("Inquiry complete\n"); 209*cee62800SMatthias Ringwald printf("Peer not found, starting scan again\n"); 210*cee62800SMatthias Ringwald start_scan(); 211*cee62800SMatthias Ringwald break; 212*cee62800SMatthias Ringwald 213*cee62800SMatthias Ringwald default: 214*cee62800SMatthias Ringwald break; 215*cee62800SMatthias Ringwald } 216*cee62800SMatthias Ringwald break; 217*cee62800SMatthias Ringwald 218*cee62800SMatthias Ringwald case RFCOMM_DATA_PACKET: 219*cee62800SMatthias Ringwald test_track_transferred(size); 220*cee62800SMatthias Ringwald #if 0 221*cee62800SMatthias Ringwald printf("RCV: '"); 222*cee62800SMatthias Ringwald for (i=0;i<size;i++){ 223*cee62800SMatthias Ringwald putchar(packet[i]); 224*cee62800SMatthias Ringwald } 225*cee62800SMatthias Ringwald printf("'\n"); 226*cee62800SMatthias Ringwald #endif 227*cee62800SMatthias Ringwald break; 228*cee62800SMatthias Ringwald 229*cee62800SMatthias Ringwald default: 230*cee62800SMatthias Ringwald break; 231*cee62800SMatthias Ringwald } 232*cee62800SMatthias Ringwald } 233*cee62800SMatthias Ringwald 234*cee62800SMatthias Ringwald /* 235*cee62800SMatthias Ringwald * @section Main Application Setup 236*cee62800SMatthias Ringwald * 237*cee62800SMatthias Ringwald * @text As with the packet and the heartbeat handlers, the combined app setup contains the code from the individual example setups. 238*cee62800SMatthias Ringwald */ 239*cee62800SMatthias Ringwald 240*cee62800SMatthias Ringwald 241*cee62800SMatthias Ringwald /* LISTING_START(MainConfiguration): Init L2CAP RFCOMM SDO SM ATT Server and start heartbeat timer */ 242*cee62800SMatthias Ringwald int btstack_main(int argc, const char * argv[]); 243*cee62800SMatthias Ringwald int btstack_main(int argc, const char * argv[]){ 244*cee62800SMatthias Ringwald UNUSED(argc); 245*cee62800SMatthias Ringwald (void)argv; 246*cee62800SMatthias Ringwald 247*cee62800SMatthias Ringwald // register for HCI events 248*cee62800SMatthias Ringwald hci_event_callback_registration.callback = &packet_handler; 249*cee62800SMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration); 250*cee62800SMatthias Ringwald 251*cee62800SMatthias Ringwald l2cap_init(); 252*cee62800SMatthias Ringwald 253*cee62800SMatthias Ringwald rfcomm_init(); 254*cee62800SMatthias Ringwald rfcomm_register_service(packet_handler, RFCOMM_SERVER_CHANNEL, 0xffff); 255*cee62800SMatthias Ringwald 256*cee62800SMatthias Ringwald // init SDP 257*cee62800SMatthias Ringwald gap_ssp_set_io_capability(SSP_IO_CAPABILITY_DISPLAY_YES_NO); 258*cee62800SMatthias Ringwald 259*cee62800SMatthias Ringwald // turn on! 260*cee62800SMatthias Ringwald hci_power_control(HCI_POWER_ON); 261*cee62800SMatthias Ringwald 262*cee62800SMatthias Ringwald return 0; 263*cee62800SMatthias Ringwald } 264*cee62800SMatthias Ringwald /* LISTING_END */ 265*cee62800SMatthias Ringwald /* EXAMPLE_END */ 266