Subversion Repositories HomeAutomation

Rev

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

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