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