root / trunk / toolbox / bootloader / bootloader.c @ 164
History | View | Annotate | Download (5.48 KB)
1 |
#include <avr/io.h> |
---|---|
2 |
#include <util/delay.h> |
3 |
#include <avr/boot.h> |
4 |
|
5 |
#include "tooltron.h" |
6 |
#include "uart.h" |
7 |
|
8 |
#define TRUE 0 |
9 |
#define FALSE 1 |
10 |
|
11 |
#define ADDR 18 |
12 |
|
13 |
|
14 |
#define MAX_WAIT_IN_CYCLES 800000 |
15 |
#define MAX_TIMEOUT 60000 // Seconds to wait before exiting bootloader mode |
16 |
#define MAIN_ADDR 0x02 |
17 |
|
18 |
//Status LED
|
19 |
#define LED_DDR DDRB
|
20 |
#define LED_PORT PORTB
|
21 |
#define LED PORTB1
|
22 |
|
23 |
//Function prototypes
|
24 |
void flash_led(uint8_t);
|
25 |
void onboard_program_write(uint16_t page, uint8_t *buf);
|
26 |
void (*main_start)(void) = MAIN_ADDR; |
27 |
|
28 |
typedef enum { |
29 |
sd, |
30 |
src, |
31 |
dest, |
32 |
comd, |
33 |
read, |
34 |
cs, |
35 |
ack |
36 |
} state_t; |
37 |
|
38 |
BOOTLOADER_SECTION void init_uart(uint16_t baud) {
|
39 |
// Set baud rate
|
40 |
UBRRH = (uint8_t)(baud>>8);
|
41 |
UBRRL = (uint8_t)baud; |
42 |
|
43 |
// Enable RX/TX and RX/TX Interrupt
|
44 |
UCSRB = _BV(RXCIE) | _BV(RXEN) | _BV(TXCIE) | _BV(TXEN); |
45 |
|
46 |
// Enable the TXEN pin as output
|
47 |
DDRD |= TX_EN; |
48 |
} |
49 |
|
50 |
BOOTLOADER_SECTION int8_t uart_get_byte(uint8_t *output_byte) { |
51 |
if (UCSRA & _BV(RXC)) {
|
52 |
*output_byte = UDR; |
53 |
return 0; |
54 |
} else {
|
55 |
return -1; |
56 |
} |
57 |
} |
58 |
|
59 |
BOOTLOADER_SECTION void uart_send_byte(uint8_t data) {
|
60 |
//Waits until current transmit is done
|
61 |
while (!(UCSRA & _BV(UDRE)));
|
62 |
|
63 |
// Enable writes and send
|
64 |
uart_toggle_transmit(UART_TX_ON); |
65 |
UDR = data; |
66 |
|
67 |
// Waits until the transmit is done
|
68 |
while(!(UCSRA & _BV(UDRE)));
|
69 |
uart_toggle_transmit(UART_TX_OFF); |
70 |
|
71 |
return;
|
72 |
} |
73 |
|
74 |
BOOTLOADER_SECTION void uart_toggle_transmit(uint8_t state) {
|
75 |
if (state == UART_TX_ON) {
|
76 |
PORTD |= TX_EN; |
77 |
} else {
|
78 |
PORTD &= ~TX_EN; |
79 |
} |
80 |
} |
81 |
|
82 |
BOOTLOADER_SECTION char parse_packet(uint8_t *mbuf) {
|
83 |
uint8_t r = 0; // Byte from the network |
84 |
uint8_t crc = 0; // Running checksum of the packet |
85 |
uint8_t cmd = 0; // The command received |
86 |
uint8_t pos = 0; // Position in the message buffer |
87 |
uint8_t lim = 0; // Max number of bytes to read into the message buf |
88 |
state_t state = sd; // State machine
|
89 |
uint16_t count; |
90 |
//reset_timer();
|
91 |
count = 0;
|
92 |
|
93 |
while (1) { |
94 |
// Wait for the next byte
|
95 |
while ((uart_get_byte(&r)) < 0) { |
96 |
if (count >= MAX_TIMEOUT) {
|
97 |
return TT_BAD;
|
98 |
} |
99 |
} |
100 |
|
101 |
switch (state) {
|
102 |
case sd:
|
103 |
if (r == DELIM) {
|
104 |
state = src; |
105 |
} |
106 |
break;
|
107 |
|
108 |
case src:
|
109 |
if (r == DELIM) {
|
110 |
state = src; |
111 |
} else {
|
112 |
crc = r; |
113 |
state = dest; |
114 |
} |
115 |
break;
|
116 |
|
117 |
case dest:
|
118 |
if (r == DELIM) {
|
119 |
state = src; |
120 |
} else if (r == ADDR) { |
121 |
crc ^= r; |
122 |
state = comd; |
123 |
} else {
|
124 |
state = sd; |
125 |
} |
126 |
break;
|
127 |
|
128 |
case comd:
|
129 |
cmd = r; |
130 |
crc ^= r; |
131 |
|
132 |
if (r == DELIM) {
|
133 |
state = src; |
134 |
} else if (r == TT_PROGM) { |
135 |
lim = PROGM_PACKET_SIZE; |
136 |
state = read; |
137 |
} else if (r == TT_PROGD) { |
138 |
lim = PROGD_PACKET_SIZE; |
139 |
state = read; |
140 |
} else {
|
141 |
state = cs; |
142 |
} |
143 |
break;
|
144 |
|
145 |
case read:
|
146 |
mbuf[pos] = r; |
147 |
crc ^= r; |
148 |
pos++; |
149 |
|
150 |
if (pos == lim) {
|
151 |
state = cs; |
152 |
} |
153 |
|
154 |
break;
|
155 |
|
156 |
case cs:
|
157 |
if (r == crc) {
|
158 |
return cmd;
|
159 |
} else {
|
160 |
return TT_BAD;
|
161 |
} |
162 |
|
163 |
break;
|
164 |
|
165 |
default:
|
166 |
return TT_BAD;
|
167 |
} |
168 |
} |
169 |
} |
170 |
|
171 |
BOOTLOADER_SECTION void send_packet(uint8_t cmd) {
|
172 |
uart_send_byte(DELIM); |
173 |
uart_send_byte(ADDR); |
174 |
uart_send_byte(SERVER); |
175 |
uart_send_byte(cmd); |
176 |
uart_send_byte(ACK_CRC ^ cmd); |
177 |
} |
178 |
|
179 |
//#define SPM_PAGESIZE 32
|
180 |
BOOTLOADER_SECTION void onboard_program_write(uint16_t page, uint8_t *buf) {
|
181 |
uint16_t i; |
182 |
|
183 |
boot_page_erase (page); |
184 |
boot_spm_busy_wait (); // Wait until the memory is erased.
|
185 |
|
186 |
for (i=0; i < SPM_PAGESIZE; i+=2){ |
187 |
// Set up little-endian word.
|
188 |
boot_page_fill (i, buf[i] | (buf[i+1] <<8)); |
189 |
} |
190 |
|
191 |
boot_page_write (page); // Store buffer in flash page.
|
192 |
boot_spm_busy_wait(); // Wait until the memory is written.
|
193 |
} |
194 |
|
195 |
BOOTLOADER_SECTION void flash_led(uint8_t count) {
|
196 |
uint8_t i; |
197 |
|
198 |
for (i = 0; i < count; ++i) { |
199 |
LED_PORT |= _BV(LED); |
200 |
_delay_ms(100);
|
201 |
LED_PORT &= ~_BV(LED); |
202 |
_delay_ms(100);
|
203 |
} |
204 |
} |
205 |
|
206 |
BOOTLOADER_SECTION int main(void) { |
207 |
uint8_t mbuf[PROGD_PACKET_SIZE]; |
208 |
uint16_t caddr = MAIN_ADDR; |
209 |
uint8_t iteration = 0;
|
210 |
uint8_t resp; |
211 |
uint16_t prog_len = 0;
|
212 |
|
213 |
init_uart(51); //MAGIC NUMBER?? |
214 |
|
215 |
//set LED pin as output
|
216 |
LED_DDR |= 0x07;
|
217 |
PORTB = 0x07;
|
218 |
|
219 |
//Start bootloading process
|
220 |
send_packet(TT_BOOT); |
221 |
|
222 |
resp = parse_packet(mbuf); |
223 |
if (resp == TT_PROGM) {
|
224 |
prog_len = mbuf[0];
|
225 |
prog_len |= mbuf[1] << 8; |
226 |
} else {
|
227 |
PORTB = 0;
|
228 |
main_start(); |
229 |
} |
230 |
send_packet(TT_ACK); |
231 |
|
232 |
while(1) { |
233 |
resp = parse_packet(mbuf); |
234 |
|
235 |
if (resp == TT_PROGD) {
|
236 |
if (iteration == 0) { |
237 |
onboard_program_write(caddr++, &(mbuf[2]));
|
238 |
iteration = 1;
|
239 |
caddr += PROGD_PACKET_SIZE - 2;
|
240 |
} else {
|
241 |
onboard_program_write(caddr, &(mbuf[2]));
|
242 |
caddr += PROGD_PACKET_SIZE; |
243 |
} |
244 |
} else {
|
245 |
while(1) { |
246 |
flash_led(1);
|
247 |
} |
248 |
} |
249 |
|
250 |
send_packet(TT_ACK); |
251 |
|
252 |
if (prog_len <= PROGD_PACKET_SIZE) {
|
253 |
send_packet(TT_ACK); |
254 |
PORTB = 0;
|
255 |
_delay_ms(1000);
|
256 |
main_start(); |
257 |
} else {
|
258 |
prog_len -= PROGD_PACKET_SIZE; |
259 |
} |
260 |
} |
261 |
} |
262 |
|