Subversion Repositories HomeAutomation

Rev

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

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