APM:Libraries
serial_4way_avrootloader.cpp
Go to the documentation of this file.
1 /*
2 
3 (c) 2017 night_ghost@ykoctpa.ru
4 
5 based on:
6 
7  * from Cleanflight.
8  *
9  * for info about Hagens AVRootloader:
10  * http://www.mikrocontroller.net/topic/avr-bootloader-mit-verschluesselung
11 */
12 
13 #include <stdbool.h>
14 #include <stdint.h>
15 #include <string.h>
16 
17 #include "serial_4way.h"
18 
19 #ifdef USE_SERIAL_4WAY_BLHELI_INTERFACE
20 
21 #include <hal.h>
22 #include "serial_4way_impl.h"
24 
25 #if defined(USE_SERIAL_4WAY_BLHELI_BOOTLOADER)
26 
27 // Bootloader commands
28 // RunCmd
29 #define RestartBootloader 0
30 #define ExitBootloader 1
31 
32 #define CMD_RUN 0x00
33 #define CMD_PROG_FLASH 0x01
34 #define CMD_ERASE_FLASH 0x02
35 #define CMD_READ_FLASH_SIL 0x03
36 #define CMD_VERIFY_FLASH 0x03
37 #define CMD_VERIFY_FLASH_ARM 0x04
38 #define CMD_READ_EEPROM 0x04
39 #define CMD_PROG_EEPROM 0x05
40 #define CMD_READ_SRAM 0x06
41 #define CMD_READ_FLASH_ATM 0x07
42 #define CMD_KEEP_ALIVE 0xFD
43 #define CMD_SET_ADDRESS 0xFF
44 #define CMD_SET_BUFFER 0xFE
45 
46 #define CMD_BOOTINIT 0x07
47 #define CMD_BOOTSIGN 0x08
48 
49 
50 #define START_BIT_TIMEOUT_MS 2
51 
52 #define BIT_TIME (52) // 52uS
53 #define BIT_TIME_HALVE (BIT_TIME >> 1) // 26uS
54 #define BIT_TIME_3_4 (BIT_TIME_HALVE + (BIT_TIME_HALVE >> 1)) // 39uS
55 #define START_BIT_TIME (BIT_TIME_3_4)
56 //#define STOP_BIT_TIME ((BIT_TIME * 9) + BIT_TIME_HALVE)
57 
58 static uint8_t suart_getc_(uint8_t *bt)
59 {
60  uint32_t btime;
61  uint32_t start_time;
62 
63  uint32_t wait_time = millis() + START_BIT_TIMEOUT_MS;
64  while (ESC_IS_HI) {
65  // check for startbit begin
66  if (millis() >= wait_time) {
67  return 0;
68  }
69  }
70  // start bit
71  start_time = micros();
72  btime = start_time + START_BIT_TIME;
73  uint16_t bitmask = 0;
74  uint8_t bit = 0;
75  while (micros() < btime);
76  while(1) {
77  if (ESC_IS_HI)
78  {
79  bitmask |= (1 << bit);
80  }
81  btime = btime + BIT_TIME;
82  bit++;
83  if (bit == 10) break;
84  while (micros() < btime);
85  }
86  // check start bit and stop bit
87  if ((bitmask & 1) || (!(bitmask & (1 << 9)))) {
88  return 0;
89  }
90  *bt = bitmask >> 1;
91  return 1;
92 }
93 
94 static void suart_putc_(const uint8_t *tx_b)
95 {
96  // shift out stopbit first
97  uint16_t bitmask = (*tx_b << 2) | 1 | (1 << 10);
98  uint32_t btime = micros();
99  while(1) {
100  if(bitmask & 1) {
101  ESC_SET_HI; // 1
102  }
103  else {
104  ESC_SET_LO; // 0
105  }
106  btime = btime + BIT_TIME;
107  bitmask = (bitmask >> 1);
108  if (bitmask == 0) break; // stopbit shifted out - but don't wait
109  while (micros() < btime);
110  }
111 }
112 
113 static uint8_16_u CRC_16;
114 static uint8_16_u LastCRC_16;
115 
116 static void ByteCrc(const uint8_t *bt)
117 {
118  uint8_t xb = *bt;
119  for (uint8_t i = 0; i < 8; i++)
120  {
121  if (((xb & 0x01) ^ (CRC_16.word & 0x0001)) !=0 ) {
122  CRC_16.word = CRC_16.word >> 1;
123  CRC_16.word = CRC_16.word ^ 0xA001;
124  } else {
125  CRC_16.word = CRC_16.word >> 1;
126  }
127  xb = xb >> 1;
128  }
129 }
130 
131 static uint8_t BL_ReadBuf(uint8_t *pstring, uint8_t len)
132 {
133  // len 0 means 256
134  CRC_16.word = 0;
135  LastCRC_16.word = 0;
136  uint8_t LastACK = brNONE;
137  do {
138  if(!suart_getc_(pstring)) goto timeout;
139  ByteCrc(pstring);
140  pstring++;
141  len--;
142  } while(len > 0);
143 
144  if(isMcuConnected()) {
145  //With CRC read 3 more
146  if(!suart_getc_(&LastCRC_16.bytes[0])) goto timeout;
147  if(!suart_getc_(&LastCRC_16.bytes[1])) goto timeout;
148  if(!suart_getc_(&LastACK)) goto timeout;
149  if (CRC_16.word != LastCRC_16.word) {
150  LastACK = brERRORCRC;
151  }
152  } else {
153  if(!suart_getc_(&LastACK)) goto timeout;
154  }
155 timeout:
156  return (LastACK == brSUCCESS);
157 }
158 
159 static void BL_SendBuf(const uint8_t *pstring, uint8_t len)
160 {
161  ESC_OUTPUT;
162  CRC_16.word=0;
163  do {
164  suart_putc_(pstring);
165  ByteCrc(pstring);
166  pstring++;
167  len--;
168  } while (len > 0);
169 
170  if (isMcuConnected()) {
171  suart_putc_(&CRC_16.bytes[0]);
172  suart_putc_(&CRC_16.bytes[1]);
173  }
174  ESC_INPUT;
175 }
176 
177 uint8_t BL_ConnectEx(uint8_32_u *pDeviceInfo)
178 {
179  #define BootMsgLen 4
180  #define DevSignHi (BootMsgLen)
181  #define DevSignLo (BootMsgLen+1)
182 
183  //DeviceInfo.dword=0; is set before
184  uint8_t BootInfo[9];
185  uint8_t BootMsg[BootMsgLen+1] = "471";
186  // x * 0 + 9
187 #if defined(USE_SERIAL_4WAY_SK_BOOTLOADER)
188  static const uint8_t BootInit[] = {0,0,0,0,0,0,0,0,0,0,0,0,0x0D,'B','L','H','e','l','i',0xF4,0x7D};
189  BL_SendBuf(BootInit, 21);
190 #else
191  static const uint8_t BootInit[] = {0,0,0,0,0,0,0,0,0x0D,'B','L','H','e','l','i',0xF4,0x7D};
192  BL_SendBuf(BootInit, 17);
193 #endif
194  if (!BL_ReadBuf(BootInfo, BootMsgLen + 4)) {
195  return 0;
196  }
197  // BootInfo has no CRC (ACK byte already analyzed... )
198  // Format = BootMsg("471c") SIGNATURE_001, SIGNATURE_002, BootVersion (always 6), BootPages (,ACK)
199  for (uint8_t i = 0; i < (BootMsgLen - 1); i++) { // Check only the first 3 letters -> 471x OK
200  if (BootInfo[i] != BootMsg[i]) {
201  return (0);
202  }
203  }
204 
205  //only 2 bytes used $1E9307 -> 0x9307
206  pDeviceInfo->bytes[2] = BootInfo[BootMsgLen - 1];
207  pDeviceInfo->bytes[1] = BootInfo[DevSignHi];
208  pDeviceInfo->bytes[0] = BootInfo[DevSignLo];
209  return (1);
210 }
211 
212 static uint8_t BL_GetACK(uint32_t Timeout)
213 {
214  uint8_t LastACK = brNONE;
215  while (!(suart_getc_(&LastACK)) && (Timeout)) {
216  Timeout--;
217  } ;
218  return (LastACK);
219 }
220 
221 uint8_t BL_SendCMDKeepAlive(void)
222 {
223  uint8_t sCMD[] = {CMD_KEEP_ALIVE, 0};
224  BL_SendBuf(sCMD, 2);
225  if (BL_GetACK(1) != brERRORCOMMAND) {
226  return 0;
227  }
228  return 1;
229 }
230 
232 {
233  uint8_t sCMD[] = {RestartBootloader, 0};
234  pDeviceInfo->bytes[0] = 1;
235  BL_SendBuf(sCMD, 2); //sends simply 4 x 0x00 (CRC =00)
236  return;
237 }
238 
239 static uint8_t BL_SendCMDSetAddress(ioMem_t *pMem) //supports only 16 bit Adr
240 {
241  // skip if adr == 0xFFFF
242  if((pMem->D_FLASH_ADDR_H == 0xFF) && (pMem->D_FLASH_ADDR_L == 0xFF)) return 1;
243  uint8_t sCMD[] = {CMD_SET_ADDRESS, 0, pMem->D_FLASH_ADDR_H, pMem->D_FLASH_ADDR_L };
244  BL_SendBuf(sCMD, 4);
245  return (BL_GetACK(2) == brSUCCESS);
246 }
247 
248 static uint8_t BL_SendCMDSetBuffer(ioMem_t *pMem)
249 {
250  uint8_t sCMD[] = {CMD_SET_BUFFER, 0, 0, pMem->D_NUM_BYTES};
251  if (pMem->D_NUM_BYTES == 0) {
252  // set high byte
253  sCMD[2] = 1;
254  }
255  BL_SendBuf(sCMD, 4);
256  if (BL_GetACK(2) != brNONE) return 0;
257  BL_SendBuf(pMem->D_PTR_I, pMem->D_NUM_BYTES);
258  return (BL_GetACK(40) == brSUCCESS);
259 }
260 
261 static uint8_t BL_ReadA(uint8_t cmd, ioMem_t *pMem)
262 {
263  if (BL_SendCMDSetAddress(pMem)) {
264  uint8_t sCMD[] = {cmd, pMem->D_NUM_BYTES};
265  BL_SendBuf(sCMD, 2);
266  return (BL_ReadBuf(pMem->D_PTR_I, pMem->D_NUM_BYTES ));
267  }
268  return 0;
269 }
270 
271 static uint8_t BL_WriteA(uint8_t cmd, ioMem_t *pMem, uint32_t timeout)
272 {
273  if (BL_SendCMDSetAddress(pMem)) {
274  if (!BL_SendCMDSetBuffer(pMem)) return 0;
275  uint8_t sCMD[] = {cmd, 0x01};
276  BL_SendBuf(sCMD, 2);
277  return (BL_GetACK(timeout) == brSUCCESS);
278  }
279  return 0;
280 }
281 
282 uint8_t BL_ReadFlash(uint8_t interface_mode, ioMem_t *pMem)
283 {
284  if(interface_mode == imATM_BLB) {
285  return BL_ReadA(CMD_READ_FLASH_ATM, pMem);
286  } else {
287  return BL_ReadA(CMD_READ_FLASH_SIL, pMem);
288  }
289 }
290 
291 uint8_t BL_ReadEEprom(ioMem_t *pMem)
292 {
293  return BL_ReadA(CMD_READ_EEPROM, pMem);
294 }
295 
296 uint8_t BL_PageErase(ioMem_t *pMem)
297 {
298  if (BL_SendCMDSetAddress(pMem)) {
299  uint8_t sCMD[] = {CMD_ERASE_FLASH, 0x01};
300  BL_SendBuf(sCMD, 2);
301  return (BL_GetACK((1400 / START_BIT_TIMEOUT_MS)) == brSUCCESS);
302  }
303  return 0;
304 }
305 
306 uint8_t BL_WriteEEprom(ioMem_t *pMem)
307 {
308  return BL_WriteA(CMD_PROG_EEPROM, pMem, (3000 / START_BIT_TIMEOUT_MS));
309 }
310 
311 uint8_t BL_WriteFlash(ioMem_t *pMem)
312 {
313  return BL_WriteA(CMD_PROG_FLASH, pMem, (400 / START_BIT_TIMEOUT_MS));
314 }
315 
316 uint8_t BL_VerifyFlash(ioMem_t *pMem)
317 {
318  if (BL_SendCMDSetAddress(pMem)) {
319  if (!BL_SendCMDSetBuffer(pMem)) return 0;
320  uint8_t sCMD[] = {CMD_VERIFY_FLASH_ARM, 0x01};
321  BL_SendBuf(sCMD, 2);
322  return (BL_GetACK(40 / START_BIT_TIMEOUT_MS));
323  }
324  return 0;
325 }
326 
327 #endif
328 #endif
struct timespec start_time
Definition: system.cpp:16
uint8_t * D_PTR_I
uint8_t D_NUM_BYTES
uint8_t D_FLASH_ADDR_L
uint8_t BL_VerifyFlash(ioMem_t *pMem)
#define CMD_SET_ADDRESS
#define CMD_READ_EEPROM
#define brERRORCRC
uint8_32_u
Definition: serial_4way.h:36
#define imATM_BLB
uint8_t D_FLASH_ADDR_H
uint8_t BL_ReadEEprom(ioMem_t *pMem)
#define ESC_SET_LO
void BL_SendCMDRunRestartBootloader(uint8_32_u *pDeviceInfo)
#define ESC_OUTPUT
bool isMcuConnected(void)
#define CMD_KEEP_ALIVE
#define ESC_IS_HI
uint8_t BL_WriteEEprom(ioMem_t *pMem)
#define CMD_PROG_FLASH
uint8_t BL_SendCMDKeepAlive(void)
#define brNONE
uint8_16_u
Definition: serial_4way.h:30
#define brERRORCOMMAND
#define ESC_SET_HI
uint8_t BL_PageErase(ioMem_t *pMem)
uint32_t millis()
Definition: system.cpp:157
#define CMD_VERIFY_FLASH_ARM
#define CMD_READ_FLASH_ATM
uint8_t BL_ReadFlash(uint8_t interface_mode, ioMem_t *pMem)
#define CMD_READ_FLASH_SIL
#define CMD_ERASE_FLASH
uint8_t BL_WriteFlash(ioMem_t *pMem)
uint8_t BL_ConnectEx(uint8_32_u *pDeviceInfo)
#define RestartBootloader
uint32_t micros()
Definition: system.cpp:152
#define CMD_SET_BUFFER
#define CMD_PROG_EEPROM
#define brSUCCESS
#define ESC_INPUT