Rev 1307 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1127 | - | 1 | /***************************************************************************** |
2 | * |
||
3 | * AVRPROG compatible boot-loader |
||
4 | * Version : 0.85 (Dec. 2008) |
||
5 | * Compiler : avr-gcc 4.1.2 / avr-libc 1.4.6 |
||
6 | * size : depends on features and startup ( minmal features < 512 words) |
||
7 | * by : Martin Thomas, Kaiserslautern, Germany |
||
8 | * eversmith@heizung-thomas.de |
||
9 | * Additional code and improvements contributed by: |
||
10 | * - Uwe Bonnes |
||
11 | * - Bjoern Riemer |
||
12 | * - Olaf Rempel |
||
13 | * |
||
14 | * License : Copyright (c) 2006-2008 M. Thomas, U. Bonnes, O. Rempel |
||
15 | * Free to use. You have to mention the copyright |
||
16 | * owners in source-code and documentation of derived |
||
17 | * work. No warranty! (Yes, you can insert the BSD |
||
18 | * license here) |
||
19 | * |
||
20 | * Tested with ATmega8, ATmega16, ATmega162, ATmega32, ATmega324P, |
||
21 | * ATmega644, ATmega644P, ATmega128, AT90CAN128 |
||
22 | * |
||
23 | * - Initial versions have been based on the Butterfly bootloader-code |
||
24 | * by Atmel Corporation (Authors: BBrandal, PKastnes, ARodland, LHM) |
||
25 | * |
||
26 | **************************************************************************** |
||
27 | * |
||
28 | * See the makefile and readme.txt for information on how to adapt |
||
29 | * the linker-settings to the selected Boot Size (BOOTSIZE=xxxx) and |
||
30 | * the MCU-type. Other configurations futher down in this file. |
||
31 | * |
||
32 | * With BOOT_SIMPLE, minimal features and discarded int-vectors |
||
33 | * this bootloader has should fit into a a 512 word (1024, 0x400 bytes) |
||
34 | * bootloader-section. |
||
35 | * |
||
36 | ****************************************************************************/ |
||
37 | /* |
||
38 | TODOs: |
||
39 | - check lock-bits set |
||
40 | - __bad_interrupt still linked even with modified |
||
41 | linker-scripts which needs a default-handler, |
||
42 | "wasted": 3 words for AVR5 (>8kB), 2 words for AVR4 |
||
43 | - Check watchdog-disable-function in avr-libc. |
||
44 | */ |
||
45 | // tabsize: 4 |
||
46 | |||
47 | // Fuses ATmega 644P D7 DC FC |
||
48 | |||
49 | |||
50 | /* MCU frequency */ |
||
51 | #ifndef F_CPU |
||
52 | // #define F_CPU 7372800 |
||
53 | #define F_CPU (20000000) |
||
54 | #endif |
||
55 | |||
56 | #define BOOTSIZE 1024 |
||
57 | |||
58 | #define set_LED1() (PORTC &= ~(1 << PC3)) |
||
59 | #define clr_LED1() (PORTC |= (1 << PC3)) |
||
60 | #define set_LED2() (PORTC &= ~(1 << PC2)) |
||
61 | #define clr_LED2() (PORTC |= (1 << PC2)) |
||
62 | #define set_LED3() (PORTB &= ~(1 << PB1)) |
||
63 | #define clr_LED3() (PORTB |= (1 << PB1)) |
||
64 | #define set_LED4() (PORTB &= ~(1 << PB0)) |
||
65 | #define clr_LED4() (PORTB |= (1 << PB0)) |
||
66 | |||
67 | /* UART Baudrate */ |
||
68 | // #define BAUDRATE 9600 |
||
69 | // #define BAUDRATE 19200 |
||
70 | #define BAUDRATE 115200 |
||
71 | |||
72 | /* use "Double Speed Operation" */ |
||
73 | //#define UART_DOUBLESPEED |
||
74 | |||
75 | /* use second UART on mega128 / can128 / mega162 / mega324p / mega644p */ |
||
76 | #define UART_USE_SECOND |
||
77 | |||
78 | /* Device-Type: |
||
79 | For AVRProg the BOOT-option is prefered |
||
80 | which is the "correct" value for a bootloader. |
||
81 | avrdude may only detect the part-code for ISP */ |
||
82 | #define DEVTYPE DEVTYPE_BOOT |
||
83 | // #define DEVTYPE DEVTYPE_ISP |
||
84 | |||
85 | /* |
||
86 | * Pin "STARTPIN" on port "STARTPORT" in this port has to grounded |
||
87 | * (active low) to start the bootloader |
||
88 | */ |
||
89 | #define BLPORT PORTA |
||
90 | #define BLDDR DDRA |
||
91 | #define BLPIN PINA |
||
92 | #define BLPNUM PINA4 |
||
93 | |||
94 | /* |
||
95 | * Define if Watchdog-Timer should be disable at startup |
||
96 | */ |
||
97 | #define DISABLE_WDT_AT_STARTUP |
||
98 | |||
99 | /* |
||
100 | * Watchdog-reset is issued at exit |
||
101 | * define the timeout-value here (see avr-libc manual) |
||
102 | */ |
||
103 | #define EXIT_WDT_TIME WDTO_250MS |
||
104 | |||
105 | /* |
||
106 | * Select startup-mode |
||
107 | * SIMPLE-Mode - Jump to bootloader main BL-loop if key is |
||
108 | * pressed (Pin grounded) "during" reset or jump to the |
||
109 | * application if the pin is not grounded. The internal |
||
110 | * pull-up resistor is enabled during the startup and |
||
111 | * gets disabled before the application is started. |
||
112 | * POWERSAVE-Mode - Startup is separated in two loops |
||
113 | * which makes power-saving a little easier if no firmware |
||
114 | * is on the chip. Needs more memory |
||
115 | * BOOTICE-Mode - to flash the JTAGICE upgrade.ebn file. |
||
116 | * No startup-sequence in this mode. Jump directly to the |
||
117 | * parser-loop on reset |
||
118 | * F_CPU in BOOTICEMODE must be 7372800 Hz to be compatible |
||
119 | * with the org. JTAGICE-Firmware |
||
120 | * WAIT-mode waits 1 sec for the defined character if nothing |
||
121 | * is recived then the user prog is started. |
||
122 | */ |
||
123 | #define START_SIMPLE |
||
124 | //#define START_WAIT |
||
125 | //#define START_POWERSAVE |
||
126 | //#define START_BOOTICE |
||
127 | |||
128 | /* character to start the bootloader in mode START_WAIT */ |
||
129 | #define START_WAIT_UARTCHAR 'S' |
||
130 | |||
131 | /* wait-time for START_WAIT mode ( t = WAIT_TIME * 10ms ) */ |
||
132 | #define WAIT_VALUE 100 /* here: 100*10ms = 1000ms = 1sec */ |
||
133 | |||
134 | /* |
||
135 | * enable/disable readout of fuse and lock-bits |
||
136 | * (AVRPROG has to detect the AVR correctly by device-code |
||
137 | * to show the correct information). |
||
138 | */ |
||
139 | //#define ENABLEREADFUSELOCK |
||
140 | |||
141 | /* enable/disable write of lock-bits |
||
142 | * WARNING: lock-bits can not be reseted by bootloader (as far as I know) |
||
143 | * Only protection no unprotection, "chip erase" from bootloader only |
||
144 | * clears the flash but does no real "chip erase" (this is not possible |
||
145 | * with a bootloader as far as I know) |
||
146 | * Keep this undefined! |
||
147 | */ |
||
148 | //#define WRITELOCKBITS |
||
149 | |||
150 | /* |
||
151 | * define the following if the bootloader should not output |
||
152 | * itself at flash read (will fake an empty boot-section) |
||
153 | */ |
||
154 | #define READ_PROTECT_BOOTLOADER |
||
155 | |||
156 | |||
157 | #define VERSION_HIGH '0' |
||
158 | #define VERSION_LOW '8' |
||
159 | |||
160 | #define GET_LOCK_BITS 0x0001 |
||
161 | #define GET_LOW_FUSE_BITS 0x0000 |
||
162 | #define GET_HIGH_FUSE_BITS 0x0003 |
||
163 | #define GET_EXTENDED_FUSE_BITS 0x0002 |
||
164 | |||
165 | |||
166 | #ifdef UART_DOUBLESPEED |
||
167 | // #define UART_CALC_BAUDRATE(baudRate) (((F_CPU*10UL) / ((baudRate) *8UL) +5)/10 -1) |
||
168 | #define UART_CALC_BAUDRATE(baudRate) ((uint32_t)((F_CPU) + ((uint32_t)baudRate * 4UL)) / ((uint32_t)(baudRate) * 8UL) - 1) |
||
169 | #else |
||
170 | // #define UART_CALC_BAUDRATE(baudRate) (((F_CPU*10UL) / ((baudRate)*16UL) +5)/10 -1) |
||
171 | #define UART_CALC_BAUDRATE(baudRate) ((uint32_t)((F_CPU) + ((uint32_t)baudRate * 8UL)) / ((uint32_t)(baudRate) * 16UL) - 1) |
||
172 | #endif |
||
173 | |||
174 | |||
175 | #include <stdint.h> |
||
176 | #include <avr/io.h> |
||
177 | #include <avr/wdt.h> |
||
178 | #include <avr/boot.h> |
||
179 | #include <avr/pgmspace.h> |
||
180 | #include <avr/eeprom.h> |
||
181 | #include <avr/interrupt.h> |
||
182 | #include <util/delay.h> |
||
183 | |||
184 | #include "chipdef.h" |
||
185 | |||
186 | //#include "lcd.h" |
||
187 | |||
188 | uint8_t gBuffer[SPM_PAGESIZE]; |
||
189 | |||
190 | #if defined(BOOTLOADERHASNOVECTORS) |
||
191 | #warning "This Bootloader does not link interrupt vectors - see makefile" |
||
192 | /* make the linker happy - it wants to see __vector_default */ |
||
193 | // void __vector_default(void) { ; } |
||
194 | void __vector_default(void) { ; } |
||
195 | #endif |
||
196 | |||
197 | static void sendchar(uint8_t data) |
||
198 | { |
||
199 | while (!(UART_STATUS & (1<<UART_TXREADY))); |
||
200 | UART_DATA = data; |
||
201 | } |
||
202 | |||
203 | static uint8_t recvchar(void) |
||
204 | { |
||
205 | while (!(UART_STATUS & (1<<UART_RXREADY))); |
||
206 | clr_LED1(); |
||
207 | return UART_DATA; |
||
208 | } |
||
209 | |||
210 | static inline void eraseFlash(void) |
||
211 | { |
||
212 | // erase only main section (bootloader protection) |
||
213 | uint32_t addr = 0; |
||
214 | while (APP_END > addr) { |
||
215 | boot_page_erase(addr); // Perform page erase |
||
216 | boot_spm_busy_wait(); // Wait until the memory is erased. |
||
217 | addr += SPM_PAGESIZE; |
||
218 | } |
||
219 | boot_rww_enable(); |
||
220 | } |
||
221 | |||
222 | static inline void recvBuffer(pagebuf_t size) |
||
223 | { |
||
224 | pagebuf_t cnt; |
||
225 | uint8_t *tmp = gBuffer; |
||
226 | |||
227 | for (cnt = 0; cnt < sizeof(gBuffer); cnt++) { |
||
228 | *tmp++ = (cnt < size) ? recvchar() : 0xFF; |
||
229 | } |
||
230 | } |
||
231 | |||
232 | static inline uint16_t writeFlashPage(uint16_t waddr, pagebuf_t size) |
||
233 | { |
||
234 | uint32_t pagestart = (uint32_t)waddr<<1; |
||
235 | uint32_t baddr = pagestart; |
||
236 | uint16_t data; |
||
237 | uint8_t *tmp = gBuffer; |
||
238 | |||
239 | do { |
||
240 | data = *tmp++; |
||
241 | data |= *tmp++ << 8; |
||
242 | boot_page_fill(baddr, data); // call asm routine. |
||
243 | |||
244 | baddr += 2; // Select next word in memory |
||
245 | size -= 2; // Reduce number of bytes to write by two |
||
246 | } while (size); // Loop until all bytes written |
||
247 | |||
248 | boot_page_write(pagestart); |
||
249 | boot_spm_busy_wait(); |
||
250 | boot_rww_enable(); // Re-enable the RWW section |
||
251 | |||
252 | return baddr>>1; |
||
253 | } |
||
254 | |||
255 | static inline uint16_t writeEEpromPage(uint16_t address, pagebuf_t size) |
||
256 | { |
||
257 | uint8_t *tmp = gBuffer; |
||
258 | |||
259 | do { |
||
260 | eeprom_write_byte( (uint8_t*)address, *tmp++ ); |
||
261 | address++; // Select next byte |
||
262 | size--; // Decreas number of bytes to write |
||
263 | } while (size); // Loop until all bytes written |
||
264 | |||
265 | // eeprom_busy_wait(); |
||
266 | |||
267 | return address; |
||
268 | } |
||
269 | |||
270 | static inline uint16_t readFlashPage(uint16_t waddr, pagebuf_t size) |
||
271 | { |
||
272 | uint32_t baddr = (uint32_t)waddr<<1; |
||
273 | uint16_t data; |
||
274 | |||
275 | do { |
||
276 | #ifndef READ_PROTECT_BOOTLOADER |
||
277 | #warning "Bootloader not read-protected" |
||
278 | #if defined(RAMPZ) |
||
279 | data = pgm_read_word_far(baddr); |
||
280 | #else |
||
281 | data = pgm_read_word_near(baddr); |
||
282 | #endif |
||
283 | #else |
||
284 | // don't read bootloader |
||
285 | if ( baddr < APP_END ) { |
||
286 | #if defined(RAMPZ) |
||
287 | data = pgm_read_word_far(baddr); |
||
288 | #else |
||
289 | data = pgm_read_word_near(baddr); |
||
290 | #endif |
||
291 | } |
||
292 | else { |
||
293 | data = 0xFFFF; // fake empty |
||
294 | } |
||
295 | #endif |
||
296 | sendchar(data); // send LSB |
||
297 | sendchar((data >> 8)); // send MSB |
||
298 | baddr += 2; // Select next word in memory |
||
299 | size -= 2; // Subtract two bytes from number of bytes to read |
||
300 | } while (size); // Repeat until block has been read |
||
301 | |||
302 | return baddr>>1; |
||
303 | } |
||
304 | |||
305 | static inline uint16_t readEEpromPage(uint16_t address, pagebuf_t size) |
||
306 | { |
||
307 | do { |
||
308 | sendchar( eeprom_read_byte( (uint8_t*)address ) ); |
||
309 | address++; |
||
310 | size--; // Decrease number of bytes to read |
||
311 | } while (size); // Repeat until block has been read |
||
312 | |||
313 | return address; |
||
314 | } |
||
315 | |||
316 | #if defined(ENABLEREADFUSELOCK) |
||
317 | static uint8_t read_fuse_lock(uint16_t addr) |
||
318 | { |
||
319 | uint8_t mode = (1<<BLBSET) | (1<<SPMEN); |
||
320 | uint8_t retval; |
||
321 | |||
322 | asm volatile |
||
323 | ( |
||
324 | "movw r30, %3\n\t" /* Z to addr */ \ |
||
325 | "sts %0, %2\n\t" /* set mode in SPM_REG */ \ |
||
326 | "lpm\n\t" /* load fuse/lock value into r0 */ \ |
||
327 | "mov %1,r0\n\t" /* save return value */ \ |
||
328 | : "=m" (SPM_REG), |
||
329 | "=r" (retval) |
||
330 | : "r" (mode), |
||
331 | "r" (addr) |
||
332 | : "r30", "r31", "r0" |
||
333 | ); |
||
334 | return retval; |
||
335 | } |
||
336 | #endif |
||
337 | |||
338 | static void send_boot(void) |
||
339 | { |
||
340 | sendchar('A'); |
||
341 | sendchar('V'); |
||
342 | sendchar('R'); |
||
343 | sendchar('B'); |
||
344 | sendchar('O'); |
||
345 | sendchar('O'); |
||
346 | sendchar('T'); |
||
347 | } |
||
348 | |||
349 | |||
350 | |||
351 | static void (*jump_to_app)(void) = 0x0000; |
||
352 | |||
353 | int main(void) |
||
354 | { |
||
355 | uint16_t address = 0; |
||
356 | uint8_t device = 0, val; |
||
357 | |||
358 | DDRC = 0xFF; |
||
359 | PORTC = PORTC | 0xff; |
||
360 | |||
361 | |||
362 | |||
363 | #ifdef DISABLE_WDT_AT_STARTUP |
||
364 | #ifdef WDT_OFF_SPECIAL |
||
365 | #warning "using target specific watchdog_off" |
||
366 | bootloader_wdt_off(); |
||
367 | #else |
||
368 | cli(); |
||
369 | wdt_reset(); |
||
370 | wdt_disable(); |
||
371 | #endif |
||
372 | #endif |
||
373 | |||
374 | #ifdef START_POWERSAVE |
||
375 | uint8_t OK = 1; |
||
376 | #endif |
||
377 | |||
378 | BLDDR &= ~(1<<BLPNUM); // set as Input |
||
379 | BLPORT |= (1<<BLPNUM); // Enable pullup |
||
380 | |||
381 | // Set baud rate |
||
382 | UART_BAUD_HIGH = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF; |
||
383 | UART_BAUD_LOW = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF); |
||
384 | |||
385 | #ifdef UART_DOUBLESPEED |
||
386 | UART_STATUS = ( 1<<UART_DOUBLE ); |
||
387 | #endif |
||
388 | |||
389 | UART_CTRL = UART_CTRL_DATA; |
||
390 | UART_CTRL2 = UART_CTRL2_DATA; |
||
391 | |||
392 | #if defined(START_POWERSAVE) |
||
393 | /* |
||
394 | This is an adoption of the Butterfly Bootloader startup-sequence. |
||
395 | It may look a little strange but separating the login-loop from |
||
396 | the main parser-loop gives a lot a possibilities (timeout, sleep-modes |
||
397 | etc.). |
||
398 | */ |
||
399 | for(;OK;) { |
||
400 | if ((BLPIN & (1<<BLPNUM))) { |
||
401 | // jump to main app if pin is not grounded |
||
402 | BLPORT &= ~(1<<BLPNUM); // set to default |
||
403 | #ifdef UART_DOUBLESPEED |
||
404 | UART_STATUS &= ~( 1<<UART_DOUBLE ); |
||
405 | #endif |
||
406 | jump_to_app(); // Jump to application sector |
||
407 | |||
408 | } else { |
||
409 | val = recvchar(); |
||
410 | /* ESC */ |
||
411 | if (val == 0x1B) { |
||
412 | // AVRPROG connection |
||
413 | // Wait for signon |
||
414 | while (val != 'S') |
||
415 | val = recvchar(); |
||
416 | |||
417 | send_boot(); // Report signon |
||
418 | OK = 0; |
||
419 | |||
420 | } else { |
||
421 | sendchar('?'); |
||
422 | } |
||
423 | } |
||
424 | // Power-Save code here |
||
425 | } |
||
426 | |||
427 | #elif defined(START_SIMPLE) |
||
428 | |||
429 | if ((BLPIN & (1<<BLPNUM))) { |
||
430 | // jump to main app if pin is not grounded |
||
431 | BLPORT &= ~(1<<BLPNUM); // set to default |
||
432 | #ifdef UART_DOUBLESPEED |
||
433 | UART_STATUS &= ~( 1<<UART_DOUBLE ); |
||
434 | #endif |
||
435 | jump_to_app(); // Jump to application sector |
||
436 | } |
||
437 | |||
438 | #elif defined(START_WAIT) |
||
439 | |||
440 | uint16_t cnt = 0; |
||
441 | |||
442 | while (1) { |
||
443 | if (UART_STATUS & (1<<UART_RXREADY)) |
||
444 | if (UART_DATA == START_WAIT_UARTCHAR) |
||
445 | break; |
||
446 | |||
447 | if (cnt++ >= WAIT_VALUE) { |
||
448 | BLPORT &= ~(1<<BLPNUM); // set to default |
||
449 | jump_to_app(); // Jump to application sector |
||
450 | } |
||
451 | |||
452 | _delay_ms(10); |
||
453 | } |
||
454 | send_boot(); |
||
455 | |||
456 | #elif defined(START_BOOTICE) |
||
457 | #warning "BOOTICE mode - no startup-condition" |
||
458 | |||
459 | #else |
||
460 | #error "Select START_ condition for bootloader in main.c" |
||
461 | #endif |
||
462 | |||
463 | |||
464 | |||
465 | for(;;) { |
||
466 | |||
467 | set_LED1(); |
||
468 | |||
469 | val = recvchar(); |
||
470 | |||
471 | // Autoincrement? |
||
472 | if (val == 'a') { |
||
473 | sendchar('Y'); // Autoincrement is quicker |
||
474 | |||
475 | //write address |
||
476 | } else if (val == 'A') { |
||
477 | address = recvchar(); //read address 8 MSB |
||
478 | address = (address<<8) | recvchar(); |
||
479 | sendchar('\r'); |
||
480 | |||
481 | // Buffer load support |
||
482 | } else if (val == 'b') { |
||
483 | sendchar('Y'); // Report buffer load supported |
||
484 | sendchar((sizeof(gBuffer) >> 8) & 0xFF); // Report buffer size in bytes |
||
485 | sendchar(sizeof(gBuffer) & 0xFF); |
||
486 | |||
487 | // Start buffer load |
||
488 | } else if (val == 'B') { |
||
489 | pagebuf_t size; |
||
490 | size = recvchar() << 8; // Load high byte of buffersize |
||
491 | size |= recvchar(); // Load low byte of buffersize |
||
492 | val = recvchar(); // Load memory type ('E' or 'F') |
||
493 | recvBuffer(size); |
||
494 | |||
495 | if (device == DEVTYPE) { |
||
496 | if (val == 'F') { |
||
497 | address = writeFlashPage(address, size); |
||
498 | } else if (val == 'E') { |
||
499 | address = writeEEpromPage(address, size); |
||
500 | } |
||
501 | sendchar('\r'); |
||
502 | } else { |
||
503 | sendchar(0); |
||
504 | } |
||
505 | |||
506 | // Block read |
||
507 | } else if (val == 'g') { |
||
508 | pagebuf_t size; |
||
509 | size = recvchar() << 8; // Load high byte of buffersize |
||
510 | size |= recvchar(); // Load low byte of buffersize |
||
511 | val = recvchar(); // Get memtype |
||
512 | |||
513 | if (val == 'F') { |
||
514 | address = readFlashPage(address, size); |
||
515 | } else if (val == 'E') { |
||
516 | address = readEEpromPage(address, size); |
||
517 | } |
||
518 | |||
519 | // Chip erase |
||
520 | } else if (val == 'e') { |
||
521 | if (device == DEVTYPE) { |
||
522 | eraseFlash(); |
||
523 | } |
||
524 | sendchar('\r'); |
||
525 | |||
526 | // Exit upgrade |
||
527 | } else if (val == 'E') { |
||
528 | wdt_enable(EXIT_WDT_TIME); // Enable Watchdog Timer to give reset |
||
529 | sendchar('\r'); |
||
530 | |||
531 | #ifdef WRITELOCKBITS |
||
532 | #warning "Extension 'WriteLockBits' enabled" |
||
533 | // TODO: does not work reliably |
||
534 | // write lockbits |
||
535 | } else if (val == 'l') { |
||
536 | if (device == DEVTYPE) { |
||
537 | // write_lock_bits(recvchar()); |
||
538 | boot_lock_bits_set(recvchar()); // boot.h takes care of mask |
||
539 | boot_spm_busy_wait(); |
||
540 | } |
||
541 | sendchar('\r'); |
||
542 | #endif |
||
543 | // Enter programming mode |
||
544 | } else if (val == 'P') { |
||
545 | sendchar('\r'); |
||
546 | |||
547 | // Leave programming mode |
||
548 | } else if (val == 'L') { |
||
549 | sendchar('\r'); |
||
550 | |||
551 | // return programmer type |
||
552 | } else if (val == 'p') { |
||
553 | sendchar('S'); // always serial programmer |
||
554 | |||
555 | #ifdef ENABLEREADFUSELOCK |
||
556 | #warning "Extension 'ReadFuseLock' enabled" |
||
557 | // read "low" fuse bits |
||
558 | } else if (val == 'F') { |
||
559 | sendchar(read_fuse_lock(GET_LOW_FUSE_BITS)); |
||
560 | |||
561 | // read lock bits |
||
562 | } else if (val == 'r') { |
||
563 | sendchar(read_fuse_lock(GET_LOCK_BITS)); |
||
564 | |||
565 | // read high fuse bits |
||
566 | } else if (val == 'N') { |
||
567 | sendchar(read_fuse_lock(GET_HIGH_FUSE_BITS)); |
||
568 | |||
569 | // read extended fuse bits |
||
570 | } else if (val == 'Q') { |
||
571 | sendchar(read_fuse_lock(GET_EXTENDED_FUSE_BITS)); |
||
572 | #endif |
||
573 | |||
574 | // Return device type |
||
575 | } else if (val == 't') { |
||
576 | sendchar(DEVTYPE); |
||
577 | sendchar(0); |
||
578 | |||
579 | // clear and set LED ignored |
||
580 | } else if ((val == 'x') || (val == 'y')) { |
||
581 | recvchar(); |
||
582 | sendchar('\r'); |
||
583 | |||
584 | // set device |
||
585 | } else if (val == 'T') { |
||
586 | device = recvchar(); |
||
587 | sendchar('\r'); |
||
588 | |||
589 | // Return software identifier |
||
590 | } else if (val == 'S') { |
||
591 | send_boot(); |
||
592 | |||
593 | // Return Software Version |
||
594 | } else if (val == 'V') { |
||
595 | sendchar(VERSION_HIGH); |
||
596 | sendchar(VERSION_LOW); |
||
597 | |||
598 | // Return Signature Bytes (it seems that |
||
599 | // AVRProg expects the "Atmel-byte" 0x1E last |
||
600 | // but shows it first in the dialog-window) |
||
601 | } else if (val == 's') { |
||
602 | sendchar(SIG_BYTE3); |
||
603 | sendchar(SIG_BYTE2); |
||
604 | sendchar(SIG_BYTE1); |
||
605 | |||
606 | /* ESC */ |
||
607 | } else if(val != 0x1b) { |
||
608 | sendchar('?'); |
||
609 | } |
||
610 | |||
611 | } |
||
612 | return 0; |
||
613 | } |