Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (6.67 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 0x400
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
  void (*main_start)(void) = BOOT_START/2 - 1;
27

    
28

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

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

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

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

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

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

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

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

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

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

    
89

    
90
        return;
91
}
92

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

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

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

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

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

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

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

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

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

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

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

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

    
188
            break;
189

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

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

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

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

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

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

    
220
/*BOOTLOADER_SECTION*/ int main(void) {
221
  uint8_t mbuf[PROGD_PACKET_SIZE];
222
  rjump_t jbuf;
223
  uint16_t caddr = MAIN_ADDR;
224
  uint8_t iteration;
225
  uint8_t resp;
226
  uint16_t prog_len;
227
  uint8_t i;
228
  
229
  //main_start = (void*)(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) - 1;
262
              jbuf.sword &= 0x0FFF;
263
              jbuf.sword |= 0xC000;
264

    
265
              mbuf[0] = (BOOT_START/2 - 1) & 0xFF;
266
              mbuf[1] = 0xC0 | (((BOOT_START/2 - 1) >> 8) & 0x0F);
267
              //memcpy_P(mbuf, (PGM_VOID_P)MAIN_ADDR, 2);
268
              //mbuf[0] = pgm_read_byte(MAIN_ADDR);
269
              //mbuf[1] = pgm_read_byte(MAIN_ADDR + 1);
270
              //PORTB &= ~_BV(PORTB0);
271
              //while(1);
272

    
273
              iteration = 1;
274
          } /*else {
275
              PORTB &= ~_BV(PORTB1);
276
              while(1);
277
          }*/
278

    
279

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

    
288
      send_packet(TT_ACK);
289

    
290
      if (prog_len <= PROGD_PACKET_SIZE) {
291
          for (i = 0; i < PROGD_PACKET_SIZE; i++) {
292
              mbuf[i]= 0;
293
          }
294

    
295
          mbuf[PROGD_PACKET_SIZE-2] = jbuf.bytes[0];
296
          mbuf[PROGD_PACKET_SIZE-1] = jbuf.bytes[1];
297

    
298
          onboard_program_write(BOOT_START - SPM_PAGESIZE, mbuf);
299

    
300
          PORTB = 0;
301
          main_start();
302
      } else { 
303
          prog_len -= PROGD_PACKET_SIZE;
304
      }
305
  }
306
  
307
  return -1;
308
}
309

    
310
/*
311
int main (void) {
312
    while(1);
313
}*/