1 | /**
|
2 | * The common bootloader for RX and TX
|
3 | */
|
4 |
|
5 | #include <avr/io.h>
|
6 | #include <avr/interrupt.h>
|
7 | #include <avr/pgmspace.h>
|
8 | #include <avr/eeprom.h>
|
9 | #include <avr/boot.h>
|
10 | #include <stdlib.h>
|
11 | #include <string.h>
|
12 | #include <util/crc16.h>
|
13 | #include <avr/wdt.h>
|
14 |
|
15 | #include "../global_files/avr_helper.h"
|
16 |
|
17 | #if defined(_TYPE_1001_) || defined(_TYPE_1002_) || defined(_TYPE_1004_)
|
18 | #warning "compiling mega32"
|
19 | #define RESET_SOURCE_MASK (_BV(JTRF)|_BV(WDRF)|_BV(BORF)|_BV(EXTRF)|_BV(PORF))
|
20 | #elif _TYPE_1003_
|
21 | #warning "compiling mega328(p)"
|
22 | #define RESET_SOURCE_MASK (_BV(WDRF)|_BV(BORF)|_BV(EXTRF)|_BV(PORF))
|
23 | #elif _TYPE_1006_
|
24 | #warning "compiling mega1284p"
|
25 | #define RESET_SOURCE_MASK (_BV(WDRF)|_BV(BORF)|_BV(EXTRF)|_BV(PORF))
|
26 | #else
|
27 | #error "This code is not yet done for this module type"
|
28 | #endif
|
29 |
|
30 | char rxbuffer_boot[SPM_PAGESIZE*2+20]; // This is a hughe array, but we are in the bootloader and have all for us
|
31 | char txbuffer[40];
|
32 | uint16_t rxpos_boot = 0; // anzahl empfangener Zeichen
|
33 | uint8_t txpos = 0; // anzahl zu sendender Zeichen
|
34 | uint8_t txspos = 0; // nächstes zu senden
|
35 | uint8_t myAddress = MY_DEF_ADDR; // unsere Adresse
|
36 | uint32_t page = 0;
|
37 | uint16_t crc = 0;
|
38 | uint16_t shouldCrc = 0;
|
39 |
|
40 | /**
|
41 | * The different states of the bootloader
|
42 | */
|
43 | enum
|
44 | {
|
45 | BOOT_CMD = 1,
|
46 | BOOT_DATA,
|
47 | BOOT_CHK
|
48 | };
|
49 |
|
50 | #define PROGMEM_CRC_ADDR 0x0000
|
51 |
|
52 | void (*startMainApp)( void ) = 0x0000; /* Funktionspointer auf 0x0000 */
|
53 |
|
54 | /*
|
55 | FUSES =
|
56 | {
|
57 | .low = 0xFF, // 0xff
|
58 | .high = ( FUSE_EESAVE & FUSE_SPIEN & FUSE_CKOPT & FUSE_BOOTSZ1 & FUSE_BOOTSZ0 ) // 0xc1
|
59 | };
|
60 | */
|
61 | #if defined(_TYPE_1001_) || defined(_TYPE_1002_) || defined(_TYPE_1004_)
|
62 | FUSES =
|
63 | {
|
64 | 0xFF,
|
65 | ( FUSE_EESAVE & FUSE_SPIEN & FUSE_CKOPT & FUSE_BOOTSZ1 & FUSE_BOOTSZ0 ) // 0xc1
|
66 | //EFUSE_DEFAULT
|
67 | };
|
68 | #elif defined (_TYPE_1006_) || defined (_TYPE_1003_)
|
69 | FUSES =
|
70 | {
|
71 | 0xFD,
|
72 | ( FUSE_EESAVE & FUSE_SPIEN & FUSE_BOOTSZ1 & FUSE_BOOTSZ0 ), // 0xc1
|
73 | 0xFF
|
74 | //EFUSE_DEFAULT
|
75 | };
|
76 | #endif
|
77 | void ( *bootloader ) ( void ) = (void(*)(void))0x3800;
|
78 |
|
79 |
|
80 | /**
|
81 | * converts AH to uint8_t value
|
82 | */
|
83 | uint8_t ahtoUint8 ( uint8_t *data )
|
84 | {
|
85 | uint8_t val = 0;
|
86 |
|
87 | for ( uint8_t i = 0 ; i < 2 ; i++ )
|
88 | {
|
89 | if ( ( data[i] >= '0' ) && ( data[i] <= '9' ) )
|
90 | val = ( val * 16 ) + ( data[i] - '0' );
|
91 | else if ( ( data[i] >= 'a' ) && ( data[i] <= 'f' ) )
|
92 | val = ( val * 16 ) + ( data[i] - 'a' + 0x0a );
|
93 | else
|
94 | break;
|
95 | }
|
96 |
|
97 | return val;
|
98 | }
|
99 |
|
100 | /**
|
101 | * converts AH to uint16_t value
|
102 | */
|
103 | uint16_t ahtoUint16 ( uint8_t *data )
|
104 | {
|
105 | uint16_t val = 0;
|
106 |
|
107 | for ( uint8_t i = 0 ; i < 4 ; i++ )
|
108 | {
|
109 | if ( ( data[i] >= '0' ) && ( data[i] <= '9' ) )
|
110 | val = ( val * 16 ) + ( data[i] - '0' );
|
111 | else if ( ( data[i] >= 'a' ) && ( data[i] <= 'f' ) )
|
112 | val = ( val * 16 ) + ( data[i] - 'a' + 0x0a );
|
113 | else
|
114 | break;
|
115 | }
|
116 |
|
117 | return val;
|
118 | }
|
119 |
|
120 | /**
|
121 | * convert uint16_t to AH. The result is stored in buffer
|
122 | */
|
123 | char* uint16ToAh ( char *buffer, uint16_t val )
|
124 | {
|
125 | uint16_t t = val;
|
126 | uint8_t z;
|
127 |
|
128 | for ( uint8_t i = 0 ; i < 4 ; i++ )
|
129 | {
|
130 | z = ( uint8_t ) ( ( t & 0xF000 ) >> 12 );
|
131 | t = t << 4;
|
132 |
|
133 | if ( ( z >= 0 ) && ( z <= 9 ) )
|
134 | buffer[i] = z + '0';
|
135 | else if ( ( z >= 0x0a ) && ( z <= 0x0f ) )
|
136 | buffer[i] = z + 'a' - 10;
|
137 | }
|
138 |
|
139 | buffer[4] = 0;
|
140 |
|
141 | return buffer;
|
142 | }
|
143 |
|
144 | /**
|
145 | * convert uint8_t to AH. The result is stored in buffer
|
146 | */
|
147 | char* uint8ToAh ( char *buffer, uint8_t val )
|
148 | {
|
149 | uint8_t t = val;
|
150 | uint8_t z;
|
151 |
|
152 | for ( uint8_t i = 0 ; i < 2 ; i++ )
|
153 | {
|
154 | z = ( uint8_t ) ( ( t & 0xF0 ) >> 4 );
|
155 | t = t << 4;
|
156 |
|
157 | if ( ( z >= 0 ) && ( z <= 9 ) )
|
158 | buffer[i] = z + '0';
|
159 | else if ( ( z >= 0x0a ) && ( z <= 0x0f ) )
|
160 | buffer[i] = z + 'a' - 10;
|
161 | }
|
162 |
|
163 | buffer[2] = 0;
|
164 |
|
165 | return buffer;
|
166 | }
|
167 |
|
168 | /**
|
169 | * Append Zero terminated string to TX buffer
|
170 | */
|
171 | void uartPuts(const char *sb)
|
172 | {
|
173 | int len = strlen(sb);
|
174 | if ((txpos+len) < sizeof(txbuffer))
|
175 | {
|
176 | strcat(txbuffer, sb);
|
177 | txpos+=strlen(sb);
|
178 | }
|
179 | }
|
180 |
|
181 | #define MSG "BOOT" /*SPM_PAGESIZE "\r\n"*/
|
182 |
|
183 | /**
|
184 | * setup UART comm port
|
185 | */
|
186 | void initUart(uint16_t baud)
|
187 | {
|
188 | uint16_t ubrr = ( uint16_t ) ( ( ( uint32_t ) F_CPU / ( 16UL * baud ) ) - 1 );
|
189 |
|
190 | #if defined(_TYPE_1001_) || defined(_TYPE_1002_) || defined(_TYPE_1004_)
|
191 | UBRRH = ( uint8_t ) ( ubrr << 8 ) & 0x0F;
|
192 | UBRRL = ( uint8_t ) ( ubrr & 0xFF );
|
193 |
|
194 | UCSRA = _BVC(U2X) | _BVC(MPCM);
|
195 |
|
196 | UCSRB = _BV ( RXEN ) | _BV ( TXEN ) | _BVC( RXCIE ) | _BVC(UCSZ2);
|
197 |
|
198 | UCSRC = _BV ( URSEL ) | _BVC(UMSEL) | _BV ( UCSZ1 ) | _BV ( UCSZ0 ) | _BVC(USBS) | _BVC(UPM1) | _BVC(UPM0) | _BVC(UCPOL);
|
199 | #elif defined (_TYPE_1006_) || defined (_TYPE_1003_)
|
200 | UBRR0H = ( uint8_t ) ( ubrr << 8 ) & 0x0F;
|
201 | UBRR0L = ( uint8_t ) ( ubrr & 0xFF );
|
202 |
|
203 | UCSR0A = _BVC(U2X0) | _BVC(MPCM0);
|
204 |
|
205 | UCSR0B = _BV ( RXEN0 ) | _BV ( TXEN0 ) | _BVC( RXCIE0 ) | _BVC(UCSZ02);
|
206 |
|
207 | UCSR0C = _BVC ( UMSEL01 ) | _BVC(UMSEL00) | _BV ( UCSZ01 ) | _BV ( UCSZ00 ) | _BVC(USBS0) | _BVC(UPM01) | _BVC(UPM00) | _BVC(UCPOL0);
|
208 | #endif
|
209 | }
|
210 |
|
211 |
|
212 |
|
213 | /**
|
214 | * write a buffer to flash page.
|
215 | * This is 1:1 from the avrlibc documentation
|
216 | */
|
217 | void boot_program_page (uint32_t page, uint8_t *buf)
|
218 | {
|
219 | uint16_t i;
|
220 | uint8_t sreg;
|
221 |
|
222 | uint8_t z='0'+page;
|
223 |
|
224 | // Disable interrupts.
|
225 |
|
226 | sreg = SREG;
|
227 | cli();
|
228 |
|
229 | eeprom_busy_wait ();
|
230 |
|
231 | boot_page_erase (page);
|
232 | boot_spm_busy_wait (); // Wait until the memory is erased.
|
233 |
|
234 | for (i=0; i<SPM_PAGESIZE; i+=2)
|
235 | {
|
236 | // Set up little-endian word.
|
237 |
|
238 | uint16_t w = *buf++;
|
239 | w += (*buf++) << 8;
|
240 |
|
241 | boot_page_fill (page + i, w);
|
242 | }
|
243 |
|
244 | boot_page_write (page); // Store buffer in flash page.
|
245 | boot_spm_busy_wait(); // Wait until the memory is written.
|
246 |
|
247 | // Reenable RWW-section again. We need this if we want to jump back
|
248 | // to the application after bootloading.
|
249 |
|
250 | boot_rww_enable ();
|
251 |
|
252 | // Re-enable interrupts (if they were ever enabled).
|
253 |
|
254 | SREG = sreg;
|
255 | }
|
256 |
|
257 | /**
|
258 | * Send the header of a command
|
259 | */
|
260 | void sendHeader(uint8_t toAddr)
|
261 | {
|
262 | char buffer[6];
|
263 | uartPuts("@");
|
264 | uartPuts(uint8ToAh(buffer, toAddr));
|
265 | uartPuts(uint8ToAh(buffer, myAddress));
|
266 | }
|
267 |
|
268 | /**
|
269 | * send module ID
|
270 | */
|
271 | void sendModuleID(uint8_t toAddr)
|
272 | {
|
273 | char buffer[6];
|
274 | sendHeader(toAddr);
|
275 | uartPuts("T");
|
276 | uartPuts(uint16ToAh(buffer, MODULE_ID));
|
277 | uartPuts("\r");
|
278 | }
|
279 |
|
280 | /**
|
281 | * Send flash page size
|
282 | * This is used by the app to adjust data send
|
283 | */
|
284 | void sendPageSize(uint8_t toAddr)
|
285 | {
|
286 | char buffer[6];
|
287 | sendHeader(toAddr);
|
288 | uartPuts("BT");
|
289 | uartPuts(uint16ToAh(buffer, SPM_PAGESIZE));
|
290 | uartPuts("\r");
|
291 | }
|
292 |
|
293 | /**
|
294 | * Send ACK for reboot command
|
295 | */
|
296 | void sendRebootACK(uint8_t toAddr)
|
297 | {
|
298 | char buffer[6];
|
299 | sendHeader(toAddr);
|
300 | uartPuts("RTA");
|
301 | uartPuts("\r");
|
302 | }
|
303 |
|
304 | /**
|
305 | * Send Bot loader ACK
|
306 | */
|
307 | void sendBootloaderACK(uint8_t toAddr)
|
308 | {
|
309 | char buffer[6];
|
310 | sendHeader(toAddr);
|
311 | uartPuts("BLA");
|
312 | uartPuts(uint16ToAh(buffer, page));
|
313 | uartPuts("\r");
|
314 | }
|
315 |
|
316 | /**
|
317 | * Send bootloader NACK
|
318 | */
|
319 | void sendBootloaderNACKcrc(uint8_t toAddr)
|
320 | {
|
321 | char buffer[6];
|
322 | sendHeader(toAddr);
|
323 | uartPuts("BLNcrc");
|
324 | uartPuts(uint16ToAh(buffer, crc));
|
325 | uartPuts(",sh ");
|
326 | uartPuts(uint16ToAh(buffer, shouldCrc));
|
327 | uartPuts("\r");
|
328 | }
|
329 |
|
330 | /**
|
331 | * Send Prog CRC
|
332 | */
|
333 | void sendProgCRC(uint8_t toAddr, uint16_t crc)
|
334 | {
|
335 | char buffer[6];
|
336 | sendHeader(toAddr);
|
337 | uartPuts("CRC");
|
338 | uartPuts(uint16ToAh(buffer, crc));
|
339 | uartPuts(uint16ToAh(buffer, eeprom_read_word(PROGMEM_CRC_ADDR)));
|
340 | uartPuts("\r");
|
341 | }
|
342 |
|
343 | void sendBootloaderNACK(uint8_t toAddr)
|
344 | {
|
345 | char buffer[6];
|
346 | sendHeader(toAddr);
|
347 | uartPuts("BLN");
|
348 | uartPuts("\r");
|
349 | }
|
350 |
|
351 | /**
|
352 | * Send Bootloader start downbload ACK or NACK
|
353 | */
|
354 | void sendBootloaderStartACK(uint8_t toAddr, uint8_t ack)
|
355 | {
|
356 | char buffer[6];
|
357 | sendHeader(toAddr);
|
358 | if (ack)
|
359 | uartPuts("BSA\r");
|
360 | else
|
361 | uartPuts("BSN\r");
|
362 | }
|
363 |
|
364 |
|
365 | uint8_t doTransmitUart(void)
|
366 | {
|
367 | // Handle transmit data
|
368 | #if defined(_TYPE_1001_) || defined(_TYPE_1002_) || defined(_TYPE_1004_)
|
369 | if ((txpos > 0) && (UCSRA & _BV(UDRE)))
|
370 | #elif defined (_TYPE_1006_) || defined (_TYPE_1003_)
|
371 | if ((txpos > 0) && (UCSR0A & _BV(UDRE0)))
|
372 | #endif
|
373 | {
|
374 | #if defined(_TYPE_1001_) || defined(_TYPE_1002_) || defined(_TYPE_1004_)
|
375 | UDR = txbuffer[txspos];
|
376 | #elif defined (_TYPE_1006_) || defined (_TYPE_1003_)
|
377 | UDR0 = txbuffer[txspos];
|
378 | #endif
|
379 | txspos++;
|
380 |
|
381 | if (txspos >= txpos)
|
382 | {
|
383 | txspos = 0;
|
384 | txpos = 0;
|
385 | txbuffer[0] = 0;
|
386 | }
|
387 | }
|
388 | return txpos;
|
389 | }
|
390 |
|
391 | /**
|
392 | * Caclulate program CRC
|
393 | * This function calculate the CRC over all program space
|
394 | */
|
395 | uint16_t calcProgCRC(void)
|
396 | {
|
397 | crc = 0;
|
398 | for (uint16_t i=0; i<(BOOTLOADER_ADR); i++)
|
399 | {
|
400 | crc = _crc_xmodem_update(crc, pgm_read_byte ( i ));
|
401 | }
|
402 | return crc;
|
403 | }
|
404 |
|
405 |
|
406 |
|
407 | /**
|
408 | * Our main loop
|
409 | */
|
410 | int main ( void )
|
411 | {
|
412 | #if defined(_TYPE_1001_) || defined(_TYPE_1002_) || defined(_TYPE_1004_)
|
413 | uint8_t resetSource = MCUCSR & RESET_SOURCE_MASK;
|
414 | MCUCSR &= ~RESET_SOURCE_MASK;
|
415 | #elif defined (_TYPE_1006_) || defined (_TYPE_1003_)
|
416 | uint8_t resetSource = MCUSR & RESET_SOURCE_MASK;
|
417 | MCUSR &= ~RESET_SOURCE_MASK;
|
418 | #endif
|
419 | wdt_disable(); // Important or we risk a mess
|
420 | cli();
|
421 |
|
422 |
|
423 | initUart ( 38400 );
|
424 |
|
425 |
|
426 | uint8_t status = BOOT_CMD;
|
427 | uint8_t toAddr = 0x00;
|
428 | uint8_t fromAddr = myAddress;
|
429 | uint16_t fwsize = 0; // size of fw to load
|
430 | uint16_t rxfwsize = 0; // size of received size
|
431 | char buffer[10];
|
432 | uint8_t cmd_rx = 0;
|
433 |
|
434 | // we just forced into boot loader
|
435 | // aCK this and report page size !
|
436 | //sendModuleID(toAddr);
|
437 | //while (doTransmitUart());
|
438 | uint16_t iscrc = calcProgCRC();
|
439 | sendProgCRC(ADDR_BROADCAST_DEF, iscrc);
|
440 | while(doTransmitUart());
|
441 |
|
442 | sendPageSize(ADDR_BROADCAST_DEF);
|
443 | while (doTransmitUart()); // Empty TX buffer
|
444 |
|
445 | while ( 1 )
|
446 | {
|
447 | /*
|
448 | * IF get this far without any reset source set,
|
449 | * we are directly called by the main app
|
450 | * So we have to skip the CRC check and directly continue with the bootloader
|
451 | */
|
452 | if (resetSource != 0) // not jumped in on purpose (from main app)
|
453 | {
|
454 | /*
|
455 | * We have come here after a reset. We now check the CRC of tzhe program
|
456 | * If it is ok, we will start the main app. If not, we will continue
|
457 | * with the boot loader
|
458 | */
|
459 | if (iscrc == eeprom_read_word(PROGMEM_CRC_ADDR))
|
460 | {
|
461 | static uint16_t delay=0xffff;
|
462 | delay--;
|
463 | if (delay == 0)
|
464 | {
|
465 | sendHeader(ADDR_BROADCAST_DEF);
|
466 | uartPuts("MPCRCOk\r");
|
467 | startMainApp(); // reboot into main prog
|
468 | }
|
469 | }
|
470 | else
|
471 | {
|
472 | sendHeader(ADDR_BROADCAST_DEF);
|
473 | //uartPuts("MPCRCErr\r");
|
474 | }
|
475 | }
|
476 | while (doTransmitUart()); // Empty TX buffer
|
477 |
|
478 | // Handle receive data
|
479 | char c = 0;
|
480 | #if defined(_TYPE_1001_) || defined(_TYPE_1002_) || defined(_TYPE_1004_)
|
481 | if (UCSRA & _BV(RXC))
|
482 | {
|
483 | c = UDR;
|
484 | #elif defined (_TYPE_1006_) || defined (_TYPE_1003_)
|
485 | if (UCSR0A & _BV(RXC0))
|
486 | {
|
487 | c = UDR0;
|
488 | #endif
|
489 | rxbuffer_boot[rxpos_boot] = c;
|
490 | rxpos_boot++;
|
491 | if (c == '\r')
|
492 | {
|
493 | resetSource = 0; // Stay here
|
494 | cmd_rx = 1;
|
495 | }
|
496 | if (rxpos_boot > sizeof(rxbuffer_boot))
|
497 | {
|
498 | rxpos_boot=0;
|
499 | }
|
500 |
|
501 | }
|
502 | doTransmitUart();
|
503 | if (cmd_rx == 1)
|
504 | {
|
505 | uint8_t error = 0;
|
506 | // If the syntax is not correct, we will simply ignore the rest and fall through.
|
507 | if ((rxbuffer_boot[0] == '@') || (rxpos_boot >= 7)) // "@" + <adr> + B + <cmd> + <optional data>
|
508 | {
|
509 | toAddr = ahtoUint8((uint8_t*)&rxbuffer_boot[1]);
|
510 | fromAddr = ahtoUint8((uint8_t*)&rxbuffer_boot[3]);
|
511 | if ((toAddr == myAddress) || (toAddr == ADDR_BROADCAST_DEF))
|
512 | {
|
513 | // Ok, this is a message for us !
|
514 | if ((rxbuffer_boot[5] == 'T') && (rxbuffer_boot[6] == '?'))
|
515 | {
|
516 | sendModuleID(fromAddr);
|
517 | }
|
518 | else if ((rxbuffer_boot[5] == 'R') && (rxbuffer_boot[6] == 'T'))
|
519 | {
|
520 | sendRebootACK(fromAddr);
|
521 | wdt_enable(WDTO_250MS);
|
522 | }
|
523 | else if (0) //(rxbuffer_boot[5] == 'D') && (rxbuffer_boot[6] == 'F'))
|
524 | {
|
525 | for (uint16_t s=0; s<(0x7fff) ; s+=SPM_PAGESIZE)
|
526 | {
|
527 | uartPuts("\r\n");
|
528 | uartPuts(uint16ToAh(buffer, s));
|
529 | uartPuts(">");
|
530 |
|
531 | while (txpos)
|
532 | doTransmitUart();
|
533 |
|
534 |
|
535 | for (uint8_t b=0; b<SPM_PAGESIZE ; b++)
|
536 | {
|
537 | uartPuts(uint8ToAh(buffer, pgm_read_byte((uint8_t*)(b+s)) ));
|
538 |
|
539 | while (txpos)
|
540 | doTransmitUart();
|
541 | }
|
542 | }
|
543 | }
|
544 | else if ((rxbuffer_boot[5] == 'B') && (rxbuffer_boot[6] == 'T'))
|
545 | {
|
546 | sendPageSize(fromAddr);
|
547 | //startMainApp();
|
548 | //bootloader(); // jump back from bootloader to bootloader, does make sense ? :-)
|
549 | }
|
550 | else if ((rxbuffer_boot[5] == 'B') && (rxbuffer_boot[6] == 'P'))
|
551 | {
|
552 | //sendPageSize(fromAddr);
|
553 | startMainApp();
|
554 | //bootloader(); // jump back from bootloader to bootloader, does make sense ? :-)
|
555 | }
|
556 | else if ((rxbuffer_boot[5] == 'B') && (rxbuffer_boot[6] == 'L') && (rxpos_boot >= 9))
|
557 | {
|
558 | uint8_t bytecnt = ahtoUint8((uint8_t*)&rxbuffer_boot[7]);
|
559 | uint8_t offset = 9;
|
560 | if (rxpos_boot >= ((bytecnt*2)+offset+4))
|
561 | {
|
562 | uint16_t pos;
|
563 | // reformat data to binary
|
564 | // we reuse the rx array, as we are sure no additional data comes in (we are stuck here, right !)
|
565 | // this is save
|
566 | crc = 0;
|
567 | for (uint16_t i = 0 ; i < bytecnt ; i++)
|
568 | {
|
569 | pos = (i*2)+offset;
|
570 | rxbuffer_boot[i] = ahtoUint8((uint8_t*)&rxbuffer_boot[pos]);
|
571 | crc = _crc_xmodem_update(crc, rxbuffer_boot[i]);
|
572 | }
|
573 |
|
574 | rxfwsize+=bytecnt;
|
575 |
|
576 | // get should crc
|
577 | pos = (bytecnt*2)+offset;
|
578 | shouldCrc = ahtoUint16((uint8_t*)&rxbuffer_boot[pos]);
|
579 |
|
580 | // Fill remainder of page
|
581 | if (bytecnt < SPM_PAGESIZE)
|
582 | {
|
583 | for (uint16_t i = bytecnt ; i < SPM_PAGESIZE ; i++)
|
584 | rxbuffer_boot[i] = 0xFF; // Will be ignored by CPU !
|
585 | }
|
586 |
|
587 | if (crc == shouldCrc)
|
588 | {
|
589 | // now write flash
|
590 | boot_program_page(page, (uint8_t*)rxbuffer_boot);
|
591 |
|
592 | page+=SPM_PAGESIZE;
|
593 |
|
594 | if (rxfwsize >= fwsize)
|
595 | {
|
596 | uint16_t iscrc = calcProgCRC();
|
597 | eeprom_write_word((uint16_t*)PROGMEM_CRC_ADDR, iscrc);
|
598 | sendProgCRC(ADDR_BROADCAST_DEF, iscrc);
|
599 | }
|
600 |
|
601 | sendBootloaderACK(fromAddr);
|
602 |
|
603 | }
|
604 | else
|
605 | {
|
606 | sendBootloaderNACKcrc(fromAddr);
|
607 | }
|
608 | }
|
609 | else
|
610 | {
|
611 | sendBootloaderNACK(fromAddr);
|
612 | }
|
613 | }
|
614 | else if ((rxbuffer_boot[5] == 'B') && (rxbuffer_boot[6] == 'S') && (rxpos_boot >= 15))
|
615 | {
|
616 | uint16_t id = ahtoUint16((uint8_t*)&rxbuffer_boot[7]);
|
617 | if (id == MODULE_ID)
|
618 | {
|
619 | fwsize = ahtoUint16((uint8_t*)&rxbuffer_boot[11]);
|
620 | if (fwsize > 0)
|
621 | {
|
622 | sendBootloaderStartACK(fromAddr, 1);
|
623 | page = 0;
|
624 | }
|
625 | else
|
626 | {
|
627 | error = 2;
|
628 | }
|
629 | }
|
630 | else
|
631 | error = 1;
|
632 | if (error)
|
633 | {
|
634 | sendBootloaderStartACK(fromAddr, 0);
|
635 | }
|
636 | }
|
637 | else
|
638 | {
|
639 | //sendUnknownCmd(fromAddr);
|
640 | }
|
641 | }
|
642 | }
|
643 | rxpos_boot = 0;
|
644 | cmd_rx = 0;
|
645 | }
|
646 | }
|
647 | }
|