xref: /btstack/chipset/nxp/btstack_chipset_nxp.c (revision 91dcc6581851fac666d4912e40f81a43cacdfa75)
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