Statistics
| Revision:

root / trunk / toolbox / bootloader / bootloader.c @ 171

History | View | Annotate | Download (5.9 KB)

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