Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (6 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(RXCIE) | _BV(RXEN) | _BV(TXCIE) | _BV(TXEN);
56
 
57
        // Enable the TXEN pin as output
58
        DDRD |= TX_EN;
59
}
60

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

    
70
BOOTLOADER_SECTION void uart_send_byte(uint8_t data) {
71
        //Waits until current transmit is done
72
    while (!(UCSRA & _BV(UDRE)));
73

    
74
    // Enable writes and send
75
        uart_toggle_transmit(UART_TX_ON);
76
    UDR = data;
77

    
78
    // Waits until the transmit is done
79
    while(!(UCSRA & _BV(UDRE)));
80
    uart_toggle_transmit(UART_TX_OFF);
81

    
82
        return;
83
}
84

    
85
BOOTLOADER_SECTION void uart_toggle_transmit(uint8_t state) {
86
        if (state == UART_TX_ON) {
87
                PORTD |= TX_EN;
88
        } else {
89
                PORTD &= ~TX_EN;
90
        }
91
}
92

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

    
104
  while (1) {
105
    // Wait for the next byte
106
    while ((uart_get_byte(&r)) < 0) {
107
        if (count >= MAX_TIMEOUT) {
108
            return TT_BAD;
109
       }
110
    }
111

    
112
    switch (state) {
113
        case sd:
114
            if (r == DELIM) {
115
                state = src;
116
            }
117
            break;
118

    
119
        case src:
120
            if (r == DELIM) {
121
                state = src;
122
            } else {
123
                crc = r;
124
                state = dest;
125
            }
126
            break;
127

    
128
        case dest:
129
            if (r == DELIM) {
130
                state = src;
131
            } else if (r == ADDR) {
132
                crc ^= r;
133
                state = comd;
134
            } else {
135
                state = sd;
136
            }
137
            break;
138

    
139
        case comd:
140
            cmd = r;
141
            crc ^= r;
142

    
143
            if (r == DELIM) {
144
                state = src;
145
            } else if (r == TT_PROGM) {
146
                lim = PROGM_PACKET_SIZE;
147
                state = read;
148
            } else if (r == TT_PROGD) {
149
                lim = PROGD_PACKET_SIZE;
150
                state = read;
151
            } else {
152
                state = cs;
153
            }
154
            break;
155

    
156
        case read:
157
            mbuf[pos] = r;
158
            crc ^= r;
159
            pos++;
160

    
161
            if (pos == lim) {
162
                state = cs;
163
            }
164

    
165
            break;
166
       
167
        case cs:
168
            if (r == crc) {
169
                return cmd;
170
            } else {
171
                return TT_BAD;
172
            }
173

    
174
            break;
175

    
176
        default:
177
            return TT_BAD;
178
    }
179
  }
180
}
181

    
182
BOOTLOADER_SECTION void send_packet(uint8_t cmd) {
183
    uart_send_byte(DELIM);
184
    uart_send_byte(ADDR);
185
    uart_send_byte(SERVER);
186
    uart_send_byte(cmd);
187
    uart_send_byte(ACK_CRC ^ cmd);
188
}
189

    
190
//#define SPM_PAGESIZE 32
191
BOOTLOADER_SECTION void onboard_program_write(uint16_t page, uint8_t *buf) {
192
  uint16_t i;
193

    
194
  boot_page_erase (page);
195
  boot_spm_busy_wait ();      // Wait until the memory is erased.
196

    
197
  for (i=0; i < SPM_PAGESIZE; i+=2){
198
    // Set up little-endian word.
199
    boot_page_fill (i, buf[i] | (buf[i+1] <<8));
200
  }
201

    
202
  boot_page_write (page);     // Store buffer in flash page.
203
  boot_spm_busy_wait();       // Wait until the memory is written.
204
}
205

    
206
BOOTLOADER_SECTION void  __init(void) {
207
  uint8_t mbuf[PROGD_PACKET_SIZE];
208
  uint8_t jbuf[2];
209
  uint16_t caddr = MAIN_ADDR;
210
  uint8_t iteration = 0;
211
  uint8_t resp;
212
  uint16_t prog_len = 0;
213
  uint8_t i;
214

    
215
  init_uart(51); //MAGIC NUMBER??
216

    
217
  //set LED pin as output
218
  LED_DDR |= 0x07;
219
  PORTB = 0x07;
220

    
221
  //Start bootloading process
222
  send_packet(TT_BOOT);
223

    
224
  resp = parse_packet(mbuf);
225
  if (resp == TT_PROGM) {
226
    prog_len = mbuf[0];
227
    prog_len |= mbuf[1] << 8;
228
  } else {
229
      PORTB = 0;
230
      main_start();
231
  }
232
  send_packet(TT_ACK);
233

    
234
  while(1) {
235
      resp = parse_packet(mbuf);
236

    
237
      if (resp == TT_PROGD) {
238
          if (iteration == 0) {
239
              // Store the jump to user code
240
              jbuf[0] = mbuf[0];
241
              jbuf[1] = mbuf[1];
242

    
243
              *((uint16_t*)mbuf) = pgm_read_word(MAIN_ADDR);
244

    
245
              onboard_program_write(caddr, mbuf);
246
              iteration = 1;
247
              caddr += PROGD_PACKET_SIZE - 2;
248
          } else {
249
              onboard_program_write(caddr, mbuf);
250
              caddr += PROGD_PACKET_SIZE;
251
          }
252
      } else {
253
          main_start();
254
      }
255

    
256
      send_packet(TT_ACK);
257

    
258
      if (prog_len <= PROGD_PACKET_SIZE) {
259
          send_packet(TT_ACK);
260

    
261
          for (i = 0; i < PROGD_PACKET_SIZE; i++) {
262
              mbuf[i]= 0;
263
          }
264

    
265
          mbuf[PROGD_PACKET_SIZE-2] = jbuf[0];
266
          mbuf[PROGD_PACKET_SIZE-1] = jbuf[1];
267

    
268
          onboard_program_write(JUMP_ADDR, mbuf);
269

    
270
          PORTB = 0;
271
          main_start();
272
      } else { 
273
          prog_len -= PROGD_PACKET_SIZE;
274
      }
275
  }
276
}
277

    
278

    
279
int main (void) {
280
    while(1);
281
}