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 // prototypes 76 static void nxp_send_chunk_v1(void); 77 static void nxp_done_with_status(uint8_t status); 78 static void nxp_send_chunk_v3(void); 79 static void nxp_read_uart_handler(void); 80 static void nxp_start(void); 81 82 // globals 83 static void (*nxp_download_complete)(uint8_t status); 84 static const btstack_uart_t * nxp_uart_driver; 85 static bool nxp_have_firmware; 86 87 static uint16_t nxp_chip_id; 88 89 static const uint8_t * nxp_fw_data; 90 static uint32_t nxp_fw_size; 91 static uint32_t nxp_fw_offset; 92 93 static uint8_t nxp_input_buffer[10]; 94 static uint16_t nxp_input_pos; 95 static uint16_t nxp_input_bytes_requested; 96 97 static uint8_t nxp_output_buffer[2048 + 1]; 98 99 static const uint8_t nxp_ack_buffer_v1[] = {NXP_ACK_V1 }; 100 static const uint8_t nxp_ack_buffer_v3[] = {NXP_ACK_V3, 0x92 }; 101 102 static uint16_t nxp_fw_request_len; 103 static uint8_t nxp_fw_resend_count; 104 105 static enum { 106 NXP_TX_IDLE, 107 NXP_TX_SEND_CHUNK_V1, 108 NXP_TX_SEND_CHUNK_V3, 109 } nxp_tx_state; 110 111 #ifdef HAVE_POSIX_FILE_IO 112 static char nxp_firmware_path[1000]; 113 static FILE * nxp_firmware_file; 114 115 static char *nxp_fw_name_from_chipid(uint16_t chip_id) 116 { 117 switch (chip_id) { 118 case NXP_CHIP_ID_W9098: 119 return NXP_FIRMWARE_W9098; 120 case NXP_CHIP_ID_IW416: 121 return NXP_FIRMWARE_IW416; 122 case NXP_CHIP_ID_IW612: 123 return NXP_FIRMWARE_IW612; 124 default: 125 log_error("Unknown chip id 0x%04x", chip_id); 126 return NULL; 127 } 128 } 129 130 static void nxp_load_firmware(void) { 131 if (nxp_firmware_file == NULL){ 132 log_info("chipset-bcm: open file %s", nxp_firmware_path); 133 nxp_firmware_file = fopen(nxp_firmware_path, "rb"); 134 if (nxp_firmware_file != NULL){ 135 nxp_have_firmware = true; 136 } 137 } 138 139 } 140 static uint16_t nxp_read_firmware(uint16_t bytes_to_read, uint8_t * buffer) { 141 size_t bytes_read = fread(buffer, 1, bytes_to_read, nxp_firmware_file); 142 return bytes_read; 143 } 144 145 static void nxp_unload_firmware(void) { 146 btstack_assert(nxp_firmware_file != NULL); 147 fclose(nxp_firmware_file); 148 nxp_firmware_file = NULL; 149 } 150 #else 151 void nxp_load_firmware(void){ 152 nxp_have_firmware = true; 153 } 154 155 // read bytes from firmware file 156 static uint16_t nxp_read_firmware(uint16_t bytes_to_read, uint8_t * buffer){ 157 if (nxp_fw_request_len > nxp_fw_size - nxp_fw_offset){ 158 printf("fw_request_len %u > remaining file len %u\n", nxp_fw_request_len, nxp_fw_size - nxp_fw_offset); 159 return nxp_fw_size - nxp_fw_offset; 160 } 161 memcpy(buffer, &nxp_fw_data[nxp_fw_offset], bytes_to_read); 162 nxp_fw_offset += nxp_fw_request_len; 163 return bytes_to_read; 164 } 165 static void nxp_unload_firmware(void) { 166 } 167 #endif 168 169 static void nxp_dummy(void){ 170 } 171 172 static void nxp_send_ack_v1() { 173 printf("SEND: ack v1\n"); 174 nxp_uart_driver->send_block(nxp_ack_buffer_v1, sizeof(nxp_ack_buffer_v1)); 175 } 176 177 static void nxp_send_ack_v3() { 178 printf("SEND: ack v3\n"); 179 nxp_uart_driver->send_block(nxp_ack_buffer_v3, sizeof(nxp_ack_buffer_v3)); 180 } 181 182 static bool nxp_valid_packet(void){ 183 switch (nxp_input_buffer[0]){ 184 case NXP_V1_FIRMWARE_REQUEST_PACKET: 185 case NXP_V1_CHIP_VERION_PACKET: 186 // first two uint16_t should xor to 0xffff 187 return ((nxp_input_buffer[1] ^ nxp_input_buffer[3]) == 0xff) && ((nxp_input_buffer[2] ^ nxp_input_buffer [4]) == 0xff); 188 case NXP_V3_CHIP_VERSION_PACKET: 189 case NXP_V3_FIRMWARE_REQUEST_PACKET: 190 // TODO: check crc-8 191 return true; 192 default: 193 return false; 194 } 195 } 196 197 static void nxp_handle_chip_version_v1(void){ 198 printf("RECV: NXP_V1_CHIP_VER_PKT, id = 0x%x02, revision = 0x%02x\n", nxp_input_buffer[0], nxp_input_buffer[1]); 199 nxp_tx_state = NXP_TX_IDLE; 200 nxp_send_ack_v1(); 201 } 202 203 static void nxp_handle_chip_version_v3(void){ 204 nxp_chip_id = little_endian_read_16(nxp_input_buffer, 1); 205 btstack_strcpy(nxp_firmware_path, sizeof(nxp_firmware_path), nxp_fw_name_from_chipid(nxp_chip_id)); 206 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); 207 nxp_tx_state = NXP_TX_IDLE; 208 nxp_send_ack_v3(); 209 } 210 211 static void nxp_prepare_firmware(void){ 212 // get firmware 213 if (nxp_have_firmware == false){ 214 nxp_load_firmware(); 215 } 216 if (nxp_have_firmware == false){ 217 printf("No firmware found, abort\n"); 218 } 219 } 220 221 static void nxp_send_chunk_v1(void){ 222 if (nxp_fw_request_len == 0){ 223 printf("last chunk sent!\n"); 224 nxp_unload_firmware(); 225 nxp_done_with_status(ERROR_CODE_SUCCESS); 226 return; 227 } else if ((nxp_fw_request_len & 1) == 0){ 228 // update sttate 229 nxp_fw_offset += nxp_fw_request_len; 230 nxp_fw_resend_count = 0; 231 // read next firmware chunk 232 uint16_t bytes_read = nxp_read_firmware(nxp_fw_request_len, nxp_output_buffer); 233 if (bytes_read < nxp_fw_request_len){ 234 printf("only %u of %u bytes available, abort.\n", bytes_read, nxp_fw_request_len); 235 nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE); 236 return; 237 } 238 } else { 239 // resend last chunk if request len is odd 240 if (nxp_fw_resend_count >= NXP_MAX_RESEND_COUNT){ 241 printf("Resent last block %u times, abort.", nxp_fw_resend_count); 242 nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE); 243 return; 244 } 245 nxp_fw_resend_count++; 246 } 247 printf("SEND: firmware %08x - %u bytes (%u. try)\n", nxp_fw_offset, nxp_fw_request_len, nxp_fw_resend_count + 1); 248 nxp_tx_state = NXP_TX_IDLE; 249 nxp_uart_driver->send_block(nxp_output_buffer, nxp_fw_request_len); 250 } 251 252 static void nxp_send_chunk_v3(void){ 253 // update state 254 nxp_fw_offset += nxp_fw_request_len; 255 nxp_fw_resend_count = 0; 256 if (nxp_fw_request_len == 0){ 257 printf("last chunk sent!\n"); 258 nxp_unload_firmware(); 259 nxp_done_with_status(ERROR_CODE_SUCCESS); 260 return; 261 } 262 // read next firmware chunk 263 uint16_t bytes_read = nxp_read_firmware(nxp_fw_request_len, nxp_output_buffer); 264 if (bytes_read < nxp_fw_request_len){ 265 printf("only %u of %u bytes available, abort.\n", bytes_read, nxp_fw_request_len); 266 nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE); 267 return; 268 } 269 printf("SEND: firmware %08x - %u bytes (%u. try)\n", nxp_fw_offset, nxp_fw_request_len, nxp_fw_resend_count + 1); 270 nxp_tx_state = NXP_TX_IDLE; 271 nxp_uart_driver->send_block(nxp_output_buffer, nxp_fw_request_len); 272 } 273 274 static void nxp_handle_firmware_request_v1(void){ 275 nxp_fw_request_len = little_endian_read_16(nxp_input_buffer, 1); 276 printf("RECV: NXP_V1_FW_REQ_PKT, len %u\n", nxp_fw_request_len); 277 278 nxp_prepare_firmware(); 279 if (nxp_have_firmware == false){ 280 return; 281 } 282 nxp_tx_state = NXP_TX_SEND_CHUNK_V1; 283 nxp_send_ack_v1(); 284 } 285 286 static void nxp_handle_firmware_request_v3(void){ 287 nxp_fw_request_len = little_endian_read_16(nxp_input_buffer, 1); 288 printf("RECV: NXP_V3_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_state = NXP_TX_SEND_CHUNK_V3; 295 nxp_send_ack_v3(); 296 } 297 298 static void nxp_start_read(uint16_t bytes_to_read){ 299 nxp_input_bytes_requested = bytes_to_read; 300 nxp_uart_driver->receive_block(&nxp_input_buffer[nxp_input_pos], bytes_to_read); 301 } 302 303 static void nxp_read_uart_handler(void){ 304 uint16_t bytes_to_read; 305 if (nxp_input_pos == 0){ 306 switch (nxp_input_buffer[0]){ 307 case NXP_V1_CHIP_VERION_PACKET: 308 case NXP_V3_CHIP_VERSION_PACKET: 309 case NXP_V1_FIRMWARE_REQUEST_PACKET: 310 nxp_input_pos++; 311 bytes_to_read = 4; 312 break; 313 case NXP_V3_FIRMWARE_REQUEST_PACKET: 314 nxp_input_pos++; 315 bytes_to_read = 9; 316 break; 317 default: 318 // invalid packet type, skip and get next byte 319 bytes_to_read = 1; 320 break; 321 } 322 nxp_start_read(bytes_to_read); 323 } else { 324 nxp_input_pos += nxp_input_bytes_requested; 325 printf("RECV: "); 326 printf_hexdump(nxp_input_buffer, nxp_input_pos); 327 switch (nxp_input_buffer[0]){ 328 case NXP_V1_CHIP_VERION_PACKET: 329 nxp_handle_chip_version_v1(); 330 break; 331 case NXP_V3_CHIP_VERSION_PACKET: 332 nxp_handle_chip_version_v3(); 333 break; 334 case NXP_V1_FIRMWARE_REQUEST_PACKET: 335 nxp_handle_firmware_request_v1(); 336 break; 337 case NXP_V3_FIRMWARE_REQUEST_PACKET: 338 nxp_handle_firmware_request_v3(); 339 break; 340 default: 341 btstack_assert(false); 342 break; 343 } 344 nxp_input_pos = 0; 345 bytes_to_read = 1; 346 } 347 nxp_start_read(bytes_to_read); 348 } 349 350 static void nxp_write_uart_handler(void){ 351 switch (nxp_tx_state){ 352 case NXP_TX_IDLE: 353 break; 354 case NXP_TX_SEND_CHUNK_V1: 355 nxp_send_chunk_v1(); 356 break; 357 case NXP_TX_SEND_CHUNK_V3: 358 nxp_send_chunk_v3(); 359 break; 360 default: 361 break; 362 } 363 } 364 365 static void nxp_start(void){ 366 nxp_tx_state = NXP_TX_IDLE; 367 nxp_fw_resend_count = 0; 368 nxp_fw_offset = 0; 369 nxp_have_firmware = false; 370 nxp_uart_driver->set_block_received(&nxp_read_uart_handler); 371 nxp_uart_driver->set_block_sent(&nxp_write_uart_handler); 372 nxp_uart_driver->receive_block(nxp_input_buffer, 1); 373 } 374 375 static void nxp_done_with_status(uint8_t status){ 376 printf("DONE!\n"); 377 (*nxp_download_complete)(status); 378 } 379 380 static void nxp_done(void){ 381 nxp_done_with_status(ERROR_CODE_SUCCESS); 382 } 383 384 void btstack_chipset_nxp_set_v1_firmware_path(const char * firmware_path){ 385 btstack_strcpy(nxp_firmware_path, sizeof(nxp_firmware_path), firmware_path); 386 } 387 388 void btstack_chipset_nxp_set_firmware(const uint8_t * fw_data, uint32_t fw_size){ 389 nxp_fw_data = fw_data; 390 nxp_fw_size = fw_size; 391 } 392 393 void btstack_chipset_nxp_download_firmware_with_uart(const btstack_uart_t *uart_driver, void (*done)(uint8_t status)) { 394 nxp_uart_driver = uart_driver; 395 nxp_download_complete = done; 396 397 int res = nxp_uart_driver->open(); 398 399 if (res) { 400 log_error("uart_block init failed %u", res); 401 nxp_download_complete(res); 402 } 403 404 nxp_start(); 405 } 406 407 408 static void chipset_init(const void *transport_config){ 409 UNUSED(transport_config); 410 } 411 412 static btstack_chipset_t btstack_chipset_nxp = { 413 .name = "NXP", 414 .init = chipset_init, 415 .next_command = NULL, 416 .set_baudrate_command = NULL, 417 .set_bd_addr_command = NULL 418 }; 419 420 const btstack_chipset_t *btstack_chipset_nxp_instance(void){ 421 return &btstack_chipset_nxp; 422 } 423