xref: /btstack/chipset/em9301/btstack_chipset_em9301.c (revision 39127754112d635f8d55bf39817a539acc1c6e74)
1 /*
2  * Copyright (C) 2014 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_em9301.c"
39 
40 /*
41  *  btstack_chipset_em9301.c
42  *
43  *  Adapter to use em9301-based chipsets with BTstack
44  *
45  *  Allows to set public BD ADDR
46  */
47 
48 #include "btstack_config.h"
49 #include "btstack_chipset_em9301.h"
50 #include "btstack_debug.h"
51 
52 #include <stddef.h>   /* NULL */
53 #include <string.h>   /* memcpy */
54 #include "hci.h"
55 
56 // should go to some common place
57 #define OPCODE(ogf, ocf) (ocf | ogf << 10)
58 
59 #define HCI_OPCODE_EM_WRITE_PATCH_START        (0xFC27)
60 #define HCI_OPCODE_EM_WRITE_PATCH_CONTINUE     (0xFC28)
61 #define HCI_OPCODE_EM_WRITE_PATCH_ABORT        (0xFC29)
62 #define HCI_OPCODE_EM_CPU_RESET                (0xFC32)
63 
64 /**
65  * @param bd_addr
66  */
67 const hci_cmd_t hci_vendor_em_set_public_address = {
68     0xFC02, "B"
69 };
70 
71 /**
72  * @param baud_rate_index
73  */
74 const hci_cmd_t hci_vendor_em_set_uart_baudrate = {
75     0xFC07, "1"
76 };
77 
78 /**
79  * @param transmitter_test_mode
80  * @param channel_number
81  * @param packet_length
82  * @param packet_payload_type
83  */
84 const hci_cmd_t hci_vendor_em_transmitter_test = {
85     0xFC11, "1111"
86 };
87 
88 /**
89  */
90 const hci_cmd_t hci_vendor_em_transmitter_test_end = {
91     0xFC12, ""
92 };
93 
94 /**
95  * @param patch_index
96  */
97 const hci_cmd_t hci_vendor_em_patch_query = {
98     0xFC34, "2"
99 };
100 
101 /**
102  * Change the state of the selected memory.
103  * @param memory_attribute
104  */
105 const hci_cmd_t hci_vendor_em_set_memory_mode = {
106     0xFC2B, "1"
107 };
108 
109 /**
110  * @param sleep_option_settings
111  */
112 const hci_cmd_t hci_vendor_em_set_sleep_options = {
113     0xFC2D, "1"
114 };
115 
116 // baudrate to index for hci_vendor_em_set_uart_baudrate
117 static const uint32_t baudrates[] = {
118 	      0,
119 	      0,
120 	      0,
121 	   9600,
122 	  14400,
123 	  19200,
124 	  28800,
125 	  38400,
126 	  57600,
127 	  76800,
128 	 115200,
129 	 230400,
130 	 460800,
131 	 921600,
132 	1843200,
133 };
134 
135 #ifdef HAVE_EM9304_PATCH_CONTAINER
136 
137 extern const uint8_t   container_blob_data[];
138 extern const uint32_t  container_blob_size;
139 
140 static uint32_t container_blob_offset  = 0;
141 static uint32_t container_end;	// current container
142 static uint16_t patch_sequence_number;
143 static int      em_cpu_reset_sent;
144 
145 static enum {
146 	UPLOAD_IDLE,
147 	UPLOAD_ACTIVE,
148 } upload_state;
149 
150 
151 // CRC32 implementation using 4-bit lookup table created by pycrc v0.9.1, https://pycrc.org
152 // ./pycrc.py --model crc-32 --algorithm table-driven --table-idx-width=4 --generate c
153 static const uint32_t crc32_table[16] = {
154 	0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
155 	0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
156 };
157 
158 static uint32_t btstack_crc32(const uint8_t *buf, uint16_t size){
159 	uint16_t pos;
160 	uint32_t crc = 0xffffffff;
161 	for (pos=0 ; pos<size ; pos++){
162         int tbl_idx = crc ^ buf[pos];
163         crc = crc32_table[tbl_idx & 0x0f] ^ (crc >> 4);
164         tbl_idx = crc ^ (buf[pos] >> 4);
165         crc = crc32_table[tbl_idx & 0x0f] ^ (crc >> 4);
166     }
167 	return ~crc;
168 }
169 
170 #endif
171 
172 static void chipset_set_bd_addr_command(bd_addr_t addr, uint8_t *hci_cmd_buffer){
173     little_endian_store_16(hci_cmd_buffer, 0, OPCODE(OGF_VENDOR, 0x02));
174     hci_cmd_buffer[2] = 0x06;
175     reverse_bd_addr(addr, &hci_cmd_buffer[3]);
176 }
177 
178 static void chipset_set_baudrate_command(uint32_t baudrate, uint8_t *hci_cmd_buffer){
179 	// lookup baudrates
180 	unsigned i;
181 	int found = 0;
182 	for (i=0 ; i < sizeof(baudrates)/sizeof(uint32_t) ; i++){
183 		if (baudrates[i] == baudrate){
184 			found = i;
185 			break;
186 		}
187 	}
188 	if (!found){
189 		log_error("Baudrate %u not found in table", baudrate);
190 		return;
191 	}
192     little_endian_store_16(hci_cmd_buffer, 0, OPCODE(OGF_VENDOR, 0x07));
193     hci_cmd_buffer[2] = 0x01;
194     hci_cmd_buffer[3] = i;
195 }
196 
197 #ifdef HAVE_EM9304_PATCH_CONTAINER
198 static void chipset_init(const void * config){
199 	UNUSED(config);
200 	container_blob_offset = 0;
201 	em_cpu_reset_sent = 0;
202 	upload_state = UPLOAD_IDLE;
203 }
204 
205 static btstack_chipset_result_t chipset_next_command(uint8_t * hci_cmd_buffer){
206 	log_info("pos %u, container end %u, blob size %u", container_blob_offset, container_end, container_blob_size);
207 
208     if (container_blob_offset >= container_blob_size) {
209     	if (0 == em_cpu_reset_sent){
210     		// send EM CPU Reset
211 		    little_endian_store_16(hci_cmd_buffer, 0, HCI_OPCODE_EM_CPU_RESET);
212 		    hci_cmd_buffer[2] = 0;
213 		    em_cpu_reset_sent = 1;
214 		    return BTSTACK_CHIPSET_VALID_COMMAND;
215     	} else {
216 	        return BTSTACK_CHIPSET_DONE;
217     	}
218     }
219 
220     uint32_t tag;
221     uint16_t bytes_to_upload;
222     uint32_t crc;
223     uint32_t container_size;
224 
225 	switch (upload_state){
226 		case UPLOAD_IDLE:
227 			// check for 'em93' tag
228 			tag = little_endian_read_32(container_blob_data, container_blob_offset);
229 			if (0x656d3933 != tag) {
230 				log_error("Expected 0x656d3933 ('em934') but got %08x", (int) tag);
231 				return BTSTACK_CHIPSET_DONE;
232 			}
233 			// fetch info for current container
234 			container_size = little_endian_read_32(container_blob_data, container_blob_offset + 4);
235 			container_end = container_blob_offset + container_size;
236 			// start uploading (<= 59 bytes)
237 			patch_sequence_number = 1;
238 			bytes_to_upload = btstack_min(59, container_end - container_blob_offset);
239 			crc = btstack_crc32(&container_blob_data[container_blob_offset], bytes_to_upload);
240 			log_info("Container type 0x%02x, id %u, build nr %u, user build nr %u, size %u",
241 				(int) container_blob_data[container_blob_offset+9],
242 				(int) container_blob_data[container_blob_offset+10],
243 				(int) little_endian_read_16(container_blob_data, container_blob_offset+12),
244 				(int) little_endian_read_16(container_blob_data, container_blob_offset+14),
245 				(int) container_size);
246 			// build command
247 		    little_endian_store_16(hci_cmd_buffer, 0, HCI_OPCODE_EM_WRITE_PATCH_START);
248 		    hci_cmd_buffer[2] = 5 + bytes_to_upload;
249 		    hci_cmd_buffer[3] = 0;	// upload to iRAM1
250 		    little_endian_store_32(hci_cmd_buffer, 4, crc);
251 		    memcpy(&hci_cmd_buffer[8], &container_blob_data[container_blob_offset], bytes_to_upload);
252 		    container_blob_offset += bytes_to_upload;
253 		    if (container_blob_offset < container_end){
254 		    	upload_state = UPLOAD_ACTIVE;
255 		    }
256 		    return BTSTACK_CHIPSET_VALID_COMMAND;
257 		case UPLOAD_ACTIVE:
258 			// Upload next segement
259 			bytes_to_upload = btstack_min(58, container_end - container_blob_offset);
260 			crc = btstack_crc32(&container_blob_data[container_blob_offset], bytes_to_upload);
261 			// build command
262 		    little_endian_store_16(hci_cmd_buffer, 0, HCI_OPCODE_EM_WRITE_PATCH_CONTINUE);
263 		    hci_cmd_buffer[2] = 6 + bytes_to_upload;
264 		    little_endian_store_16(hci_cmd_buffer, 3, patch_sequence_number++);
265 		    little_endian_store_32(hci_cmd_buffer, 5, crc);
266 		    memcpy(&hci_cmd_buffer[9], &container_blob_data[container_blob_offset], bytes_to_upload);
267 		    container_blob_offset += bytes_to_upload;
268 		    if (container_blob_offset >= container_end){
269 		    	log_info("container done maybe another one");
270 		    	upload_state = UPLOAD_IDLE;
271 		    }
272 		    return BTSTACK_CHIPSET_VALID_COMMAND;
273         default:
274             btstack_assert(false);
275             break;
276 	}
277 	return BTSTACK_CHIPSET_DONE;
278 }
279 #endif
280 
281 static const btstack_chipset_t btstack_chipset_em9301 = {
282     "EM9301",
283 #ifdef HAVE_EM9304_PATCH_CONTAINER
284     chipset_init,
285     chipset_next_command,
286 #else
287     NULL,
288     NULL,
289 #endif
290     chipset_set_baudrate_command,
291     chipset_set_bd_addr_command,
292 };
293 
294 // MARK: public API
295 const btstack_chipset_t * btstack_chipset_em9301_instance(void){
296     return &btstack_chipset_em9301;
297 }
298