Subversion Repositories HomeAutomation

Rev

Rev 279 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed

Rev 279 Rev 283
1
#include "bios_funs.h"
1
#include "bios_funs.h"
2
#include "avr_cfg.h"
2
#include "avr_cfg.h"
3
#include <inttypes.h>
3
#include <inttypes.h>
4
#include <avr/io.h>
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
5
#include <avr/interrupt.h>
6
#include <avr/wdt.h>
6
#include <avr/wdt.h>
7
#include <avr/pgmspace.h>
7
#include <avr/pgmspace.h>
8
#ifdef BIOS_UART
8
#ifdef BIOS_UART
9
#include <stdio.h>
9
#include <stdio.h>
10
#endif
10
#endif
11
#include <string.h>
11
#include <string.h>
12
#include <util/crc16.h>
12
#include <util/crc16.h>
13
#include "flash.h"
13
#include "flash.h"
14
#include "vectors.h" // Must be included after sfr_defs.h but before any ISR()
14
#include "vectors.h" // Must be included after sfr_defs.h but before any ISR()
15
#include "mcp2515/mcp2515.h"
15
#include "mcp2515/mcp2515.h"
16
 
16
 
17
//---------------------------------------------------------------------------
17
//---------------------------------------------------------------------------
18
// Globals
18
// Globals
19
 
19
 
20
volatile uint32_t gMilliSecTick;
20
volatile uint32_t gMilliSecTick;
21
volatile uint8_t bios_msg_full;
21
volatile uint8_t bios_msg_full;
22
Can_Message_t* bios_msg_ptr; // only a pointer to main-local structure to save .bss space
22
Can_Message_t* bios_msg_ptr; // only a pointer to main-local structure to save .bss space
23
 
23
 
24
//---------------------------------------------------------------------------
24
//---------------------------------------------------------------------------
25
// Function definitions for the exported interface
25
// Function definitions for the exported interface
26
 
26
 
27
void reset(void) {
27
void reset(void) {
28
    //Just loop and let the watchdog reset
28
    //Just loop and let the watchdog reset
29
    cli();
29
    cli();
30
    while(1);
30
    while(1);
31
}
31
}
32
 
32
 
33
#ifdef BIOS_UART
33
#ifdef BIOS_UART
34
void bios_putchar(char c) {
34
void bios_putchar(char c) {
35
    UART_PUTCHAR(c);
35
    UART_PUTCHAR(c);
36
}
36
}
37
 
37
 
38
char bios_getchar(void) {
38
char bios_getchar(void) {
39
    char c;
39
    char c;
40
    UART_GETCHAR(c)
40
    UART_GETCHAR(c)
41
    return c;
41
    return c;
42
}
42
}
43
#endif
43
#endif
44
 
44
 
45
unsigned long timebase_get(void) {
45
unsigned long timebase_get(void) {
46
    uint8_t sreg;
46
    uint8_t sreg;
47
    unsigned long res;
47
    unsigned long res;
48
   
48
   
49
    //Disable interrupts while reading tick count
49
    //Disable interrupts while reading tick count
50
    sreg=SREG;
50
    sreg=SREG;
51
    cli();
51
    cli();
52
   
52
   
53
    res = gMilliSecTick;
53
    res = gMilliSecTick;
54
   
54
   
55
    SREG=sreg;
55
    SREG=sreg;
56
   
56
   
57
    return res;
57
    return res;
58
}
58
}
59
 
59
 
60
// TODO: Insert can driver's Can_Send directly in bios interface.
60
// TODO: Insert can driver's Can_Send directly in bios interface.
61
Can_Return_t can_send(Can_Message_t* msg) {
61
Can_Return_t can_send(Can_Message_t* msg) {
62
    return Can_Send(msg);
62
    return Can_Send(msg);
63
}
63
}
64
 
64
 
65
//---------------------------------------------------------------------------
65
//---------------------------------------------------------------------------
66
// Function definitions for the private functions
66
// Function definitions for the private functions
67
 
67
 
