3D prevent negative arming // Reverse logic
[betaflight.git] / support / stmloader / stmbootloader.c
blob9a0550b8dade06e6e81ecdf7fe5807be428a2473
1 /*
2 This file is part of AutoQuad.
4 AutoQuad is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 AutoQuad is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with AutoQuad. If not, see <http://www.gnu.org/licenses/>.
16 Copyright © 2011 Bill Nesbitt
19 #ifndef _GNU_SOURCE
20 #define _GNU_SOURCE
21 #endif
23 #include "serial.h"
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <ctype.h>
29 #define STM_RETRIES_SHORT 1000
30 #define STM_RETRIES_LONG 50000
32 unsigned char getResults[11];
34 unsigned char stmHexToChar(const char *hex) {
35 char hex1, hex2;
36 unsigned char nibble1, nibble2;
38 // force data to upper case
39 hex1 = toupper(hex[0]);
40 hex2 = toupper(hex[1]);
42 if (hex1 < 65)
43 nibble1 = hex1 - 48;
44 else
45 nibble1 = hex1 - 55;
47 if (hex2 < 65)
48 nibble2 = hex2 - 48;
49 else
50 nibble2 = hex2 - 55;
52 return (nibble1 << 4 | nibble2);
56 unsigned char stmWaitAck(serialStruct_t *s, int retries) {
57 unsigned char c;
58 unsigned int i;
60 for (i = 0; i < retries; i++) {
61 if (serialAvailable(s)) {
62 c = serialRead(s);
63 if (c == 0x79) {
64 // putchar('+'); fflush(stdout);
65 return 1;
67 if (c == 0x1f) {
68 putchar('-'); fflush(stdout);
69 return 0;
71 else {
72 printf("?%x?", c); fflush(stdout);
73 return 0;
76 usleep(500);
79 return 0;
82 unsigned char stmWrite(serialStruct_t *s, const char *hex) {
83 unsigned char c;
84 unsigned char ck;
85 unsigned char i;
87 ck = 0;
88 i = 0;
89 while (*hex) {
90 c = stmHexToChar(hex);
91 serialWrite(s, (char *)&c, 1);
92 ck ^= c;
93 hex += 2;
94 i++;
96 if (i == 1)
97 ck = 0xff ^ c;
99 // send checksum
100 serialWrite(s, (char *)&ck, 1);
102 return stmWaitAck(s, STM_RETRIES_LONG);
105 void stmWriteCommand(serialStruct_t *s, char *msb, char *lsb, char *len, char *data) {
106 char startAddress[9];
107 char lenPlusData[128];
108 char c;
110 strncpy(startAddress, msb, sizeof(startAddress));
111 strcat(startAddress, lsb);
113 sprintf(lenPlusData, "%02x%s", stmHexToChar(len) - 1, data);
115 write:
116 // send WRITE MEMORY command
117 do {
118 c = getResults[5];
119 serialWrite(s, &c, 1);
120 c = 0xff ^ c;
121 serialWrite(s, &c, 1);
122 } while (!stmWaitAck(s, STM_RETRIES_LONG));
124 // send address
125 if (!stmWrite(s, startAddress)) {
126 putchar('A');
127 goto write;
130 // send len + data
131 if (!stmWrite(s, lenPlusData)) {
132 putchar('D');
133 goto write;
136 putchar('='); fflush(stdout);
139 char *stmHexLoader(serialStruct_t *s, FILE *fp) {
140 char hexByteCount[3], hexAddressLSB[5], hexRecordType[3], hexData[128];
141 char addressMSB[5];
142 static char addressJump[9];
144 // bzero(addressJump, sizeof(addressJump));
145 // bzero(addressMSB, sizeof(addressMSB));
146 memset(addressJump, 0, sizeof(addressJump));
147 memset(addressMSB, 0, sizeof(addressMSB));
149 while (fscanf(fp, ":%2s%4s%2s%s\n", hexByteCount, hexAddressLSB, hexRecordType, hexData) != EOF) {
150 unsigned int byteCount, addressLSB, recordType;
152 recordType = stmHexToChar(hexRecordType);
153 hexData[stmHexToChar(hexByteCount) * 2] = 0; // terminate at CHKSUM
155 // printf("Record Type: %d\n", recordType);
156 switch (recordType) {
157 case 0x00:
158 stmWriteCommand(s, addressMSB, hexAddressLSB, hexByteCount, hexData);
159 break;
160 case 0x01:
161 // EOF
162 return addressJump;
163 break;
164 case 0x04:
165 // MSB of destination 32 bit address
166 strncpy(addressMSB, hexData, 4);
167 break;
168 case 0x05:
169 // 32 bit address to run after load
170 strncpy(addressJump, hexData, 8);
171 break;
175 return 0;
178 void stmLoader(serialStruct_t *s, FILE *fp, unsigned char overrideParity, unsigned char noSendR) {
179 char c;
180 unsigned char b1, b2, b3;
181 unsigned char i, n;
182 char *jumpAddress;
184 // turn on parity generation
185 if (!overrideParity)
186 serialEvenParity(s);
188 if(!noSendR) {
189 top:
190 printf("Sending R to place Baseflight in bootloader, press a key to continue");
191 serialFlush(s);
192 c = 'R';
193 serialWrite(s, &c, 1);
194 getchar();
195 printf("\n");
198 serialFlush(s);
200 printf("Poking the MCU to check whether bootloader is alive...");
202 // poke the MCU
203 do {
204 printf("p"); fflush(stdout);
205 c = 0x7f;
206 serialWrite(s, &c, 1);
207 } while (!stmWaitAck(s, STM_RETRIES_SHORT));
208 printf("STM bootloader alive...\n");
210 // send GET command
211 do {
212 c = 0x00;
213 serialWrite(s, &c, 1);
214 c = 0xff;
215 serialWrite(s, &c, 1);
216 } while (!stmWaitAck(s, STM_RETRIES_LONG));
218 b1 = serialRead(s); // number of bytes
219 b2 = serialRead(s); // bootloader version
221 for (i = 0; i < b1; i++)
222 getResults[i] = serialRead(s);
224 stmWaitAck(s, STM_RETRIES_LONG);
225 printf("Received commands.\n");
228 // send GET VERSION command
229 do {
230 c = getResults[1];
231 serialWrite(s, &c, 1);
232 c = 0xff ^ c;
233 serialWrite(s, &c, 1);
234 } while (!stmWaitAck(s, STM_RETRIES_LONG));
235 b1 = serialRead(s);
236 b2 = serialRead(s);
237 b3 = serialRead(s);
238 stmWaitAck(s, STM_RETRIES_LONG);
239 printf("STM Bootloader version: %d.%d\n", (b1 & 0xf0) >> 4, (b1 & 0x0f));
241 // send GET ID command
242 do {
243 c = getResults[2];
244 serialWrite(s, &c, 1);
245 c = 0xff ^ c;
246 serialWrite(s, &c, 1);
247 } while (!stmWaitAck(s, STM_RETRIES_LONG));
248 n = serialRead(s);
249 printf("STM Device ID: 0x");
250 for (i = 0; i <= n; i++) {
251 b1 = serialRead(s);
252 printf("%02x", b1);
254 stmWaitAck(s, STM_RETRIES_LONG);
255 printf("\n");
258 flash_size:
259 // read Flash size
260 c = getResults[3];
261 serialWrite(s, &c, 1);
262 c = 0xff ^ c;
263 serialWrite(s, &c, 1);
265 // if read not allowed, unprotect (which also erases)
266 if (!stmWaitAck(s, STM_RETRIES_LONG)) {
267 // unprotect command
268 do {
269 c = getResults[10];
270 serialWrite(s, &c, 1);
271 c = 0xff ^ c;
272 serialWrite(s, &c, 1);
273 } while (!stmWaitAck(s, STM_RETRIES_LONG));
275 // wait for results
276 if (stmWaitAck(s, STM_RETRIES_LONG))
277 goto top;
280 // send address
281 if (!stmWrite(s, "1FFFF7E0"))
282 goto flash_size;
284 // send # bytes (N-1 = 1)
285 if (!stmWrite(s, "01"))
286 goto flash_size;
288 b1 = serialRead(s);
289 b2 = serialRead(s);
290 printf("STM Flash Size: %dKB\n", b2<<8 | b1);
293 // erase flash
294 erase_flash:
295 printf("Global flash erase [command 0x%x]...", getResults[6]); fflush(stdout);
296 do {
297 c = getResults[6];
298 serialWrite(s, &c, 1);
299 c = 0xff ^ c;
300 serialWrite(s, &c, 1);
301 } while (!stmWaitAck(s, STM_RETRIES_LONG));
303 // global erase
304 if (getResults[6] == 0x44) {
305 // mass erase
306 if (!stmWrite(s, "FFFF"))
307 goto erase_flash;
309 else {
310 c = 0xff;
311 serialWrite(s, &c, 1);
312 c = 0x00;
313 serialWrite(s, &c, 1);
315 if (!stmWaitAck(s, STM_RETRIES_LONG))
316 goto erase_flash;
319 printf("Done.\n");
321 // upload hex file
322 printf("Flashing device...\n");
323 jumpAddress = stmHexLoader(s, fp);
324 if (jumpAddress) {
325 printf("\nFlash complete, executing.\n");
328 // send GO command
329 do {
330 c = getResults[4];
331 serialWrite(s, &c, 1);
332 c = 0xff ^ c;
333 serialWrite(s, &c, 1);
334 } while (!stmWaitAck(s, STM_RETRIES_LONG));
336 // send address
337 if (!stmWrite(s, jumpAddress))
338 goto go;
340 else {
341 printf("\nFlash complete.\n");