Project

General

Profile

Statistics
| Revision:

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