68
#ifdef BIOS_UART
68
#ifdef BIOS_UART
69
static int console_getchar(FILE *stream) {
69
static int console_getchar(FILE *stream) {
70
    return bios_getchar();
70
    return bios_getchar();
71
}
71
}
72
 
72
 
73
static int console_putchar(char c, FILE *stream) {
73
static int console_putchar(char c, FILE *stream) {
74
    bios_putchar(c);
74
    bios_putchar(c);
75
    return 0;
75
    return 0;
76
}
76
}
77
 
77
 
78
static FILE bios_stdio = FDEV_SETUP_STREAM(console_putchar, console_getchar,
78
static FILE bios_stdio = FDEV_SETUP_STREAM(console_putchar, console_getchar,
79
                                         _FDEV_SETUP_RW);
79
                                         _FDEV_SETUP_RW);
80
#endif
80
#endif
81
 
81
 
82
//---------------------------------------------------------------------------
82
//---------------------------------------------------------------------------
83
// Interrupt Service Routines
83
// Interrupt Service Routines
84
// Read app_vectors.h!
84
// Read app_vectors.h!
85
 
85
 
86
ISR(TIMEBASE_VECTOR) {
86
ISR(TIMEBASE_VECTOR) {
87
    TIMEBASE_COUNTER -= TIMEBASE_RELOAD;
87
    TIMEBASE_COUNTER -= TIMEBASE_RELOAD;
88
    gMilliSecTick++;
88
    gMilliSecTick++;
89
    wdt_reset();
89
    wdt_reset();
90
}
90
}
91
 
91
 
92
void Can_Process(Can_Message_t* msg) {
92
void Can_Process(Can_Message_t* msg) {
93
    if (!(msg->ExtendedFlag)) return;
93
    if (!(msg->ExtendedFlag)) return;
94
   
94
   
95
    if ((msg->Id & CAN_MASK_CLASS) == ((uint32_t)CAN_NMT << CAN_SHIFT_CLASS)) {
95
    if ((msg->Id & CAN_MASK_CLASS) == ((uint32_t)CAN_NMT << CAN_SHIFT_CLASS)) {
96
        if ((msg->Id & CAN_MASK_NMT_RID) == ((uint32_t)NODE_ID << CAN_SHIFT_NMT_RID)) {
96
        if ((msg->Id & CAN_MASK_NMT_RID) == ((uint32_t)NODE_ID << CAN_SHIFT_NMT_RID)) {
97
            //printf("BIOS received msg!\n");
97
            //printf("BIOS received msg!\n");
98
            if ((msg->Id & CAN_MASK_NMT_TYPE)>>CAN_SHIFT_NMT_TYPE == CAN_NMT_RESET) {
98
            if ((msg->Id & CAN_MASK_NMT_TYPE)>>CAN_SHIFT_NMT_TYPE == CAN_NMT_RESET) {
99
                reset();
99
                reset();
100
            }
100
            }
101
            // Copy message to bios buffer if bios is done with the previous message.
101
            // Copy message to bios buffer if bios is done with the previous message.
102
            // This is also a check to see if bios is still running. When app is
102
            // This is also a check to see if bios is still running. When app is
103
            // started, bios_msg_full is never reset to 0 so the check fails and all
103
            // started, bios_msg_full is never reset to 0 so the check fails and all
104
            // NMT communication except reset is ignored. 
104
            // NMT communication except reset is ignored. 
105
            if (!(bios_msg_full)) {
105
            if (!(bios_msg_full)) {
106
                memcpy(bios_msg_ptr, msg, sizeof(Can_Message_t));
106
                memcpy(bios_msg_ptr, msg, sizeof(Can_Message_t));
107
                bios_msg_full = 1;
107
                bios_msg_full = 1;
108
            }
108
            }
109
        }      
109
        }      
110
    } else if (bios->can_callback) {
110
    } else if (bios->can_callback) {
111
        //printf("Calling app callback.\n");
111
        //printf("Calling app callback.\n");
112
        bios->can_callback(msg);
112
        bios->can_callback(msg);
113
    }
113
    }
114
}
114
}
115
 
115
 
