xref: /btstack/chipset/da145xx/btstack_chipset_da145xx.c (revision d00ab9e3a0094f929407efbf0610465286ad22de)
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