1 /*
2 * Copyright (C) 2017 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_da145xx.c"
39
40 /*
41 * Adapter to use da1458x-based chipsets with BTstack
42 *
43 */
44
45 #include "btstack_config.h"
46 #include "btstack_chipset_da145xx.h"
47 #include "btstack_debug.h"
48
49
50 #include <stddef.h> /* NULL */
51 #include <string.h> /* memcpy */
52 #include "hci.h"
53
54 // Firmware download protocol contstants
55 #define SOH 0x01
56 #define STX 0x02
57 #define ACK 0x06
58 #define NACK 0x15
59 #define CRC_INIT 0x00
60
61 // prototypes
62 static void da145xx_w4_stx(void);
63 static void da145xx_w4_command_sent(void);
64 static void da145xx_w4_fw_sent(void);
65 static void da145xx_w4_ack(void);
66 static void da145xx_w4_crc(void);
67 static void da145xx_w4_final_ack_sent(void);
68
69 // globals
70 static void (*download_complete)(int result);
71 static const btstack_uart_block_t * the_uart_driver;
72
73 static int download_count;
74 static uint8_t response_buffer[1];
75 static uint8_t command_buffer[3];
76 static const uint8_t * chipset_fw_data;
77 static uint16_t chipset_fw_size;
78
da145xx_start(void)79 static void da145xx_start(void){
80 // start to read
81 the_uart_driver->set_block_received(&da145xx_w4_stx);
82 the_uart_driver->receive_block(&response_buffer[0], 1);
83 log_info("da145xx_start: wait for 0x%02x", STX);
84 }
85
da145xx_w4_stx(void)86 static void da145xx_w4_stx(void){
87 log_debug("da145xx_w4_stx: read %x", response_buffer[0]);
88 switch (response_buffer[0]){
89 case STX:
90 log_info("da145xx_w4_stx: send download command");
91 // setup download config message
92 command_buffer[0] = SOH;
93 little_endian_store_16(command_buffer, 1, chipset_fw_size);
94 the_uart_driver->set_block_sent(da145xx_w4_command_sent);
95 the_uart_driver->send_block(command_buffer, 3);
96 break;
97 default:
98 // read again
99 the_uart_driver->receive_block(&response_buffer[0], 1);
100 break;
101 }
102 }
103
da145xx_w4_command_sent(void)104 static void da145xx_w4_command_sent(void){
105 log_info("da145xx_w4_command_sent: wait for ACK 0x%02x", ACK);
106 // write complete
107 the_uart_driver->set_block_received(&da145xx_w4_ack);
108 the_uart_driver->receive_block(&response_buffer[0], 1);
109 }
110
da145xx_w4_ack(void)111 static void da145xx_w4_ack(void){
112 log_info("da145xx_w4_ack: read %x", response_buffer[0]);
113 switch (response_buffer[0]){
114 case ACK:
115 // calc crc
116 // send file
117 log_info("da145xx_w4_ack: ACK received, send firmware");
118 the_uart_driver->set_block_sent(da145xx_w4_fw_sent);
119 the_uart_driver->send_block(chipset_fw_data, chipset_fw_size);
120 break;
121 case NACK:
122 // denied
123 the_uart_driver->close();
124 download_complete(1);
125 break;
126 default:
127 download_count++;
128 if (download_count < 10){
129 // something else went wrong try again
130 da145xx_start();
131 } else {
132 // give up
133 the_uart_driver->close();
134 download_complete(1);
135 }
136 break;
137 }
138 }
139
da145xx_w4_fw_sent(void)140 static void da145xx_w4_fw_sent(void){
141 // write complete
142 log_info("da145xx_w4_fw_sent: wait for crc");
143 the_uart_driver->set_block_received(&da145xx_w4_crc);
144 the_uart_driver->receive_block(&response_buffer[0], 1);
145 }
146
da145xx_w4_crc(void)147 static void da145xx_w4_crc(void){
148 log_info("da145xx_w4_crc: read %x\n", response_buffer[0]);
149
150 // calculate crc
151 int i;
152 uint8_t fcrc = CRC_INIT;
153 for (i = 0; i < chipset_fw_size; i++){
154 fcrc ^= chipset_fw_data[i];
155 }
156
157 // check crc
158 if (fcrc != response_buffer[0]){
159 log_error("da145xx_w4_crc: got 0x%02x expected 0x%02x", response_buffer[0], fcrc);
160 download_complete(1);
161 return;
162 }
163
164 // everything's fine, send final ack
165 command_buffer[0] = ACK;
166 the_uart_driver->set_block_sent(&da145xx_w4_final_ack_sent);
167 the_uart_driver->send_block(command_buffer, 1);
168 }
169
da145xx_w4_final_ack_sent(void)170 static void da145xx_w4_final_ack_sent(void){
171 download_complete(0);
172 }
173
btstack_chipset_da145xx_download_firmware_with_uart(const btstack_uart_t * uart_driver,const uint8_t * fw_data,uint16_t fw_size,void (* done)(int result))174 void btstack_chipset_da145xx_download_firmware_with_uart(const btstack_uart_t * uart_driver, const uint8_t * fw_data, uint16_t fw_size, void (*done)(int result)){
175
176 the_uart_driver = uart_driver;
177 download_complete = done;
178 chipset_fw_data = fw_data;
179 chipset_fw_size = fw_size;
180
181 int res = the_uart_driver->open();
182
183 if (res) {
184 log_error("uart_block init failed %u", res);
185 download_complete(res);
186 }
187
188 download_count = 0;
189 da145xx_start();
190 }
191
btstack_chipset_da145xx_download_firmware(const btstack_uart_block_t * uart_driver,const uint8_t * fw,uint16_t fw_size,void (* done)(int result))192 void btstack_chipset_da145xx_download_firmware(const btstack_uart_block_t * uart_driver, const uint8_t * fw, uint16_t fw_size, void (*done)(int result)){
193 btstack_chipset_da145xx_download_firmware_with_uart(uart_driver, fw, fw_size, done);
194 }
195
196 // not used currently
197
198 static const btstack_chipset_t btstack_chipset_da145xx = {
199 "DA145xx",
200 NULL, // chipset_init not used
201 NULL, // chipset_next_command not used
202 NULL, // chipset_set_baudrate_command not needed as we're connected via SPI
203 NULL, // chipset_set_bd_addr not provided
204 };
205
206 // MARK: public API
btstack_chipset_da145xx_instance(void)207 const btstack_chipset_t * btstack_chipset_da145xx_instance(void){
208 return &btstack_chipset_da145xx;
209 }
210
211