116
#define BIOS_APP    1
116
#define BIOS_APP    1
117
#define BIOS_NOAPP  2
117
#define BIOS_NOAPP  2
118
#define BIOS_PGM    3
118
#define BIOS_PGM    3
119
 
119
 
120
int main() {
120
int main() {
121
    void (*app_reset)(void) = 0;
121
    void (*app_reset)(void) = 0;
122
    uint8_t bios_state;
122
    uint8_t bios_state;
123
    uint8_t nmt_type;
123
    uint8_t nmt_type;
-
 
124
    // This unneccessary initialization uses 8 bytes flash, just to make the compiler happy!
124
    uint16_t base_addr = 0;
125
    uint16_t base_addr = 0;
125
    uint16_t offset;
126
    uint16_t offset = 0;
126
    uint16_t addr;
127
    uint16_t addr;
127
    uint8_t len;
128
    uint8_t len;
128
    uint8_t i;
129
    uint8_t i;
129
    uint16_t data;
130
    uint16_t data;
130
    Can_Message_t tx_msg;
131
    Can_Message_t tx_msg;
131
    Can_Message_t bios_msg;
132
    Can_Message_t bios_msg;
132
    bios_msg_ptr = &bios_msg;
133
    bios_msg_ptr = &bios_msg;
133
   
134
   
134
#ifdef BIOS_UART
135
#ifdef BIOS_UART
135
    // Setup USART for debug channel
136
    // Setup USART for debug channel
136
    UART_INIT();
137
    UART_INIT();
137
    stdout = &bios_stdio;
138
    stdout = &bios_stdio;
138
    stdin = &bios_stdio;
139
    stdin = &bios_stdio;
139
#endif
140
#endif
140
   
141
   
141
    // Initialize a suitable hardware timer to create a 1KHz interrupt.
142
    // Initialize a suitable hardware timer to create a 1KHz interrupt.
142
    TIMEBASE_INIT();
143
    TIMEBASE_INIT();
143
   
144
   
144
    // Enable watchdog timer to protect against an application locking the
145
    // Enable watchdog timer to protect against an application locking the
145
    // node by leaving interrupts disabled. 
146
    // node by leaving interrupts disabled. 
146
    wdt_enable(WDTO_500MS);
147
    wdt_enable(WDTO_500MS);
147
   
148
   
148
    // Move interrupt vectors to start of bootloader section and enable interrupts
149
    // Move interrupt vectors to start of bootloader section and enable interrupts
149
    IVSEL_REG = _BV(IVCE);
150
    IVSEL_REG = _BV(IVCE);
150
    IVSEL_REG = _BV(IVSEL);
151
    IVSEL_REG = _BV(IVSEL);
151
    sei();
152
    sei();
152
   
153
   
153
    if (Can_Init() != CAN_OK) reset();
154
    if (Can_Init() != CAN_OK) reset();
154
   
155
   
155
    tx_msg.RemoteFlag = 0;
156
    tx_msg.RemoteFlag = 0;
156
    tx_msg.ExtendedFlag = 1;
157
    tx_msg.ExtendedFlag = 1;
157
    tx_msg.Id = CAN_ID_NMT_BIOS_START;
158
    tx_msg.Id = CAN_ID_NMT_BIOS_START;
158
    tx_msg.DataLength = 3;
159
    tx_msg.DataLength = 3;
159
    tx_msg.Data.words[0] = BIOS_VERSION;
160
    tx_msg.Data.words[0] = BIOS_VERSION;
-
 
161
#ifdef BIOS_UART
160
    printf("BOIS start\n");
162
    printf("BIOS start\n");
-
 
163
#endif
161
    if (pgm_read_word(0) == 0xffff) {
164
    if (pgm_read_word(0) == 0xffff) {
162
        // No application in flash
165
        // No application in flash
163
        //send CAN_NMT_BIOS_START(BIOS_VERSION, 0)
166
        //send CAN_NMT_BIOS_START(BIOS_VERSION, 0)
164
        tx_msg.Data.bytes[2] = 0;
167
        tx_msg.Data.bytes[2] = 0;
165
        bios_state = BIOS_NOAPP;
168
        bios_state = BIOS_NOAPP;
166
    } else {
169
    } else {
167
        // Application exists
170
        // Application exists
168
        //send CAN_NMT_BIOS_START(BIOS_VERSION, 1)
171
        //send CAN_NMT_BIOS_START(BIOS_VERSION, 1)
169
        tx_msg.Data.bytes[2] = 1;
172
        tx_msg.Data.bytes[2] = 1;
170
        bios_state = BIOS_APP;
173
        bios_state = BIOS_APP;
171
    }
174
    }
172
   
175
   
173
    while (Can_Send(&tx_msg) != CAN_OK);
176
    while (Can_Send(&tx_msg) != CAN_OK);
174
 
177
 
175
    tx_msg.DataLength = 2;
178
    tx_msg.DataLength = 2;
176
   
179
   
177
    // main loop
180
    // main loop
178
    while (1) {
181
    while (1) {
179
        // Wait for message
182
        // Wait for message
180
        while (!bios_msg_full);
183
        while (!bios_msg_full);
181
        nmt_type = (bios_msg.Id & CAN_MASK_NMT_TYPE)>>CAN_SHIFT_NMT_TYPE;
184
        nmt_type = (bios_msg.Id & CAN_MASK_NMT_TYPE)>>CAN_SHIFT_NMT_TYPE;
182
       
185
       
183
        switch (bios_state) {
186
        switch (bios_state) {
184
        case BIOS_APP:
187
        case BIOS_APP:
185
            if (nmt_type == CAN_NMT_START_APP) {
188
            if (nmt_type == CAN_NMT_START_APP) {
186
                app_reset(); // Will never return
189
                app_reset(); // Will never return
187
            }
190
            }
188
            // Fall through
191
            // Fall through
189
        case BIOS_NOAPP:
192
        case BIOS_NOAPP:
190
            if (nmt_type == CAN_NMT_PGM_START) {
193
            if (nmt_type == CAN_NMT_PGM_START) {
191
                // Set base address
194
                // Set base address
192
                base_addr = bios_msg.Data.words[0];
195
                base_addr = bios_msg.Data.words[0];
193
                flash_init();
196
                flash_init();
194
                //send CAN_NMT_PGM_ACK(offset)
197
                //send CAN_NMT_PGM_ACK(offset)
195
                tx_msg.Id = CAN_ID_NMT_PGM_ACK;
198
                tx_msg.Id = CAN_ID_NMT_PGM_ACK;
196
                tx_msg.Data.words[0] = base_addr;
199
                tx_msg.Data.words[0] = base_addr;
197
                bios_state = BIOS_PGM;
200
                bios_state = BIOS_PGM;
-
 
201
            }
-
 
202
            if (nmt_type == CAN_NMT_PGM_COPY) {
-
 
203
                // For BIOS updating over CAN. Upload bios to application area,
-
 
204
                // send this message with correct parameters to copy data from
-
 
205
                // application to bios area and pray it will come alive again.
-
 
206
                // Make extra really super sure that the .bootloader section is
-
 
207
                // EXACTLY the same, except for the vector table (which MUST be
-
 
208
                // updated) or go get your ISP.
-
 
209
                flash_copy_data(bios_msg.Data.words[0],
-
 
210
                                bios_msg.Data.words[1],
-
 
211
                                bios_msg.Data.words[2]);
-
 
212
                // flash_copy_data will never return.
198
            }
213
            }
199
            break;
214
            break;
200
        case BIOS_PGM:
215
        case BIOS_PGM:
201
            if (nmt_type == CAN_NMT_PGM_DATA) {
216
            if (nmt_type == CAN_NMT_PGM_DATA) {
202
                // Set address = base address + offset
217
                // Set address = base address + offset
203
                offset = bios_msg.Data.words[0];
218
                offset = bios_msg.Data.words[0];
204
                addr = base_addr + offset;
219
                addr = base_addr + offset;
205
                tx_msg.Data.words[0] = offset;
220
                tx_msg.Data.words[0] = offset;
206
                // TODO: Check (addr + dlc) valid instead
221
                // TODO: Check (addr + dlc) valid instead
207
                if (addr < (uint16_t)&__bios_start) { //address valid
222
                if (addr < (uint16_t)&__bios_start) { //address valid
208
                    //flash data at address
223
                    //flash data at address
209
                    len = (bios_msg.DataLength+1)/2; // Number of words in message, rounded up.
224
                    len = (bios_msg.DataLength+1)/2; // Number of words in message, rounded up.
210
                    for (i=1; i<len; i++) { // Skip first word (offset)
225
                    for (i=1; i<len; i++) { // Skip first word (offset)
211
                        data = bios_msg.Data.words[i];
226
                        data = bios_msg.Data.words[i];
212
                        flash_write_word(addr, data);
227
                        flash_write_word(addr, data);
213
                        addr += 2;
228
                        addr += 2;
214
                    }
229
                    }
215
                    //update crc //cannot update crc here, data not written yet /arune
230
                    //update crc //cannot update crc here, data not written yet /arune
216
                    offset += bios_msg.DataLength - 2;  //let offset be last address to simplify crc calc later
231
                    offset += bios_msg.DataLength - 2;  //let offset be last address to simplify crc calc later
217
                    //send CAN_NMT_PGM_ACK(offset)
232
                    //send CAN_NMT_PGM_ACK(offset)
218
                    tx_msg.Id = CAN_ID_NMT_PGM_ACK;
233
                    tx_msg.Id = CAN_ID_NMT_PGM_ACK;
219
                } else {
234
                } else {
220
                    //send CAN_NMT_PGM_NACK(offset)
235
                    //send CAN_NMT_PGM_NACK(offset)
221
                    tx_msg.Id = CAN_ID_NMT_PGM_NACK;
236
                    tx_msg.Id = CAN_ID_NMT_PGM_NACK;
222
                }
237
                }
223
            }
238
            }
224
            if (nmt_type == CAN_NMT_PGM_END) {
239
            if (nmt_type == CAN_NMT_PGM_END) {
225
                flash_flush_buffer();
240
                flash_flush_buffer();
226
                //check crc
241
                //check crc
227
                data = bios_msg.Data.words[0];
242
                data = bios_msg.Data.words[0];
228
                uint16_t calccrc = 0;
243
                uint16_t calccrc = 0;
229
                for (i=0; i < offset; i++) {
244
                for (i=0; i < offset; i++) {
230
                    calccrc = _crc16_update(calccrc, pgm_read_byte(base_addr+i));
245
                    calccrc = _crc16_update(calccrc, pgm_read_byte(base_addr+i));
231
                }
246
                }
232
                tx_msg.Data.words[0] = calccrc;
247
                tx_msg.Data.words[0] = calccrc;
233
                if (data == calccrc) { //crc ok
248
                if (data == calccrc) { //crc ok
234
                    //send CAN_NMT_PGM_ACK(crc)
249
                    //send CAN_NMT_PGM_ACK(crc)
235
                    tx_msg.Id = CAN_ID_NMT_PGM_ACK;
250
                    tx_msg.Id = CAN_ID_NMT_PGM_ACK;
236
                } else {
251
                } else {
237
                    //send CAN_NMT_PGM_NACK(crc)
252
                    //send CAN_NMT_PGM_NACK(crc)
238
                    tx_msg.Id = CAN_ID_NMT_PGM_NACK;
253
                    tx_msg.Id = CAN_ID_NMT_PGM_NACK;
239
                }
254
                }
240
                bios_state = BIOS_NOAPP;
255
                bios_state = BIOS_NOAPP;
241
            }
256
            }
242
        }
257
        }
243
        while (Can_Send(&tx_msg) != CAN_OK);
258
        while (Can_Send(&tx_msg) != CAN_OK);
244
 
259
 
245
        bios_msg_full = 0; // We're done with this message, ready for the next.
260
        bios_msg_full = 0; // We're done with this message, ready for the next.
246
    }
261
    }
247
 
262
 
248
    return 0;
263
    return 0;
249
}
264
}
250
 
265