Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (6.13 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_ADDR 0x5A0
18
#define JUMP_ADDR 0x590
19

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

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

    
28
//void onboard_program_write(uint16_t page, uint8_t *buf);
29
void (*main_start)(void) = BOOT_ADDR - 2;
30

    
31

    
32
typedef enum {
33
    sd,
34
    src,
35
    dest,
36
    comd,
37
    read,
38
    cs,
39
    ack
40
} state_t;
41

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

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

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

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

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

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

    
80
    // Waits until the transmit is done
81
    while(!(UCSRA & _BV(UDRE)));
82
    PORTB |= _BV(PORTB1);
83

    
84
    uart_toggle_transmit(UART_TX_OFF);
85

    
86
        return;
87
}
88

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

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

    
108
  while (1) {
109
    // Wait for the next byte
110
    while ((uart_get_byte(&r)) < 0) {
111
        if (count >= MAX_TIMEOUT) {
112
            return TT_BAD;
113
       }
114
    }
115

    
116
    switch (state) {
117
        case sd:
118
            if (r == DELIM) {
119
                state = src;
120
            }
121
            break;
122

    
123
        case src:
124
            if (r == DELIM) {
125
                state = src;
126
            } else {
127
                crc = r;
128
                state = dest;
129
            }
130
            break;
131

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

    
143
        case comd:
144
            cmd = r;
145
            crc ^= r;
146

    
147
            if (r == DELIM) {
148
                state = src;
149
            } else if (r == TT_PROGM) {
150
                lim = PROGM_PACKET_SIZE;
151
                state = read;
152
            } else if (r == TT_PROGD) {
153
                lim = PROGD_PACKET_SIZE;
154
                state = read;
155
            } else {
156
                state = cs;
157
            }
158
            break;
159

    
160
        case read:
161
            mbuf[pos] = r;
162
            crc ^= r;
163
            pos++;
164

    
165
            if (pos == lim) {
166
                state = cs;
167
            }
168

    
169
            break;
170
       
171
        case cs:
172
            if (r == crc) {
173
                return cmd;
174
            } else {
175
                return TT_BAD;
176
            }
177

    
178
            break;
179

    
180
        default:
181
            return TT_BAD;
182
    }
183
  }
184
}
185

    
186
BOOTLOADER_SECTION void send_packet(uint8_t cmd) {
187
    uart_send_byte(DELIM);
188
    uart_send_byte(ADDR);
189
    uart_send_byte(SERVER);
190
    uart_send_byte(cmd);
191
    uart_send_byte(ACK_CRC ^ cmd);
192
    uart_send_byte(0);
193
}
194

    
195
//#define SPM_PAGESIZE 32
196
BOOTLOADER_SECTION void onboard_program_write(uint16_t page, uint8_t *buf) {
197
  uint16_t i;
198

    
199
  boot_page_erase (page);
200
  boot_spm_busy_wait ();      // Wait until the memory is erased.
201

    
202
  for (i=0; i < SPM_PAGESIZE; i+=2){
203
    // Set up little-endian word.
204
    boot_page_fill (i, buf[i] | (buf[i+1] <<8));
205
  }
206

    
207
  boot_page_write (page);     // Store buffer in flash page.
208
  boot_spm_busy_wait();       // Wait until the memory is written.
209
}
210

    
211
BOOTLOADER_SECTION void  __init(void) {
212
  uint8_t mbuf[PROGD_PACKET_SIZE];
213
  uint8_t jbuf[2];
214
  uint16_t caddr = MAIN_ADDR;
215
  uint8_t iteration = 0;
216
  uint8_t resp;
217
  uint16_t prog_len = 0;
218
  uint8_t i;
219

    
220
  init_uart(51); //MAGIC NUMBER??
221

    
222
  //set LED pin as output
223
  LED_DDR |= 0x07;
224
  PORTB = 0x00;
225

    
226
  //Start bootloading process
227
  send_packet(TT_BOOT);
228
  PORTB |= _BV(PORTB0);
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[0] = mbuf[0];
247
              jbuf[1] = mbuf[1];
248

    
249
              *((uint16_t*)mbuf) = pgm_read_word(MAIN_ADDR);
250

    
251
              onboard_program_write(caddr, mbuf);
252
              iteration = 1;
253
              caddr += PROGD_PACKET_SIZE - 2;
254
          } else {
255
              onboard_program_write(caddr, mbuf);
256
              caddr += PROGD_PACKET_SIZE;
257
          }
258
      } else {
259
          //main_start();
260
          while(1);
261
      }
262

    
263
      send_packet(TT_ACK);
264

    
265
      if (prog_len <= PROGD_PACKET_SIZE) {
266
          //send_packet(TT_ACK);
267

    
268
          for (i = 0; i < PROGD_PACKET_SIZE; i++) {
269
              mbuf[i]= 0;
270
          }
271

    
272
          mbuf[PROGD_PACKET_SIZE-2] = jbuf[0];
273
          mbuf[PROGD_PACKET_SIZE-1] = jbuf[1];
274

    
275
          onboard_program_write(JUMP_ADDR, mbuf);
276

    
277
          PORTB = 0;
278
          main_start();
279
      } else { 
280
          prog_len -= PROGD_PACKET_SIZE;
281
      }
282
  }
283
}
284

    
285

    
286
int main (void) {
287
    while(1);
288
}