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 MATTHIAS 24 * RINGWALD 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__ "main.c" 39 40 // ***************************************************************************** 41 // 42 // Port for Rasperry Pi with built-in BCM chipset via H4 or H5 43 // 44 // ***************************************************************************** 45 46 #include <errno.h> 47 #include <fcntl.h> 48 #include <inttypes.h> 49 #include <signal.h> 50 #include <stdint.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <sys/stat.h> 55 #include <termios.h> 56 #include <unistd.h> 57 58 #include "btstack_config.h" 59 60 #include "btstack_debug.h" 61 #include "btstack_event.h" 62 #include "ble/le_device_db_tlv.h" 63 #include "classic/btstack_link_key_db_tlv.h" 64 #include "btstack_memory.h" 65 #include "btstack_run_loop.h" 66 #include "btstack_run_loop_posix.h" 67 #include "bluetooth_company_id.h" 68 #include "hci.h" 69 #include "hci_dump.h" 70 #include "btstack_stdin.h" 71 #include "btstack_tlv_posix.h" 72 73 #include "btstack_chipset_bcm.h" 74 #include "btstack_chipset_bcm_download_firmware.h" 75 #include "btstack_control_raspi.h" 76 77 #include "raspi_get_model.h" 78 79 int btstack_main(int argc, const char * argv[]); 80 81 typedef enum { 82 UART_INVALID, 83 UART_SOFTWARE_NO_FLOW, 84 UART_HARDWARE_NO_FLOW, 85 UART_HARDWARE_FLOW 86 } uart_type_t; 87 88 // default config, updated depending on RasperryPi UART configuration 89 static hci_transport_config_uart_t transport_config = { 90 HCI_TRANSPORT_CONFIG_UART, 91 115200, 92 0, // main baudrate 93 0, // flow control 94 NULL, 95 }; 96 97 static btstack_uart_config_t uart_config; 98 99 static int main_argc; 100 static const char ** main_argv; 101 102 static btstack_packet_callback_registration_t hci_event_callback_registration; 103 104 #define TLV_DB_PATH_PREFIX "/tmp/btstack_" 105 #define TLV_DB_PATH_POSTFIX ".tlv" 106 static char tlv_db_path[100]; 107 static const btstack_tlv_t * tlv_impl; 108 static btstack_tlv_posix_t tlv_context; 109 110 111 static int raspi_speed_to_baud(speed_t baud) 112 { 113 switch (baud) { 114 case B9600: 115 return 9600; 116 case B19200: 117 return 19200; 118 case B38400: 119 return 38400; 120 case B57600: 121 return 57600; 122 case B115200: 123 return 115200; 124 case B230400: 125 return 230400; 126 case B460800: 127 return 460800; 128 case B500000: 129 return 500000; 130 case B576000: 131 return 576000; 132 case B921600: 133 return 921600; 134 case B1000000: 135 return 1000000; 136 case B1152000: 137 return 1152000; 138 case B1500000: 139 return 1500000; 140 case B2000000: 141 return 2000000; 142 case B2500000: 143 return 2500000; 144 case B3000000: 145 return 3000000; 146 case B3500000: 147 return 3500000; 148 case B4000000: 149 return 4000000; 150 default: 151 return -1; 152 } 153 } 154 155 static void raspi_get_terminal_params( hci_transport_config_uart_t *tc ) 156 { 157 // open serial terminal and get parameters 158 int fd = open( tc->device_name, O_RDONLY ); 159 if( fd < 0 ) 160 { 161 perror( "can't open serial port" ); 162 return; 163 } 164 struct termios tios; 165 tcgetattr( fd, &tios ); 166 close( fd ); 167 168 speed_t ospeed = cfgetospeed( &tios ); 169 int baud = raspi_speed_to_baud( ospeed ); 170 printf( "current serial terminal parameter baudrate: %d, flow control: %s\n", baud, (tios.c_cflag&CRTSCTS)?"Hardware":"None" ); 171 172 // overwrites the initial baudrate only in case it was likely to be altered before 173 if( baud > 9600 ) 174 { 175 tc->baudrate_init = baud; 176 tc->flowcontrol = (tios.c_cflag & CRTSCTS)?1:0; 177 } 178 } 179 180 static void sigint_handler(int param){ 181 UNUSED(param); 182 183 printf("CTRL-C - SIGINT received, shutting down..\n"); 184 log_info("sigint_handler: shutting down"); 185 186 // reset anyway 187 btstack_stdin_reset(); 188 189 // power down 190 hci_power_control(HCI_POWER_OFF); 191 hci_close(); 192 log_info("Good bye, see you.\n"); 193 exit(0); 194 } 195 196 static int led_state = 0; 197 void hal_led_toggle(void){ 198 led_state = 1 - led_state; 199 printf("LED State %u\n", led_state); 200 } 201 202 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 203 bd_addr_t addr; 204 if (packet_type != HCI_EVENT_PACKET) return; 205 switch (hci_event_packet_get_type(packet)){ 206 case BTSTACK_EVENT_STATE: 207 if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) break; 208 gap_local_bd_addr(addr); 209 printf("BTstack up and running at %s\n", bd_addr_to_str(addr)); 210 // setup TLV 211 strcpy(tlv_db_path, TLV_DB_PATH_PREFIX); 212 strcat(tlv_db_path, bd_addr_to_str(addr)); 213 strcat(tlv_db_path, TLV_DB_PATH_POSTFIX); 214 tlv_impl = btstack_tlv_posix_init_instance(&tlv_context, tlv_db_path); 215 btstack_tlv_set_instance(tlv_impl, &tlv_context); 216 #ifdef ENABLE_CLASSIC 217 hci_set_link_key_db(btstack_link_key_db_tlv_get_instance(tlv_impl, &tlv_context)); 218 #endif 219 #ifdef ENABLE_BLE 220 le_device_db_tlv_configure(tlv_impl, &tlv_context); 221 #endif 222 break; 223 case HCI_EVENT_COMMAND_COMPLETE: 224 if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_name)){ 225 if (hci_event_command_complete_get_return_parameters(packet)[0]) break; 226 // terminate, name 248 chars 227 packet[6+248] = 0; 228 printf("Local name: %s\n", &packet[6]); 229 230 btstack_chipset_bcm_set_device_name((const char *)&packet[6]); 231 } 232 break; 233 default: 234 break; 235 } 236 } 237 238 // see https://github.com/RPi-Distro/pi-bluetooth/blob/master/usr/bin/btuart 239 static int raspi_get_bd_addr(bd_addr_t addr){ 240 241 FILE *fd = fopen( "/proc/device-tree/serial-number", "r" ); 242 if( fd == NULL ){ 243 fprintf(stderr, "can't read serial number, %s\n", strerror( errno ) ); 244 return -1; 245 } 246 fscanf( fd, "%*08x" "%*02x" "%02" SCNx8 "%02" SCNx8 "%02" SCNx8, &addr[3], &addr[4], &addr[5] ); 247 fclose( fd ); 248 249 addr[0] = 0xb8; addr[1] = 0x27; addr[2] = 0xeb; 250 addr[3] ^= 0xaa; addr[4] ^= 0xaa; addr[5] ^= 0xaa; 251 252 return 0; 253 } 254 255 // see https://github.com/RPi-Distro/pi-bluetooth/blob/master/usr/bin/btuart 256 // on UART_INVALID errno is set 257 static uart_type_t raspi_get_bluetooth_uart_type(void){ 258 259 uint8_t deviceUart0[21] = { 0 }; 260 FILE *fd = fopen( "/proc/device-tree/aliases/uart0", "r" ); 261 if( fd == NULL ) return UART_INVALID; 262 fscanf( fd, "%20s", deviceUart0 ); 263 fclose( fd ); 264 265 uint8_t deviceSerial1[21] = { 0 }; 266 fd = fopen( "/proc/device-tree/aliases/serial1", "r" ); 267 if( fd == NULL ) return UART_INVALID; 268 fscanf( fd, "%20s", deviceSerial1 ); 269 fclose( fd ); 270 271 // test if uart0 is an alias for serial1 272 if( strncmp( (const char *) deviceUart0, (const char *) deviceSerial1, 21 ) == 0 ){ 273 // HW uart 274 size_t count = 0; 275 uint8_t buf[16]; 276 fd = fopen( "/proc/device-tree/soc/gpio@7e200000/uart0_pins/brcm,pins", "r" ); 277 if( fd == NULL ) return UART_INVALID; 278 count = fread( buf, 1, 16, fd ); 279 fclose( fd ); 280 281 // contains assigned pins 282 int pins = count / 4; 283 if( pins == 4 ){ 284 return UART_HARDWARE_FLOW; 285 } else { 286 return UART_HARDWARE_NO_FLOW; 287 } 288 } else { 289 return UART_SOFTWARE_NO_FLOW; 290 } 291 } 292 293 static void phase2(int status); 294 int main(int argc, const char * argv[]){ 295 296 /// GET STARTED with BTstack /// 297 btstack_memory_init(); 298 299 // use logger: format HCI_DUMP_PACKETLOGGER, HCI_DUMP_BLUEZ or HCI_DUMP_STDOUT 300 const char * pklg_path = "/tmp/hci_dump.pklg"; 301 hci_dump_open(pklg_path, HCI_DUMP_PACKETLOGGER); 302 printf("Packet Log: %s\n", pklg_path); 303 304 // setup run loop 305 btstack_run_loop_init(btstack_run_loop_posix_get_instance()); 306 307 // pick serial port and configure uart block driver 308 transport_config.device_name = "/dev/serial1"; 309 310 // derive bd_addr from serial number 311 bd_addr_t addr = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; 312 raspi_get_bd_addr(addr); 313 314 // set UART config based on raspi Bluetooth UART type 315 int bt_reg_en_pin = -1; 316 bool power_cycle = true; 317 switch (raspi_get_bluetooth_uart_type()){ 318 case UART_INVALID: 319 fprintf(stderr, "can't verify HW uart, %s\n", strerror( errno ) ); 320 return -1; 321 case UART_SOFTWARE_NO_FLOW: 322 // ?? 323 bt_reg_en_pin = 128; 324 transport_config.baudrate_main = 460800; 325 transport_config.flowcontrol = 0; 326 break; 327 case UART_HARDWARE_NO_FLOW: 328 // Raspberry Pi 3 A 329 // Raspberry Pi 3 B 330 // power up with H5 and without power cycle untested/unsupported 331 bt_reg_en_pin = 128; 332 transport_config.baudrate_main = 921600; 333 transport_config.flowcontrol = 0; 334 break; 335 case UART_HARDWARE_FLOW: 336 // Raspberry Pi Zero W gpio 45, 3 mbps does not work (investigation pending) 337 // Raspberry Pi 3A+ vgpio 129 but WLAN + BL 338 // Raspberry Pi 3B+ vgpio 129 but WLAN + BL 339 transport_config.flowcontrol = 1; 340 int model = raspi_get_model(); 341 if (model == MODEL_ZERO_W){ 342 bt_reg_en_pin = 45; 343 transport_config.baudrate_main = 921600; 344 } else { 345 bt_reg_en_pin = 129; 346 transport_config.baudrate_main = 3000000; 347 } 348 349 #ifdef ENABLE_CONTROLLER_WARM_BOOT 350 power_cycle = false; 351 #else 352 // warn about power cycle on devices with shared reg_en pins 353 if (model == MODEL_3APLUS || model == MODEL_3BPLUS){ 354 printf("Wifi and Bluetooth share a single RESET line and BTstack needs to reset Bluetooth -> SSH over Wifi will fail\n"); 355 printf("Please add ENABLE_CONTROLLER_WARM_BOOT to btstack_config.h to enable startup without RESET\n"); 356 } 357 #endif 358 break; 359 } 360 printf("%s, %u, BT_REG_EN at GPIO %u, %s\n", transport_config.flowcontrol ? "H4":"H5", transport_config.baudrate_main, bt_reg_en_pin, power_cycle ? "Reset Controller" : "Warm Boot"); 361 362 // get BCM chipset driver 363 const btstack_chipset_t * chipset = btstack_chipset_bcm_instance(); 364 chipset->init(&transport_config); 365 366 // set path to firmware files 367 btstack_chipset_bcm_set_hcd_folder_path("/lib/firmware/brcm"); 368 369 // setup UART driver 370 const btstack_uart_block_t * uart_driver = btstack_uart_block_posix_instance(); 371 372 // extract UART config from transport config 373 uart_config.baudrate = transport_config.baudrate_init; 374 uart_config.flowcontrol = transport_config.flowcontrol; 375 uart_config.device_name = transport_config.device_name; 376 uart_driver->init(&uart_config); 377 378 // HW with FlowControl -> we can use regular h4 mode 379 const hci_transport_t * transport; 380 if (transport_config.flowcontrol){ 381 transport = hci_transport_h4_instance(uart_driver); 382 } else { 383 transport = hci_transport_h5_instance(uart_driver); 384 } 385 386 // setup HCI (to be able to use bcm chipset driver) 387 hci_init(transport, (void*) &transport_config); 388 hci_set_bd_addr( addr ); 389 hci_set_chipset(btstack_chipset_bcm_instance()); 390 391 // inform about BTstack state 392 hci_event_callback_registration.callback = &packet_handler; 393 hci_add_event_handler(&hci_event_callback_registration); 394 395 // handle CTRL-c 396 signal(SIGINT, sigint_handler); 397 398 main_argc = argc; 399 main_argv = argv; 400 401 // power cycle Bluetooth controller on older models without flowcontrol 402 if (power_cycle){ 403 btstack_control_raspi_set_bt_reg_en_pin(bt_reg_en_pin); 404 btstack_control_t *control = btstack_control_raspi_get_instance(); 405 control->init(NULL); 406 control->off(); 407 usleep( 100000 ); 408 control->on(); 409 } 410 411 if (transport_config.flowcontrol){ 412 413 // re-use current terminal speed (if there was no power cycle) 414 if (!power_cycle){ 415 raspi_get_terminal_params( &transport_config ); 416 } 417 418 // with flowcontrol, we use h4 and are done 419 btstack_main(main_argc, main_argv); 420 421 } else { 422 423 // assume BCM4343W used in Pi 3 A/B. Pi 3 A/B+ have a newer controller but support H4 with Flowcontrol 424 btstack_chipset_bcm_set_device_name("BCM43430A1"); 425 426 // phase #1 download firmware 427 printf("Phase 1: Download firmware\n"); 428 429 // phase #2 start main app 430 btstack_chipset_bcm_download_firmware(uart_driver, transport_config.baudrate_main, &phase2); 431 } 432 433 // go 434 btstack_run_loop_execute(); 435 return 0; 436 } 437 438 static void phase2(int status){ 439 440 if (status){ 441 printf("Download firmware failed\n"); 442 return; 443 } 444 445 printf("Phase 2: Main app\n"); 446 447 // setup app 448 btstack_main(main_argc, main_argv); 449 } 450 451