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