1 /* 2 * Copyright (C) 2014 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define BTSTACK_FILE__ "pbap_client_demo.c" 39 40 // ***************************************************************************** 41 /* EXAMPLE_START(pbap_client_demo): PBAP Client - Get Contacts from Phonebook Server 42 * 43 * @text Note: The Bluetooth address of the remote Phonbook server is hardcoded. 44 * Change it before running example, then use the UI to connect to it, to set and 45 * query contacts. 46 */ 47 // ***************************************************************************** 48 49 50 #include "btstack_config.h" 51 52 #include <stdint.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 57 #include "btstack.h" 58 59 #ifdef HAVE_BTSTACK_STDIN 60 #include "btstack_stdin.h" 61 #endif 62 63 static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 64 65 static bd_addr_t remote_addr; 66 // MBP2016 "F4-0F-24-3B-1B-E1" 67 // Nexus 7 "30-85-A9-54-2E-78" 68 // iPhone SE "BC:EC:5D:E6:15:03" 69 // PTS "001BDC080AA5" 70 static char * remote_addr_string = "DC:52:85:B4:AD:2B "; 71 72 static char * phone_number = "911"; 73 74 static const char * pb_name = "pb"; 75 static const char * fav_name = "fav"; 76 static const char * ich_name = "ich"; 77 static const char * och_name = "och"; 78 static const char * mch_name = "mch"; 79 static const char * cch_name = "cch"; 80 static const char * spd_name = "spd"; 81 82 static const char * phonebook_name; 83 static char phonebook_folder[30]; 84 static char phonebook_path[30]; 85 static enum { 86 PBAP_PATH_ROOT, 87 PBAP_PATH_FOLDER, 88 PBAP_PATH_PHONEBOOK 89 } pbap_client_demo_path_type; 90 91 static btstack_packet_callback_registration_t hci_event_callback_registration; 92 static uint16_t pbap_cid; 93 94 static int sim1_selected; 95 96 static void refresh_phonebook_folder_and_path(void){ 97 snprintf(phonebook_path, sizeof(phonebook_path), "%s%s.vcf", sim1_selected ? "SIM1/telecom/" : "telecom/", phonebook_name); 98 snprintf(phonebook_folder, sizeof(phonebook_folder), "%s%s", sim1_selected ? "SIM1/telecom/" : "telecom/", phonebook_name); 99 printf("[-] Phonebook folder '%s'\n", phonebook_folder); 100 printf("[-] Phonebook path '%s'\n", phonebook_path); 101 } 102 103 static void select_phonebook(const char * phonebook){ 104 phonebook_name = phonebook; 105 printf("[-] Phonebook name '%s'\n", phonebook_name); 106 refresh_phonebook_folder_and_path(); 107 } 108 109 #ifdef HAVE_BTSTACK_STDIN 110 111 // Testing User Interface 112 static void show_usage(void){ 113 bd_addr_t iut_address; 114 gap_local_bd_addr(iut_address); 115 116 printf("\n--- Bluetooth PBAP Client (HF) Test Console %s ---\n", bd_addr_to_str(iut_address)); 117 printf("Phonebook: '%s'\n", phonebook_folder); 118 printf("Phonebook path '%s'\n", phonebook_path); 119 printf("\n"); 120 printf("a - establish PBAP connection to %s\n", bd_addr_to_str(remote_addr)); 121 printf("A - disconnect PBAP connection to %s\n", bd_addr_to_str(remote_addr)); 122 printf("b - select SIM1\n"); 123 printf("r - set path to '/telecom'\n"); 124 printf("R - set path to '/SIM1/telecom'\n"); 125 printf("u - set path to '%s'\n", phonebook_folder); 126 printf("v - set vCardSelector to N and TEL\n"); 127 printf("V - set vCardSelectorOperator to AND\n"); 128 129 printf("e - select phonebook '%s'\n", pb_name); 130 printf("f - select phonebook '%s'\n", fav_name); 131 printf("i - select phonebook '%s'\n", ich_name); 132 printf("o - select phonebook '%s'\n", och_name); 133 printf("m - select phonebook '%s'\n", mch_name); 134 printf("c - select phonebook '%s'\n", cch_name); 135 printf("s - select phonebook '%s'\n", spd_name); 136 137 printf("d - get size of '%s'\n", phonebook_path); 138 printf("g - pull phonebook '%s'\n", phonebook_path); 139 printf("h - pull vCard listing '%s'\n", phonebook_name); 140 printf("l - get owner vCard 0.vcf\n"); 141 printf("j - Lookup contact with number '%s'\n", phone_number); 142 printf("t - disconnect HCI\n"); 143 printf("p - authenticate using password '0000'\n"); 144 printf("r - set path to 'telecom'\n"); 145 printf("x - abort operation\n"); 146 printf("\n"); 147 } 148 149 static void stdin_process(char c){ 150 switch (c){ 151 case '\n': 152 case '\r': 153 break; 154 case 'a': 155 printf("[+] Connecting to %s...\n", bd_addr_to_str(remote_addr)); 156 pbap_connect(&packet_handler, remote_addr, &pbap_cid); 157 break; 158 case 'A': 159 printf("[+] Disconnect PBAP from %s...\n", bd_addr_to_str(remote_addr)); 160 pbap_disconnect(pbap_cid); 161 break; 162 case 'b': 163 printf("[+] SIM1 selected'\n"); 164 sim1_selected = 1; 165 refresh_phonebook_folder_and_path(); 166 break; 167 168 case 'd': 169 printf("[+] Get size of phonebook '%s'\n", phonebook_path); 170 pbap_get_phonebook_size(pbap_cid, phonebook_path); 171 break; 172 case 'g': 173 printf("[+] Pull phonebook '%s'\n", phonebook_path); 174 pbap_pull_phonebook(pbap_cid, phonebook_path); 175 break; 176 case 'h': 177 if (pbap_client_demo_path_type != PBAP_PATH_FOLDER){ 178 printf("[!] Pull vCard list requires to set phonebook folder, e.g. using 'r' command\n"); 179 break; 180 } 181 printf("[+] Pull vCard list for '%s'\n", phonebook_name); 182 pbap_pull_vcard_listing(pbap_cid, phonebook_name); 183 break; 184 case 'j': 185 if (pbap_client_demo_path_type != PBAP_PATH_PHONEBOOK){ 186 printf("[!] Pull vCard list requires to set phonenbook folder, e.g. using 'u' command\n"); 187 break; 188 } 189 printf("[+] Lookup name for number '%s'\n", phone_number); 190 pbap_lookup_by_number(pbap_cid, phone_number); 191 break; 192 case 'l': 193 if (pbap_client_demo_path_type != PBAP_PATH_PHONEBOOK){ 194 printf("[!] Pull vCard entry requires to set phonenbook folder, e.g. using 'u' command\n"); 195 break; 196 } 197 printf("[+] Pull vCard '0.vcf'\n"); 198 pbap_pull_vcard_entry(pbap_cid, "0.vcf"); 199 break; 200 case 'c': 201 printf("[+] Select phonebook '%s'\n", cch_name); 202 select_phonebook(cch_name); 203 break; 204 case 'e': 205 printf("[+] Select phonebook '%s'\n", pb_name); 206 select_phonebook(pb_name); 207 break; 208 case 'f': 209 printf("[+] Select phonebook '%s'\n", fav_name); 210 select_phonebook(fav_name); 211 break; 212 case 'i': 213 printf("[+] Select phonebook '%s'\n", ich_name); 214 select_phonebook(ich_name); 215 break; 216 case 'm': 217 printf("[+] Select phonebook '%s'\n", mch_name); 218 select_phonebook(mch_name); 219 break; 220 case 'o': 221 printf("[+] Select phonebook '%s'\n", och_name); 222 select_phonebook(och_name); 223 break; 224 case 's': 225 printf("[+] Select phonebook '%s'\n", spd_name); 226 select_phonebook(spd_name); 227 break; 228 229 case 'p': 230 pbap_authentication_password(pbap_cid, "0000"); 231 break; 232 case 'v': 233 printf("[+] Set vCardSelector 'N' and 'TEL'\n"); 234 pbap_set_vcard_selector(pbap_cid, PBAP_PROPERTY_MASK_N | PBAP_PROPERTY_MASK_TEL); 235 break; 236 case 'V': 237 printf("[+] Set vCardSelectorOperator 'AND'\n"); 238 pbap_set_vcard_selector_operator(pbap_cid, PBAP_VCARD_SELECTOR_OPERATOR_AND); 239 break; 240 case 'r': 241 printf("[+] Set path to '/telecom'\n"); 242 pbap_client_demo_path_type = PBAP_PATH_FOLDER; 243 pbap_set_phonebook(pbap_cid, "telecom"); 244 break; 245 case 'R': 246 printf("[+] Set path to '/SIM1/telecom'\n"); 247 pbap_client_demo_path_type = PBAP_PATH_FOLDER; 248 pbap_set_phonebook(pbap_cid, "SIM1/telecom"); 249 break; 250 case 'u': 251 printf("[+] Set path to '%s'\n", phonebook_folder); 252 pbap_client_demo_path_type = PBAP_PATH_PHONEBOOK; 253 pbap_set_phonebook(pbap_cid, phonebook_folder); 254 break; 255 case 'x': 256 printf("[+] Abort'\n"); 257 pbap_abort(pbap_cid); 258 break; 259 case 't': 260 pbap_disconnect(pbap_cid); 261 break; 262 default: 263 show_usage(); 264 break; 265 } 266 } 267 268 // packet handler for interactive console 269 static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 270 UNUSED(channel); 271 UNUSED(size); 272 int i; 273 uint8_t status; 274 char buffer[32]; 275 switch (packet_type){ 276 case HCI_EVENT_PACKET: 277 switch (hci_event_packet_get_type(packet)) { 278 case BTSTACK_EVENT_STATE: 279 // BTstack activated, get started 280 if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){ 281 show_usage(); 282 } 283 break; 284 case HCI_EVENT_PBAP_META: 285 switch (hci_event_pbap_meta_get_subevent_code(packet)){ 286 case PBAP_SUBEVENT_CONNECTION_OPENED: 287 status = pbap_subevent_connection_opened_get_status(packet); 288 if (status){ 289 printf("[!] Connection failed, status 0x%02x\n", status); 290 } else { 291 printf("[+] Connected\n"); 292 } 293 pbap_client_demo_path_type = PBAP_PATH_ROOT; 294 break; 295 case PBAP_SUBEVENT_CONNECTION_CLOSED: 296 printf("[+] Connection closed\n"); 297 break; 298 case PBAP_SUBEVENT_OPERATION_COMPLETED: 299 printf("[+] Operation complete, status 0x%02x\n", 300 pbap_subevent_operation_completed_get_status(packet)); 301 break; 302 case PBAP_SUBEVENT_AUTHENTICATION_REQUEST: 303 printf("[?] Authentication requested\n"); 304 break; 305 case PBAP_SUBEVENT_PHONEBOOK_SIZE: 306 status = pbap_subevent_phonebook_size_get_status(packet); 307 if (status){ 308 printf("[!] Get Phonebook size error: 0x%02x\n", status); 309 } else { 310 printf("[+] Phonebook size: %u\n", pbap_subevent_phonebook_size_get_phonebook_size(packet)); 311 } 312 break; 313 case PBAP_SUBEVENT_CARD_RESULT: 314 memcpy(buffer, pbap_subevent_card_result_get_name(packet), pbap_subevent_card_result_get_name_len(packet)); 315 buffer[pbap_subevent_card_result_get_name_len(packet)] = 0; 316 printf("[-] Name: '%s'\n", buffer); 317 memcpy(buffer, pbap_subevent_card_result_get_handle(packet), pbap_subevent_card_result_get_handle_len(packet)); 318 buffer[pbap_subevent_card_result_get_handle_len(packet)] = 0; 319 printf("[-] Handle: '%s'\n", buffer); 320 break; 321 default: 322 break; 323 } 324 break; 325 default: 326 break; 327 } 328 break; 329 case PBAP_DATA_PACKET: 330 for (i=0;i<size;i++){ 331 printf("%c", packet[i]); 332 } 333 break; 334 default: 335 break; 336 } 337 } 338 #else 339 340 // packet handler for emdded system with fixed operation sequence 341 static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 342 UNUSED(channel); 343 UNUSED(size); 344 int i; 345 switch (packet_type){ 346 case HCI_EVENT_PACKET: 347 switch (hci_event_packet_get_type(packet)) { 348 case BTSTACK_EVENT_STATE: 349 // BTstack activated, get started 350 if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){ 351 printf("[+] Connect to Phone Book Server on %s\n", bd_addr_to_str(remote_addr)); 352 pbap_connect(&packet_handler, remote_addr, &pbap_cid); 353 } 354 break; 355 case HCI_EVENT_PBAP_META: 356 switch (hci_event_pbap_meta_get_subevent_code(packet)){ 357 case PBAP_SUBEVENT_CONNECTION_OPENED: 358 printf("[+] Connected\n"); 359 printf("[+] Pull phonebook\n"); 360 pbap_pull_phonebook(pbap_cid, phonebook_path); 361 break; 362 case PBAP_SUBEVENT_CONNECTION_CLOSED: 363 printf("[+] Connection closed\n"); 364 break; 365 case PBAP_SUBEVENT_OPERATION_COMPLETED: 366 printf("[+] Operation complete\n"); 367 printf("[+] Pull Phonebook complete\n"); 368 pbap_disconnect(pbap_cid); 369 break; 370 default: 371 break; 372 } 373 break; 374 default: 375 break; 376 } 377 break; 378 case PBAP_DATA_PACKET: 379 for (i=0;i<size;i++){ 380 printf("%c", packet[i]); 381 } 382 break; 383 default: 384 break; 385 } 386 } 387 #endif 388 389 int btstack_main(int argc, const char * argv[]); 390 int btstack_main(int argc, const char * argv[]){ 391 (void)argc; 392 (void)argv; 393 394 // init L2CAP 395 l2cap_init(); 396 397 #ifdef ENABLE_BLE 398 // Initialize LE Security Manager. Needed for cross-transport key derivation 399 sm_init(); 400 #endif 401 402 // init RFCOM 403 rfcomm_init(); 404 405 // init GOEP Client 406 goep_client_init(); 407 408 // init PBAP Client 409 pbap_client_init(); 410 411 // register for HCI events 412 hci_event_callback_registration.callback = &packet_handler; 413 hci_add_event_handler(&hci_event_callback_registration); 414 415 sscanf_bd_addr(remote_addr_string, remote_addr); 416 417 select_phonebook(pb_name); 418 419 #ifdef HAVE_BTSTACK_STDIN 420 btstack_stdin_setup(stdin_process); 421 #endif 422 423 // turn on! 424 hci_power_control(HCI_POWER_ON); 425 426 return 0; 427 } 428 /* EXAMPLE_END */ 429