Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (6.41 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_WAIT_IN_CYCLES 800000
15
#define MAX_TIMEOUT 60000        // Seconds to wait before exiting bootloader mode
16
#define MAIN_ADDR 0x000
17
#define BOOT_START 0x500
18

    
19
//Status LED
20
#define LED_DDR  DDRB
21
#define LED_PORT PORTB
22
#define LED      PORTB1
23

    
24
//Function prototypes
25
void __init(void) __attribute__((naked));
26

    
27

    
28
typedef enum {
29
    sd,
30
    src,
31
    dest,
32
    comd,
33
    read,
34
    cs,
35
    ack
36
} state_t;
37

    
38
typedef union {
39
    uint8_t bytes[2];
40
    int16_t sword;
41
} rjump_t;
42

    
43
// Redirect all unused interrupts to reti
44
EMPTY_INTERRUPT(__vector_default);
45
extern void __ctors_end(void) __attribute__((__noreturn__));
46

    
47
// macros for entering subprograms
48
#define __JMP_INIT__ __asm__ __volatile__ ("rjmp __ctors_end" )
49

    
50
BOOTLOADER_SECTION void init_uart(uint16_t baud) {
51
        // Set baud rate
52
        UBRRH = (uint8_t)(baud>>8);
53
        UBRRL = (uint8_t)baud;
54
        
55
        // Enable RX/TX
56
        UCSRB = _BV(RXEN) | _BV(TXEN);
57
 
58
        // Enable the TXEN pin as output
59
        DDRD |= TX_EN;
60
    uart_toggle_transmit(UART_TX_OFF);
61
}
62

    
63
BOOTLOADER_SECTION int8_t uart_get_byte(uint8_t *output_byte) {
64
    if (UCSRA & _BV(RXC)) {
65
        *output_byte = UDR;
66
        return 0;
67
    } else {
68
        return -1;
69
    }
70
}
71

    
72
BOOTLOADER_SECTION void uart_send_byte(uint8_t data) {
73
        //Waits until current transmit is done
74
    while (!(UCSRA & _BV(UDRE)));
75
    //PORTB |= _BV(PORTB2);
76

    
77
    // Enable writes and send
78
        uart_toggle_transmit(UART_TX_ON);
79
    UDR = data;
80

    
81
    // Waits until the transmit is done
82
    while(!(UCSRA & _BV(TXC)));
83
    uart_toggle_transmit(UART_TX_OFF);
84
    UCSRA |= _BV(TXC);
85

    
86
    //PORTB |= _BV(PORTB1);
87

    
88

    
89
        return;
90
}
91

    
92
BOOTLOADER_SECTION void uart_toggle_transmit(uint8_t state) {
93
        if (state == UART_TX_ON) {
94
                PORTD |= TX_EN;
95
        } else {
96
                PORTD &= ~TX_EN;
97
        }
98
}
99

    
100
BOOTLOADER_SECTION char parse_packet(uint8_t *mbuf) {
101
  uint8_t r;        // Byte from the network
102
  uint8_t crc;      // Running checksum of the packet
103
  uint8_t cmd;      // The command received
104
  uint8_t pos;      // Position in the message buffer
105
  uint8_t lim;      // Max number of bytes to read into the message buf
106
  state_t state;    // State machine
107
  uint16_t count;
108

    
109
  r = 0;
110
  crc = 0;
111
  cmd = 0;
112
  pos = 0;
113
  lim = 0;
114
  state = sd;
115
  count = 0;
116

    
117
  while (1) {
118
    // Wait for the next byte
119
    while ((uart_get_byte(&r)) < 0) {
120
        if (count >= MAX_TIMEOUT) {
121
            return TT_BAD;
122
       }
123
    }
124

    
125
    switch (state) {
126
        case sd:
127
            if (r == DELIM) {
128
                state = src;
129
            }
130
            break;
131

    
132
        case src:
133
            if (r == DELIM) {
134
                state = src;
135
            } else {
136
                crc = r;
137
                state = dest;
138
            }
139
            break;
140

    
141
        case dest:
142
            if (r == DELIM) {
143
                state = src;
144
            } else if (r == ADDR) {
145
                crc ^= r;
146
                state = comd;
147
            } else {
148
                state = sd;
149
            }
150
            break;
151

    
152
        case comd:
153
            cmd = r;
154
            crc ^= r;
155

    
156
            if (r == DELIM) {
157
                state = src;
158
            } else if (r == TT_PROGM) {
159
                lim = PROGM_PACKET_SIZE;
160
                state = read;
161
            } else if (r == TT_PROGD) {
162
                lim = PROGD_PACKET_SIZE;
163
                state = read;
164
            } else {
165
                state = cs;
166
            }
167
            break;
168

    
169
        case read:
170
            mbuf[pos] = r;
171
            crc ^= r;
172
            pos++;
173

    
174
            if (pos == lim) {
175
                state = cs;
176
            }
177

    
178
            break;
179
       
180
        case cs:
181
            if (r == crc) {
182
                return cmd;
183
            } else {
184
                return TT_BAD;
185
            }
186

    
187
            break;
188

    
189
        default:
190
            return TT_BAD;
191
    }
192
  }
193
}
194

    
195
BOOTLOADER_SECTION void send_packet(uint8_t cmd) {
196
    uart_send_byte(DELIM);
197
    uart_send_byte(ADDR);
198
    uart_send_byte(SERVER);
199
    uart_send_byte(cmd);
200
    uart_send_byte(ACK_CRC ^ cmd);
201
}
202

    
203
//#define SPM_PAGESIZE 32
204
BOOTLOADER_SECTION void onboard_program_write(uint16_t page, uint8_t *buf) {
205
  uint16_t i;
206

    
207
  boot_page_erase (page);
208
  boot_spm_busy_wait ();      // Wait until the memory is erased.
209

    
210
  for (i=0; i < SPM_PAGESIZE; i+=2){
211
    // Set up little-endian word.
212
    boot_page_fill (page + i, buf[i] | (buf[i+1] <<8));
213
  }
214

    
215
  boot_page_write (page);     // Store buffer in flash page.
216
  boot_spm_busy_wait();       // Wait until the memory is written.
217
}
218

    
219
BOOTLOADER_SECTION void  main(void) {
220
  uint8_t mbuf[PROGD_PACKET_SIZE];
221
  rjump_t jbuf;
222
  uint16_t caddr = MAIN_ADDR;
223
  uint8_t iteration;
224
  uint8_t resp;
225
  uint16_t prog_len;
226
  uint8_t i;
227
  void (*main_start)(void);
228
  
229
  main_start = BOOT_START - 2;
230
  iteration = 0;
231

    
232
  init_uart(51); //MAGIC NUMBER??
233

    
234
  //set LED pin as output
235
  LED_DDR |= 0x07;
236
  PORTB = 0x07;
237

    
238
  //Start bootloading process
239
  send_packet(TT_BOOT);
240

    
241
  resp = parse_packet(mbuf);
242
  if (resp == TT_PROGM) {
243
    prog_len = mbuf[0];
244
    prog_len |= mbuf[1] << 8;
245
  } else {
246
      //PORTB = 0;
247
      main_start();
248
  }
249
  send_packet(TT_ACK);
250

    
251
  while(1) {
252
      resp = parse_packet(mbuf);
253

    
254
      if (resp == TT_PROGD) {
255
          if (iteration == 0) {
256
              // Store the jump to user code
257
              jbuf.bytes[0] = mbuf[0];
258
              jbuf.bytes[1] = mbuf[1];
259
             
260
              jbuf.sword &= 0x0FFF;
261
              jbuf.sword -= BOOT_START >> 1;
262
              jbuf.sword &= 0x0FFF;
263
              jbuf.sword |= 0xC000;
264

    
265
              mbuf[0] = pgm_read_byte(MAIN_ADDR);
266
              mbuf[1] = pgm_read_byte(MAIN_ADDR + 1);
267
              //PORTB &= ~_BV(PORTB0);
268
              //while(1);
269

    
270
              iteration = 1;
271
          } /*else {
272
              PORTB &= ~_BV(PORTB1);
273
              while(1);
274
          }*/
275

    
276

    
277
          onboard_program_write(caddr, mbuf);
278
          caddr += PROGD_PACKET_SIZE;
279
      } else {
280
          //main_start();
281
          PORTB &= ~_BV(PORTB2);
282
          while(1);
283
      }
284

    
285
      send_packet(TT_ACK);
286

    
287
      if (prog_len <= PROGD_PACKET_SIZE) {
288
          for (i = 0; i < PROGD_PACKET_SIZE; i++) {
289
              mbuf[i]= 0;
290
          }
291

    
292
          mbuf[PROGD_PACKET_SIZE-2] = jbuf.bytes[0];
293
          mbuf[PROGD_PACKET_SIZE-1] = jbuf.bytes[1];
294

    
295
          onboard_program_write(BOOT_START - SPM_PAGESIZE, mbuf);
296

    
297
          PORTB = 0;
298
          main_start();
299
      } else { 
300
          prog_len -= PROGD_PACKET_SIZE;
301
      }
302
  }
303
}
304

    
305
/*
306
int main (void) {
307
    while(1);
308
}*/