xref: /btstack/chipset/da145xx/btstack_chipset_da145xx.c (revision d00ab9e3a0094f929407efbf0610465286ad22de)
1*d00ab9e3SMatthias Ringwald /*
2*d00ab9e3SMatthias Ringwald  * Copyright (C) 2017 BlueKitchen GmbH
3*d00ab9e3SMatthias Ringwald  *
4*d00ab9e3SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*d00ab9e3SMatthias Ringwald  * modification, are permitted provided that the following conditions
6*d00ab9e3SMatthias Ringwald  * are met:
7*d00ab9e3SMatthias Ringwald  *
8*d00ab9e3SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*d00ab9e3SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*d00ab9e3SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*d00ab9e3SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*d00ab9e3SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*d00ab9e3SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*d00ab9e3SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*d00ab9e3SMatthias Ringwald  *    from this software without specific prior written permission.
16*d00ab9e3SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*d00ab9e3SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*d00ab9e3SMatthias Ringwald  *    monetary gain.
19*d00ab9e3SMatthias Ringwald  *
20*d00ab9e3SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*d00ab9e3SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*d00ab9e3SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*d00ab9e3SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24*d00ab9e3SMatthias Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*d00ab9e3SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*d00ab9e3SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*d00ab9e3SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*d00ab9e3SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*d00ab9e3SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*d00ab9e3SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*d00ab9e3SMatthias Ringwald  * SUCH DAMAGE.
32*d00ab9e3SMatthias Ringwald  *
33*d00ab9e3SMatthias Ringwald  * Please inquire about commercial licensing options at
34*d00ab9e3SMatthias Ringwald  * [email protected]
35*d00ab9e3SMatthias Ringwald  *
36*d00ab9e3SMatthias Ringwald  */
37*d00ab9e3SMatthias Ringwald 
38*d00ab9e3SMatthias Ringwald #define BTSTACK_FILE__ "btstack_chipset_da145xx.c"
39*d00ab9e3SMatthias Ringwald 
40*d00ab9e3SMatthias Ringwald /*
41*d00ab9e3SMatthias Ringwald  *  Adapter to use da1458x-based chipsets with BTstack
42*d00ab9e3SMatthias Ringwald  *
43*d00ab9e3SMatthias Ringwald  */
44*d00ab9e3SMatthias Ringwald 
45*d00ab9e3SMatthias Ringwald #include "btstack_config.h"
46*d00ab9e3SMatthias Ringwald #include "btstack_chipset_da145xx.h"
47*d00ab9e3SMatthias Ringwald #include "btstack_debug.h"
48*d00ab9e3SMatthias Ringwald 
49*d00ab9e3SMatthias Ringwald 
50*d00ab9e3SMatthias Ringwald #include <stddef.h>   /* NULL */
51*d00ab9e3SMatthias Ringwald #include <string.h>   /* memcpy */
52*d00ab9e3SMatthias Ringwald #include "hci.h"
53*d00ab9e3SMatthias Ringwald 
54*d00ab9e3SMatthias Ringwald // Firmware download protocol contstants
55*d00ab9e3SMatthias Ringwald #define SOH         0x01
56*d00ab9e3SMatthias Ringwald #define STX         0x02
57*d00ab9e3SMatthias Ringwald #define ACK         0x06
58*d00ab9e3SMatthias Ringwald #define NACK        0x15
59*d00ab9e3SMatthias Ringwald #define CRC_INIT    0x00
60*d00ab9e3SMatthias Ringwald 
61*d00ab9e3SMatthias Ringwald // prototypes
62*d00ab9e3SMatthias Ringwald static void da145xx_w4_stx(void);
63*d00ab9e3SMatthias Ringwald static void da145xx_w4_command_sent(void);
64*d00ab9e3SMatthias Ringwald static void da145xx_w4_fw_sent(void);
65*d00ab9e3SMatthias Ringwald static void da145xx_w4_ack(void);
66*d00ab9e3SMatthias Ringwald static void da145xx_w4_crc(void);
67*d00ab9e3SMatthias Ringwald static void da145xx_w4_final_ack_sent(void);
68*d00ab9e3SMatthias Ringwald 
69*d00ab9e3SMatthias Ringwald // globals
70*d00ab9e3SMatthias Ringwald static void (*download_complete)(int result);
71*d00ab9e3SMatthias Ringwald static const btstack_uart_block_t * the_uart_driver;
72*d00ab9e3SMatthias Ringwald 
73*d00ab9e3SMatthias Ringwald static int     download_count;
74*d00ab9e3SMatthias Ringwald static uint8_t response_buffer[1];
75*d00ab9e3SMatthias Ringwald static uint8_t command_buffer[3];
76*d00ab9e3SMatthias Ringwald static const uint8_t * chipset_fw_data;
77*d00ab9e3SMatthias Ringwald static uint16_t        chipset_fw_size;
78*d00ab9e3SMatthias Ringwald 
da145xx_start(void)79*d00ab9e3SMatthias Ringwald static void da145xx_start(void){
80*d00ab9e3SMatthias Ringwald     // start to read
81*d00ab9e3SMatthias Ringwald     the_uart_driver->set_block_received(&da145xx_w4_stx);
82*d00ab9e3SMatthias Ringwald     the_uart_driver->receive_block(&response_buffer[0], 1);
83*d00ab9e3SMatthias Ringwald     log_info("da145xx_start: wait for 0x%02x", STX);
84*d00ab9e3SMatthias Ringwald }
85*d00ab9e3SMatthias Ringwald 
da145xx_w4_stx(void)86*d00ab9e3SMatthias Ringwald static void da145xx_w4_stx(void){
87*d00ab9e3SMatthias Ringwald     log_debug("da145xx_w4_stx: read %x", response_buffer[0]);
88*d00ab9e3SMatthias Ringwald     switch (response_buffer[0]){
89*d00ab9e3SMatthias Ringwald         case STX:
90*d00ab9e3SMatthias Ringwald             log_info("da145xx_w4_stx: send download command");
91*d00ab9e3SMatthias Ringwald             // setup download config message
92*d00ab9e3SMatthias Ringwald             command_buffer[0] = SOH;
93*d00ab9e3SMatthias Ringwald             little_endian_store_16(command_buffer, 1, chipset_fw_size);
94*d00ab9e3SMatthias Ringwald             the_uart_driver->set_block_sent(da145xx_w4_command_sent);
95*d00ab9e3SMatthias Ringwald             the_uart_driver->send_block(command_buffer, 3);
96*d00ab9e3SMatthias Ringwald             break;
97*d00ab9e3SMatthias Ringwald         default:
98*d00ab9e3SMatthias Ringwald             // read again
99*d00ab9e3SMatthias Ringwald             the_uart_driver->receive_block(&response_buffer[0], 1);
100*d00ab9e3SMatthias Ringwald             break;
101*d00ab9e3SMatthias Ringwald     }
102*d00ab9e3SMatthias Ringwald }
103*d00ab9e3SMatthias Ringwald 
da145xx_w4_command_sent(void)104*d00ab9e3SMatthias Ringwald static void da145xx_w4_command_sent(void){
105*d00ab9e3SMatthias Ringwald     log_info("da145xx_w4_command_sent: wait for ACK 0x%02x", ACK);
106*d00ab9e3SMatthias Ringwald     // write complete
107*d00ab9e3SMatthias Ringwald     the_uart_driver->set_block_received(&da145xx_w4_ack);
108*d00ab9e3SMatthias Ringwald     the_uart_driver->receive_block(&response_buffer[0], 1);
109*d00ab9e3SMatthias Ringwald }
110*d00ab9e3SMatthias Ringwald 
da145xx_w4_ack(void)111*d00ab9e3SMatthias Ringwald static void da145xx_w4_ack(void){
112*d00ab9e3SMatthias Ringwald     log_info("da145xx_w4_ack: read %x", response_buffer[0]);
113*d00ab9e3SMatthias Ringwald     switch (response_buffer[0]){
114*d00ab9e3SMatthias Ringwald         case ACK:
115*d00ab9e3SMatthias Ringwald             // calc crc
116*d00ab9e3SMatthias Ringwald             // send file
117*d00ab9e3SMatthias Ringwald             log_info("da145xx_w4_ack: ACK received, send firmware");
118*d00ab9e3SMatthias Ringwald             the_uart_driver->set_block_sent(da145xx_w4_fw_sent);
119*d00ab9e3SMatthias Ringwald             the_uart_driver->send_block(chipset_fw_data, chipset_fw_size);
120*d00ab9e3SMatthias Ringwald             break;
121*d00ab9e3SMatthias Ringwald         case NACK:
122*d00ab9e3SMatthias Ringwald             // denied
123*d00ab9e3SMatthias Ringwald             the_uart_driver->close();
124*d00ab9e3SMatthias Ringwald             download_complete(1);
125*d00ab9e3SMatthias Ringwald             break;
126*d00ab9e3SMatthias Ringwald         default:
127*d00ab9e3SMatthias Ringwald             download_count++;
128*d00ab9e3SMatthias Ringwald             if (download_count < 10){
129*d00ab9e3SMatthias Ringwald                 // something else went wrong try again
130*d00ab9e3SMatthias Ringwald                 da145xx_start();
131*d00ab9e3SMatthias Ringwald             } else {
132*d00ab9e3SMatthias Ringwald                 // give up
133*d00ab9e3SMatthias Ringwald                 the_uart_driver->close();
134*d00ab9e3SMatthias Ringwald                 download_complete(1);
135*d00ab9e3SMatthias Ringwald             }
136*d00ab9e3SMatthias Ringwald             break;
137*d00ab9e3SMatthias Ringwald     }
138*d00ab9e3SMatthias Ringwald }
139*d00ab9e3SMatthias Ringwald 
da145xx_w4_fw_sent(void)140*d00ab9e3SMatthias Ringwald static void da145xx_w4_fw_sent(void){
141*d00ab9e3SMatthias Ringwald     // write complete
142*d00ab9e3SMatthias Ringwald     log_info("da145xx_w4_fw_sent: wait for crc");
143*d00ab9e3SMatthias Ringwald     the_uart_driver->set_block_received(&da145xx_w4_crc);
144*d00ab9e3SMatthias Ringwald     the_uart_driver->receive_block(&response_buffer[0], 1);
145*d00ab9e3SMatthias Ringwald }
146*d00ab9e3SMatthias Ringwald 
da145xx_w4_crc(void)147*d00ab9e3SMatthias Ringwald static void da145xx_w4_crc(void){
148*d00ab9e3SMatthias Ringwald     log_info("da145xx_w4_crc: read %x\n", response_buffer[0]);
149*d00ab9e3SMatthias Ringwald 
150*d00ab9e3SMatthias Ringwald     // calculate crc
151*d00ab9e3SMatthias Ringwald     int i;
152*d00ab9e3SMatthias Ringwald     uint8_t fcrc = CRC_INIT;
153*d00ab9e3SMatthias Ringwald     for (i = 0; i < chipset_fw_size; i++){
154*d00ab9e3SMatthias Ringwald         fcrc ^= chipset_fw_data[i];
155*d00ab9e3SMatthias Ringwald     }
156*d00ab9e3SMatthias Ringwald 
157*d00ab9e3SMatthias Ringwald     // check crc
158*d00ab9e3SMatthias Ringwald     if (fcrc != response_buffer[0]){
159*d00ab9e3SMatthias Ringwald         log_error("da145xx_w4_crc: got 0x%02x expected 0x%02x", response_buffer[0], fcrc);
160*d00ab9e3SMatthias Ringwald         download_complete(1);
161*d00ab9e3SMatthias Ringwald         return;
162*d00ab9e3SMatthias Ringwald     }
163*d00ab9e3SMatthias Ringwald 
164*d00ab9e3SMatthias Ringwald     // everything's fine, send final ack
165*d00ab9e3SMatthias Ringwald     command_buffer[0] = ACK;
166*d00ab9e3SMatthias Ringwald     the_uart_driver->set_block_sent(&da145xx_w4_final_ack_sent);
167*d00ab9e3SMatthias Ringwald     the_uart_driver->send_block(command_buffer, 1);
168*d00ab9e3SMatthias Ringwald }
169*d00ab9e3SMatthias Ringwald 
da145xx_w4_final_ack_sent(void)170*d00ab9e3SMatthias Ringwald static void da145xx_w4_final_ack_sent(void){
171*d00ab9e3SMatthias Ringwald     download_complete(0);
172*d00ab9e3SMatthias Ringwald }
173*d00ab9e3SMatthias Ringwald 
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*d00ab9e3SMatthias Ringwald 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*d00ab9e3SMatthias Ringwald 
176*d00ab9e3SMatthias Ringwald     the_uart_driver   = uart_driver;
177*d00ab9e3SMatthias Ringwald     download_complete = done;
178*d00ab9e3SMatthias Ringwald     chipset_fw_data = fw_data;
179*d00ab9e3SMatthias Ringwald     chipset_fw_size = fw_size;
180*d00ab9e3SMatthias Ringwald 
181*d00ab9e3SMatthias Ringwald     int res = the_uart_driver->open();
182*d00ab9e3SMatthias Ringwald 
183*d00ab9e3SMatthias Ringwald     if (res) {
184*d00ab9e3SMatthias Ringwald         log_error("uart_block init failed %u", res);
185*d00ab9e3SMatthias Ringwald         download_complete(res);
186*d00ab9e3SMatthias Ringwald     }
187*d00ab9e3SMatthias Ringwald 
188*d00ab9e3SMatthias Ringwald     download_count = 0;
189*d00ab9e3SMatthias Ringwald     da145xx_start();
190*d00ab9e3SMatthias Ringwald }
191*d00ab9e3SMatthias Ringwald 
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*d00ab9e3SMatthias Ringwald 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*d00ab9e3SMatthias Ringwald     btstack_chipset_da145xx_download_firmware_with_uart(uart_driver, fw, fw_size, done);
194*d00ab9e3SMatthias Ringwald }
195*d00ab9e3SMatthias Ringwald 
196*d00ab9e3SMatthias Ringwald // not used currently
197*d00ab9e3SMatthias Ringwald 
198*d00ab9e3SMatthias Ringwald static const btstack_chipset_t btstack_chipset_da145xx = {
199*d00ab9e3SMatthias Ringwald     "DA145xx",
200*d00ab9e3SMatthias Ringwald     NULL, // chipset_init not used
201*d00ab9e3SMatthias Ringwald     NULL, // chipset_next_command not used
202*d00ab9e3SMatthias Ringwald     NULL, // chipset_set_baudrate_command not needed as we're connected via SPI
203*d00ab9e3SMatthias Ringwald     NULL, // chipset_set_bd_addr not provided
204*d00ab9e3SMatthias Ringwald };
205*d00ab9e3SMatthias Ringwald 
206*d00ab9e3SMatthias Ringwald // MARK: public API
btstack_chipset_da145xx_instance(void)207*d00ab9e3SMatthias Ringwald const btstack_chipset_t * btstack_chipset_da145xx_instance(void){
208*d00ab9e3SMatthias Ringwald     return &btstack_chipset_da145xx;
209*d00ab9e3SMatthias Ringwald }
210*d00ab9e3SMatthias Ringwald 
211