1 /* 2 * Copyright (C) 2023 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__ "btstack_chipset_nxp.c" 39 40 #include "btstack_chipset_nxp.h" 41 #include "btstack_debug.h" 42 #include "btstack_event.h" 43 #include "hci_cmd.h" 44 45 #include <stdio.h> 46 47 #ifdef _MSC_VER 48 // ignore deprecated warning for fopen 49 #pragma warning(disable : 4996) 50 #endif 51 52 // Firmware download protocol constants 53 #define NXP_V1_FIRMWARE_REQUEST_PACKET 0xa5 54 #define NXP_V1_CHIP_VERION_PACKET 0xaa 55 #define NXP_V3_FIRMWARE_REQUEST_PACKET 0xa7 56 #define NXP_V3_CHIP_VERSION_PACKET 0xab 57 58 #define NXP_ACK_V1 0x5a 59 #define NXP_NAK_V1 0xbf 60 #define NXP_ACK_V3 0x7a 61 #define NXP_NAK_V3 0x7b 62 #define NXP_CRC_ERROR_V3 0x7c 63 64 // chip ids 65 #define NXP_CHIP_ID_W9098 0x5c03 66 #define NXP_CHIP_ID_IW416 0x7201 67 #define NXP_CHIP_ID_IW612 0x7601 68 69 // firmwares 70 #define NXP_FIRMWARE_W9098 "uartuart9098_bt_v1.bin" 71 #define NXP_FIRMWARE_IW416 "uartiw416_bt_v0.bin" 72 #define NXP_FIRMWARE_IW612 "uartspi_n61x_v1.bin.se" 73 74 #define NXP_MAX_RESEND_COUNT 5 75 76 // prototypes 77 static void nxp_done_with_status(uint8_t status); 78 static void nxp_read_uart_handler(void); 79 static void nxp_send_chunk_v1(void); 80 static void nxp_send_chunk_v3(void); 81 static void nxp_start(void); 82 static void nxp_run(void); 83 84 // globals 85 static void (*nxp_download_complete_callback)(uint8_t status); 86 static const btstack_uart_t * nxp_uart_driver; 87 static btstack_timer_source_t nxp_timer; 88 89 static uint16_t nxp_chip_id; 90 91 static const uint8_t * nxp_fw_data; 92 static uint32_t nxp_fw_size; 93 static uint32_t nxp_fw_offset; 94 95 static uint8_t nxp_input_buffer[10]; 96 static uint16_t nxp_input_pos; 97 static uint16_t nxp_input_bytes_requested; 98 99 static uint8_t nxp_output_buffer[2048 + 1]; 100 101 static const uint8_t nxp_ack_buffer_v1[] = {NXP_ACK_V1 }; 102 static const uint8_t nxp_ack_buffer_v3[] = {NXP_ACK_V3, 0x92 }; 103 104 static uint16_t nxp_fw_request_len; 105 static uint8_t nxp_fw_resend_count; 106 107 // state / tasks 108 static bool nxp_have_firmware; 109 static bool nxp_tx_send_ack_v1; 110 static bool nxp_tx_send_ack_v3; 111 static bool nxp_tx_send_chunk_v1; 112 static bool nxp_tx_send_chunk_v3; 113 static bool nxp_tx_active; 114 static bool nxp_download_done; 115 static uint8_t nxp_download_statue; 116 117 #ifdef HAVE_POSIX_FILE_IO 118 static char nxp_firmware_path[1000]; 119 static FILE * nxp_firmware_file; 120 121 static char *nxp_fw_name_from_chipid(uint16_t chip_id) 122 { 123 switch (chip_id) { 124 case NXP_CHIP_ID_W9098: 125 return NXP_FIRMWARE_W9098; 126 case NXP_CHIP_ID_IW416: 127 return NXP_FIRMWARE_IW416; 128 case NXP_CHIP_ID_IW612: 129 return NXP_FIRMWARE_IW612; 130 default: 131 log_error("Unknown chip id 0x%04x", chip_id); 132 return NULL; 133 } 134 } 135 136 static void nxp_load_firmware(void) { 137 if (nxp_firmware_file == NULL){ 138 log_info("open file %s", nxp_firmware_path); 139 nxp_firmware_file = fopen(nxp_firmware_path, "rb"); 140 if (nxp_firmware_file != NULL){ 141 printf("Open file '%s' failed\n", nxp_firmware_path); 142 nxp_have_firmware = true; 143 } 144 } 145 146 } 147 static uint16_t nxp_read_firmware(uint16_t bytes_to_read, uint8_t * buffer) { 148 size_t bytes_read = fread(buffer, 1, bytes_to_read, nxp_firmware_file); 149 return bytes_read; 150 } 151 152 static void nxp_unload_firmware(void) { 153 btstack_assert(nxp_firmware_file != NULL); 154 fclose(nxp_firmware_file); 155 nxp_firmware_file = NULL; 156 } 157 #else 158 void nxp_load_firmware(void){ 159 nxp_have_firmware = true; 160 } 161 162 // read bytes from firmware file 163 static uint16_t nxp_read_firmware(uint16_t bytes_to_read, uint8_t * buffer){ 164 if (nxp_fw_request_len > nxp_fw_size - nxp_fw_offset){ 165 printf("fw_request_len %u > remaining file len %u\n", nxp_fw_request_len, nxp_fw_size - nxp_fw_offset); 166 return nxp_fw_size - nxp_fw_offset; 167 } 168 memcpy(buffer, &nxp_fw_data[nxp_fw_offset], bytes_to_read); 169 nxp_fw_offset += nxp_fw_request_len; 170 return bytes_to_read; 171 } 172 static void nxp_unload_firmware(void) { 173 } 174 #endif 175 176 static void nxp_send_ack_v1() { 177 printf("SEND: ack v1\n"); 178 btstack_assert(nxp_tx_active == false); 179 nxp_tx_active = true; 180 nxp_uart_driver->send_block(nxp_ack_buffer_v1, sizeof(nxp_ack_buffer_v1)); 181 } 182 183 static void nxp_send_ack_v3() { 184 printf("SEND: ack v3\n"); 185 btstack_assert(nxp_tx_active == false); 186 nxp_tx_active = true; 187 nxp_uart_driver->send_block(nxp_ack_buffer_v3, sizeof(nxp_ack_buffer_v3)); 188 } 189 190 static bool nxp_valid_packet(void){ 191 switch (nxp_input_buffer[0]){ 192 case NXP_V1_FIRMWARE_REQUEST_PACKET: 193 case NXP_V1_CHIP_VERION_PACKET: 194 // first two uint16_t should xor to 0xffff 195 return ((nxp_input_buffer[1] ^ nxp_input_buffer[3]) == 0xff) && ((nxp_input_buffer[2] ^ nxp_input_buffer [4]) == 0xff); 196 case NXP_V3_CHIP_VERSION_PACKET: 197 case NXP_V3_FIRMWARE_REQUEST_PACKET: 198 // TODO: check crc-8 199 return true; 200 default: 201 return false; 202 } 203 } 204 205 static void nxp_handle_chip_version_v1(void){ 206 printf("RECV: NXP_V1_CHIP_VER_PKT, id = 0x%x02, revision = 0x%02x\n", nxp_input_buffer[0], nxp_input_buffer[1]); 207 nxp_tx_send_ack_v1 = true; 208 nxp_run(); 209 } 210 211 static void nxp_handle_chip_version_v3(void){ 212 nxp_chip_id = little_endian_read_16(nxp_input_buffer, 1); 213 btstack_strcpy(nxp_firmware_path, sizeof(nxp_firmware_path), nxp_fw_name_from_chipid(nxp_chip_id)); 214 printf("RECV: NXP_V3_CHIP_VER_PKT, id = 0x%04x, loader 0x%02x -> firmware '%s'\n", nxp_chip_id, nxp_input_buffer[3], nxp_firmware_path); 215 nxp_tx_send_ack_v3 = true; 216 nxp_run(); 217 } 218 219 static void nxp_prepare_firmware(void){ 220 // get firmware 221 if (nxp_have_firmware == false){ 222 nxp_load_firmware(); 223 } 224 if (nxp_have_firmware == false){ 225 printf("No firmware found, abort\n"); 226 } 227 } 228 229 static void nxp_send_chunk_v1(void){ 230 if (nxp_fw_request_len == 0){ 231 printf("last chunk sent!\n"); 232 nxp_unload_firmware(); 233 nxp_done_with_status(ERROR_CODE_SUCCESS); 234 return; 235 } else if ((nxp_fw_request_len & 1) == 0){ 236 // update sttate 237 nxp_fw_offset += nxp_fw_request_len; 238 nxp_fw_resend_count = 0; 239 // read next firmware chunk 240 uint16_t bytes_read = nxp_read_firmware(nxp_fw_request_len, nxp_output_buffer); 241 if (bytes_read < nxp_fw_request_len){ 242 printf("only %u of %u bytes available, abort.\n", bytes_read, nxp_fw_request_len); 243 nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE); 244 return; 245 } 246 } else { 247 // resend last chunk if request len is odd 248 if (nxp_fw_resend_count >= NXP_MAX_RESEND_COUNT){ 249 printf("Resent last block %u times, abort.", nxp_fw_resend_count); 250 nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE); 251 return; 252 } 253 nxp_fw_resend_count++; 254 } 255 printf("SEND: firmware %08x - %u bytes (%u. try)\n", nxp_fw_offset, nxp_fw_request_len, nxp_fw_resend_count + 1); 256 btstack_assert(nxp_tx_active == false); 257 nxp_tx_active = true; 258 nxp_uart_driver->send_block(nxp_output_buffer, nxp_fw_request_len); 259 } 260 261 static void nxp_send_chunk_v3(void){ 262 // update state 263 nxp_fw_offset += nxp_fw_request_len; 264 nxp_fw_resend_count = 0; 265 if (nxp_fw_request_len == 0){ 266 printf("last chunk sent!\n"); 267 nxp_unload_firmware(); 268 nxp_done_with_status(ERROR_CODE_SUCCESS); 269 return; 270 } 271 // read next firmware chunk 272 uint16_t bytes_read = nxp_read_firmware(nxp_fw_request_len, nxp_output_buffer); 273 if (bytes_read < nxp_fw_request_len){ 274 printf("only %u of %u bytes available, abort.\n", bytes_read, nxp_fw_request_len); 275 nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE); 276 return; 277 } 278 printf("SEND: firmware %08x - %u bytes (%u. try)\n", nxp_fw_offset, nxp_fw_request_len, nxp_fw_resend_count + 1); 279 btstack_assert(nxp_tx_active == false); 280 nxp_tx_active = true; 281 nxp_uart_driver->send_block(nxp_output_buffer, nxp_fw_request_len); 282 } 283 284 static void nxp_handle_firmware_request_v1(void){ 285 nxp_fw_request_len = little_endian_read_16(nxp_input_buffer, 1); 286 printf("RECV: NXP_V1_FW_REQ_PKT, len %u\n", nxp_fw_request_len); 287 288 nxp_prepare_firmware(); 289 if (nxp_have_firmware == false){ 290 return; 291 } 292 nxp_tx_send_ack_v1 = true; 293 nxp_tx_send_chunk_v1 = true; 294 nxp_run(); 295 } 296 297 static void nxp_handle_firmware_request_v3(void){ 298 nxp_fw_request_len = little_endian_read_16(nxp_input_buffer, 1); 299 printf("RECV: NXP_V3_FW_REQ_PKT, len %u\n", nxp_fw_request_len); 300 301 nxp_prepare_firmware(); 302 if (nxp_have_firmware == false){ 303 return; 304 } 305 nxp_tx_send_ack_v3 = true; 306 nxp_tx_send_chunk_v3 = true; 307 nxp_run(); 308 } 309 310 static void nxp_start_read(uint16_t bytes_to_read){ 311 nxp_input_bytes_requested = bytes_to_read; 312 nxp_uart_driver->receive_block(&nxp_input_buffer[nxp_input_pos], bytes_to_read); 313 } 314 315 static void nxp_read_uart_handler(void){ 316 uint16_t bytes_to_read; 317 if (nxp_input_pos == 0){ 318 switch (nxp_input_buffer[0]){ 319 case NXP_V1_CHIP_VERION_PACKET: 320 case NXP_V3_CHIP_VERSION_PACKET: 321 case NXP_V1_FIRMWARE_REQUEST_PACKET: 322 nxp_input_pos++; 323 bytes_to_read = 4; 324 break; 325 case NXP_V3_FIRMWARE_REQUEST_PACKET: 326 nxp_input_pos++; 327 bytes_to_read = 9; 328 break; 329 default: 330 // invalid packet type, skip and get next byte 331 bytes_to_read = 1; 332 break; 333 } 334 } else { 335 nxp_input_pos += nxp_input_bytes_requested; 336 printf("RECV: "); 337 printf_hexdump(nxp_input_buffer, nxp_input_pos); 338 switch (nxp_input_buffer[0]){ 339 case NXP_V1_CHIP_VERION_PACKET: 340 nxp_handle_chip_version_v1(); 341 break; 342 case NXP_V3_CHIP_VERSION_PACKET: 343 nxp_handle_chip_version_v3(); 344 break; 345 case NXP_V1_FIRMWARE_REQUEST_PACKET: 346 nxp_handle_firmware_request_v1(); 347 break; 348 case NXP_V3_FIRMWARE_REQUEST_PACKET: 349 nxp_handle_firmware_request_v3(); 350 break; 351 default: 352 btstack_assert(false); 353 break; 354 } 355 nxp_input_pos = 0; 356 bytes_to_read = 1; 357 358 // stop timer 359 btstack_run_loop_remove_timer(&nxp_timer); 360 } 361 nxp_start_read(bytes_to_read); 362 } 363 364 static void nxp_run(void){ 365 if (nxp_tx_active) { 366 return; 367 } 368 if (nxp_tx_send_ack_v1){ 369 nxp_tx_send_ack_v1 = false; 370 nxp_send_ack_v1(); 371 return; 372 } 373 if (nxp_tx_send_ack_v3){ 374 nxp_tx_send_ack_v3 = false; 375 nxp_send_ack_v3(); 376 return; 377 } 378 if (nxp_tx_send_chunk_v1){ 379 nxp_tx_send_chunk_v1 = false; 380 nxp_send_chunk_v1(); 381 return; 382 } 383 if (nxp_tx_send_chunk_v3){ 384 nxp_tx_send_chunk_v3 = false; 385 nxp_send_chunk_v3(); 386 return; 387 } 388 if (nxp_download_done){ 389 nxp_download_done = false; 390 (*nxp_download_complete_callback)(nxp_download_statue); 391 } 392 } 393 394 static void nxp_write_uart_handler(void){ 395 btstack_assert(nxp_tx_active == true); 396 printf("SEND: complete\n"); 397 nxp_tx_active = false; 398 nxp_run(); 399 } 400 401 static void nxp_start(void){ 402 nxp_fw_resend_count = 0; 403 nxp_fw_offset = 0; 404 nxp_have_firmware = false; 405 nxp_uart_driver->set_block_received(&nxp_read_uart_handler); 406 nxp_uart_driver->set_block_sent(&nxp_write_uart_handler); 407 nxp_uart_driver->receive_block(nxp_input_buffer, 1); 408 } 409 410 static void nxp_done_with_status(uint8_t status){ 411 nxp_download_statue = status; 412 nxp_download_done = true; 413 printf("DONE! status 0x%02x\n", status); 414 nxp_run(); 415 } 416 417 void btstack_chipset_nxp_set_v1_firmware_path(const char * firmware_path){ 418 btstack_strcpy(nxp_firmware_path, sizeof(nxp_firmware_path), firmware_path); 419 } 420 421 void btstack_chipset_nxp_set_firmware(const uint8_t * fw_data, uint32_t fw_size){ 422 nxp_fw_data = fw_data; 423 nxp_fw_size = fw_size; 424 } 425 426 void nxp_timer_handler(btstack_timer_source_t *ts) { 427 printf("No firmware request received, assuming firmware already loaded\n"); 428 nxp_done_with_status(ERROR_CODE_SUCCESS); 429 nxp_run(); 430 } 431 432 void btstack_chipset_nxp_download_firmware_with_uart(const btstack_uart_t *uart_driver, void (*callback)(uint8_t status)) { 433 nxp_uart_driver = uart_driver; 434 nxp_download_complete_callback = callback; 435 436 int res = nxp_uart_driver->open(); 437 438 if (res) { 439 log_error("uart_block init failed %u", res); 440 nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE); 441 nxp_run(); 442 return; 443 } 444 445 // if firmware is loaded, there will be no firmware request 446 btstack_run_loop_set_timer(&nxp_timer, 250); 447 btstack_run_loop_set_timer_handler(&nxp_timer, &nxp_timer_handler); 448 btstack_run_loop_add_timer(&nxp_timer); 449 450 nxp_start(); 451 } 452 453 // init script support 454 static enum { 455 NXP_INIT_SEND_SCO_CONFIG, 456 NXP_INIT_SEND_HOST_CONTROL_ENABLE, 457 NXP_INIT_SEND_WRITE_PCM_SETTINGS, 458 NXP_INIT_SEND_WRITE_PCM_SYNC_SETTINGS, 459 NXP_INIT_SEND_WRITE_PCM_LINK_SETTINGS, 460 NXP_INIT_DONE, 461 } nxp_init_state; 462 463 #ifdef ENABLE_SCO_OVER_HCI 464 // Voice Path: Host 465 static const uint8_t nxp_chipset_sco_routing_path = 0; 466 #endif 467 468 #ifdef ENABLE_SCO_OVER_PCM 469 // Voice Path: PCM/I2S 470 static const uint8_t nxp_chipset_sco_routing_path = 1; 471 #endif 472 473 static void nxp_init(const void *transport_config){ 474 UNUSED(transport_config); 475 nxp_init_state = NXP_INIT_SEND_SCO_CONFIG; 476 } 477 478 static btstack_chipset_result_t nxp_next_command(uint8_t * hci_cmd_buffer) { 479 switch (nxp_init_state){ 480 case NXP_INIT_SEND_SCO_CONFIG: 481 #if defined(ENABLE_SCO_OVER_HCI) || defined(ENABLE_SCO_OVER_PCM) 482 #ifdef ENABLE_NXP_PCM_WBS 483 nxp_init_state = NXP_INIT_SEND_HOST_CONTROL_ENABLE; 484 #else 485 nxp_init_state = NXP_INIT_SEND_WRITE_PCM_SETTINGS; 486 #endif 487 hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_set_sco_data_path, nxp_chipset_sco_routing_path); 488 return BTSTACK_CHIPSET_VALID_COMMAND; 489 #endif 490 #ifdef ENABLE_SCO_OVER_PCM 491 case NXP_INIT_SEND_HOST_CONTROL_ENABLE: 492 nxp_init_state = NXP_INIT_SEND_WRITE_PCM_SETTINGS; 493 // Host Control enabled 494 hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_host_pcm_i2s_control_enable, 1); 495 return BTSTACK_CHIPSET_VALID_COMMAND; 496 case NXP_INIT_SEND_WRITE_PCM_SETTINGS: 497 nxp_init_state = NXP_INIT_SEND_WRITE_PCM_SYNC_SETTINGS; 498 // PCM/I2S master mode 499 hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_write_pcm_i2s_settings, 0x02); 500 return BTSTACK_CHIPSET_VALID_COMMAND; 501 case NXP_INIT_SEND_WRITE_PCM_SYNC_SETTINGS: 502 nxp_init_state = NXP_INIT_SEND_WRITE_PCM_LINK_SETTINGS; 503 #ifdef ENABLE_NXP_PCM_WBS 504 // 16 kHz sync, 2048 kHz, data in left channel, DIN sampled on rising edge, DOUT driven on falling edge, I2Sa 505 hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_write_pcm_i2s_sync_settings, 0x03, 0x071e); 506 #else 507 // 8 kHz sync, 2048 kHz, data in left channel, DIN sampled on rising edge, DOUT driven on falling edge, I2S 508 hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_write_pcm_i2s_sync_settings, 0x03, 0x031e); 509 #endif 510 return BTSTACK_CHIPSET_VALID_COMMAND; 511 case NXP_INIT_SEND_WRITE_PCM_LINK_SETTINGS: 512 nxp_init_state = NXP_INIT_DONE; 513 // 1st SCO Link PCM Logical Slot 0, PCM start slot 1 514 hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_write_pcm_link_settings, 0x0004); 515 return BTSTACK_CHIPSET_VALID_COMMAND; 516 #endif 517 default: 518 break; 519 } 520 return BTSTACK_CHIPSET_DONE; 521 } 522 523 static btstack_chipset_t btstack_chipset_nxp = { 524 .name = "NXP", 525 .init = nxp_init, 526 .next_command = nxp_next_command, 527 .set_baudrate_command = NULL, 528 .set_bd_addr_command = NULL 529 }; 530 531 const btstack_chipset_t *btstack_chipset_nxp_instance(void){ 532 return &btstack_chipset_nxp; 533 } 534 535 uint32_t btstack_chipset_nxp_get_initial_baudrate(void){ 536 switch (nxp_chip_id){ 537 case NXP_CHIP_ID_IW612: 538 return 3000000; 539 default: 540 return 115200; 541 } 542 } 543