Subversion Repositories HomeAutomation

Rev

Rev 1868 | Rev 2034 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
361 andfri 1
/*
2
 * $Id: bios.c 2032 2012-06-27 23:08:42Z pengi $
3
 */
1641 nattgris 4
 
361 andfri 5
#include <inttypes.h>
6
#include <avr/io.h>
7
#include <avr/interrupt.h>
8
#include <avr/wdt.h>
9
#include <avr/pgmspace.h>
10
#include <string.h>
11
#include <util/crc16.h>
12
#include <config.h>
13
#include <vectors.h> // Must be included after sfr_defs.h but before any ISR()
14
#include <drivers/can/can.h>
15
#include <flash.h>
16
#include <bios_export.h>
17
#include CAN_DRIVER_H
18
 
769 arune 19
#if !defined( NODE_HW_ID )
20
#error No NODE_HW_ID in bios.inc, set NODE_HW_ID=<GENERATE_HW> and Ill generate it for you
21
#endif
22
 
361 andfri 23
#if defined(__AVR_ATmega8__)
24
#define IVSEL_REG GICR
1468 arune 25
#elif defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__)
361 andfri 26
#define IVSEL_REG MCUCR
27
#else
28
#error AVR device not supported!
29
#endif
30
 
1629 arune 31
/* DEVICETYPE is sent in bios start frame */
32
#if defined(__AVR_ATmega8__)
1631 linlun 33
#define DEVICETYPE 1
1641 nattgris 34
#elif defined(__AVR_ATmega88__)
1631 linlun 35
#define DEVICETYPE 3
1630 arune 36
#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__)
1631 linlun 37
#define DEVICETYPE 4
1629 arune 38
#elif defined(__AVR_ATmega328P__)
1631 linlun 39
#define DEVICETYPE 5
1629 arune 40
#else
41
#error AVR device not supported!
42
#endif
43
 
585 arune 44
#if defined(AUTOSTART)
1641 nattgris 45
#if AUTOSTART == 0
585 arune 46
#error Please choose a higher AUTOSTART value in bios.inc, the nod will cease to work, and you can only reflash node with ISP
47
#endif
48
#if AUTOSTART == 1
49
#error Please choose a higher AUTOSTART value in bios.inc, there might be problems with updating software on node
50
#endif
51
#endif
52
 
361 andfri 53
//---------------------------------------------------------------------------
54
// Private declarations
55
 
56
volatile uint8_t bios_msg_full;
57
Can_Message_t* bios_msg_ptr; // only a pointer to main-local structure to save .bss space
1868 arune 58
extern char __bios_start; // Start of BIOS area in flash, from ld-script.
361 andfri 59
 
769 arune 60
prog_uint32_t hwid = NODE_HW_ID;
61
 
585 arune 62
#if defined(AUTOSTART)
63
uint8_t autostart_cnt;
64
#endif
65
 
1641 nattgris 66
#define BIOS_APP     1
67
#define BIOS_NOAPP   2
68
#define BIOS_PGM     3
69
#define BIOS_END_PGM 4
361 andfri 70
 
71
//---------------------------------------------------------------------------
72
// Private functions
73
 
74
void Can_Process(Can_Message_t* msg) {
75
    if (!(msg->ExtendedFlag)) return; // We don't care about standard CAN frames.
1641 nattgris 76
 
361 andfri 77
    if ((msg->Id & CAN_MASK_CLASS)>>CAN_SHIFT_CLASS == CAN_NMT) {
1641 nattgris 78
 
361 andfri 79
        if ((msg->Id & CAN_MASK_NMT_TYPE)>>CAN_SHIFT_NMT_TYPE == CAN_NMT_TIME) {
80
            // Reset watchdog as long as time messages from the master node
81
            // are received periodically. If anything hangs the CAN communication
82
            // or the master node is not up, the node will be reset.
83
            wdt_reset();
1641 nattgris 84
            //TODO: Don't care about time right now... Figure out what to do with it.
585 arune 85
#if defined(AUTOSTART)
86
            autostart_cnt++;
87
#endif
361 andfri 88
        }
1641 nattgris 89
 
90
        if (((msg->Id & CAN_MASK_NMT_TYPE)>>CAN_SHIFT_NMT_TYPE) == CAN_NMT_RESET
91
                && msg->DataLength == 4
92
                && msg->Data.bytes[0] == (hwid&0xff)
93
                && msg->Data.bytes[1] == ((hwid>>8)&0xff)
94
                && msg->Data.bytes[2] == ((hwid>>16)&0xff)
95
                && msg->Data.bytes[3] == ((hwid>>24)&0xff)) {
769 arune 96
            BIOS_Reset();
97
        }
98
        // Copy message to bios buffer if bios is done with the previous message.
99
        // This is also a check to see if bios is still running. When app is
100
        // started, bios_msg_full is never reset to 0 so the check fails and all
1641 nattgris 101
        // NMT communication except reset is ignored.
769 arune 102
        if (!(bios_msg_full)) {
103
            memcpy(bios_msg_ptr, msg, sizeof(Can_Message_t));
104
            bios_msg_full = 1;
105
        }
2032 pengi 106
    }
107
    if (BIOS_CanCallback) {
361 andfri 108
        //printf("Calling app callback.\n");
109
        BIOS_CanCallback(msg);
110
    }
111
}
112
 
563 andfri 113
int main(void) {
361 andfri 114
    void (*app_reset)(void) = 0; // Function pointer to jump to application reset vector.
115
    uint8_t bios_state;
116
    uint8_t nmt_type;
117
    uint8_t pagebuf[SPM_PAGESIZE];
118
    // These unneccessary initializations uses 12 bytes flash, just to make the compiler happy!
119
    uint16_t base_addr = 0;
120
    uint16_t offset = 0;
121
    uint16_t addr = 0;
122
    uint8_t len;
123
    uint16_t data;
124
    uint8_t send_msg = 0;
125
    Can_Message_t tx_msg;
126
    Can_Message_t bios_msg;
127
    bios_msg_ptr = &bios_msg;
585 arune 128
 
129
#if defined(AUTOSTART)
130
    autostart_cnt = 0;
131
#endif
132
 
361 andfri 133
    // Enable watchdog timer to protect against an application locking the
1641 nattgris 134
    // node by leaving interrupts disabled.
361 andfri 135
    wdt_enable(WDTO_2S);
1641 nattgris 136
 
361 andfri 137
    // Move interrupt vectors to start of bootloader section and enable interrupts
138
    IVSEL_REG = _BV(IVCE);
139
    IVSEL_REG = _BV(IVSEL);
140
    sei();
1641 nattgris 141
 
361 andfri 142
    if (Can_Init() != CAN_OK) BIOS_Reset();
1747 arune 143
#if defined(INITDDRB)
144
    DDRB=INITDDRB;
145
#endif
146
#if defined(INITDDRC)
147
    DDRC=INITDDRC;
148
#endif
149
#if defined(INITDDRD)
150
    DDRD=INITDDRD;
151
#endif
152
#if defined(INITPORTB)
153
    PORTB=INITPORTB;
154
#endif
155
#if defined(INITPORTC)
156
    PORTC=INITPORTC;
157
#endif
158
#if defined(INITPORTD)
159
    PORTD=INITPORTD;
160
#endif
161
#if defined(INITPINB)
162
    PINB=INITPINB;
163
#endif
164
#if defined(INITPINC)
165
    PINC=INITPINC;
166
#endif
167
#if defined(INITPIND)
168
    PIND=INITPIND;
169
#endif
1641 nattgris 170
 
1747 arune 171
 
361 andfri 172
    tx_msg.RemoteFlag = 0;
173
    tx_msg.ExtendedFlag = 1;
174
    tx_msg.Id = CAN_ID_NMT_BIOS_START;
769 arune 175
    tx_msg.DataLength = 8;
176
    tx_msg.Data.bytes[0] = BIOS_VERSION&0xff;
177
    tx_msg.Data.bytes[1] = (BIOS_VERSION>>8)&0xff;
1629 arune 178
    tx_msg.Data.bytes[3] = DEVICETYPE;
769 arune 179
    tx_msg.Data.bytes[4] = hwid&0xff;
180
    tx_msg.Data.bytes[5] = (hwid>>8)&0xff;
181
    tx_msg.Data.bytes[6] = (hwid>>16)&0xff;
182
    tx_msg.Data.bytes[7] = (hwid>>24)&0xff;
361 andfri 183
 
184
    if (pgm_read_word(0) == 0xffff) {
185
        // No application in flash
186
        // Send CAN_NMT_BIOS_START(BIOS_VERSION, 0)
187
        tx_msg.Data.bytes[2] = 0;
188
        bios_state = BIOS_NOAPP;
189
    } else {
190
        // Application exists
191
        // Send CAN_NMT_BIOS_START(BIOS_VERSION, 1)
192
        tx_msg.Data.bytes[2] = 1;
193
        bios_state = BIOS_APP;
194
    }
1641 nattgris 195
 
361 andfri 196
    while (Can_Send(&tx_msg) != CAN_OK);
197
 
198
    tx_msg.DataLength = 2; // All msg sent after BIOS_START are length 2 so set it once.
1641 nattgris 199
 
361 andfri 200
    // Main loop
201
    while (1) {
202
        // Wait for message
585 arune 203
        while (!bios_msg_full) {
204
#if defined(AUTOSTART)
205
            if (bios_state == BIOS_APP && autostart_cnt == AUTOSTART) {
206
                app_reset();
207
            }
208
#endif
209
        }
1641 nattgris 210
 
361 andfri 211
        nmt_type = (bios_msg.Id & CAN_MASK_NMT_TYPE)>>CAN_SHIFT_NMT_TYPE;
1641 nattgris 212
 
361 andfri 213
        switch (bios_state) {
214
        case BIOS_APP:
769 arune 215
            //if (nmt_type == CAN_NMT_START_APP) {
1641 nattgris 216
            if (nmt_type == CAN_NMT_START_APP
217
                    && bios_msg.DataLength == 4
218
                    && bios_msg.Data.bytes[0] == (hwid&0xff)
219
                    && bios_msg.Data.bytes[1] == ((hwid>>8)&0xff)
220
                    && bios_msg.Data.bytes[2] == ((hwid>>16)&0xff)
221
                    && bios_msg.Data.bytes[3] == ((hwid>>24)&0xff)) {
361 andfri 222
                app_reset(); // Will never return
223
            }
224
            // Fall through
225
        case BIOS_NOAPP:
769 arune 226
            //if (nmt_type == CAN_NMT_PGM_START) {
1641 nattgris 227
            if (nmt_type == CAN_NMT_PGM_START
228
                    && bios_msg.DataLength == 8
229
                    && bios_msg.Data.bytes[4] == (hwid&0xff)
230
                    && bios_msg.Data.bytes[5] == ((hwid>>8)&0xff)
231
                    && bios_msg.Data.bytes[6] == ((hwid>>16)&0xff)
232
                    && bios_msg.Data.bytes[7] == ((hwid>>24)&0xff)) {
361 andfri 233
                // Set base address
234
                base_addr = bios_msg.Data.words[0];
235
                flash_init(pagebuf);
236
                //send CAN_NMT_PGM_ACK(offset)
237
                tx_msg.Id = CAN_ID_NMT_PGM_ACK;
238
                tx_msg.Data.words[0] = base_addr;
239
                send_msg = 1;
240
                bios_state = BIOS_PGM;
241
            }
242
            break;
243
        case BIOS_PGM:
244
            // Default to send CAN_NMT_PGM_ACK(offset)
245
            tx_msg.Id = CAN_ID_NMT_PGM_ACK;
1641 nattgris 246
 
361 andfri 247
            if (nmt_type == CAN_NMT_PGM_DATA) {
248
                // Set address = base address + offset.
249
                offset = bios_msg.Data.words[0];
250
                addr = base_addr + offset;
1641 nattgris 251
 
361 andfri 252
                // One of ACK and NACK will be sent, both have offset as data.
253
                tx_msg.Data.words[0] = offset;
254
                send_msg = 1;
255
 
256
                // Flash all data sent, beginning at addr.
257
                len = (bios_msg.DataLength+1)/2; // Number of words in message, rounded up.
258
                uint8_t i;
259
                for (i=1; i<len; i++) { // Skip first word (offset).
1641 nattgris 260
 
361 andfri 261
                    // Abort if trying to write in BIOS area.
262
                    if (addr >= (uint16_t)&__bios_start) {
263
                        // Send CAN_NMT_PGM_NACK(offset).
264
                        tx_msg.Id = CAN_ID_NMT_PGM_NACK;
265
                        break; //for loop
266
                    }
267
 
268
                    data = bios_msg.Data.words[i];
269
                    flash_write_word(addr, data);
270
                    addr += 2;
271
                }
272
                // Adjust addr if an odd number of bytes were sent, for use in crc calc.
1641 nattgris 273
                addr -= bios_msg.DataLength & 1;
361 andfri 274
            }
275
            if (nmt_type == CAN_NMT_PGM_END) {
276
                // Make sure a partly filled page will be flashed.
277
                flash_flush_buffer();
1641 nattgris 278
 
361 andfri 279
                // Calculate crc on written data.
280
                //TODO: This will not work if data is not sent sequentially without
281
                // holes, starting with offset=0. We might want to send a NACK if the
282
                // offset in a CAN_NMT_PGM_DATA msg differs from the expected offset.
283
                uint16_t loc, crc = 0;
284
                for (loc = base_addr; loc < addr; loc++) { // addr will be last location written + 2.
285
                    crc = _crc16_update(crc, pgm_read_byte(loc));
286
                }
1641 nattgris 287
 
361 andfri 288
                tx_msg.Data.words[0] = crc;
289
                send_msg = 1;
769 arune 290
                bios_state = BIOS_END_PGM;
361 andfri 291
            }
769 arune 292
            break;
293
        case BIOS_END_PGM:
294
            if (nmt_type == CAN_NMT_PGM_COPY) {
295
                // For BIOS updating over CAN. Upload bios to application area,
296
                // send this message with correct parameters to copy data from
297
                // application to bios area and pray it will come alive again.
1641 nattgris 298
                flash_copy_data(bios_msg.Data.words[0],
299
                                bios_msg.Data.words[1],
769 arune 300
                                bios_msg.Data.words[2]);
301
                // flash_copy_data will never return.
302
            }
361 andfri 303
        }
1641 nattgris 304
 
361 andfri 305
        if (send_msg) {
306
            while (Can_Send(&tx_msg) != CAN_OK);
307
            send_msg = 0;
308
        }
309
 
310
        bios_msg_full = 0; // We're done with this message, ready for the next.
311
    }
312
 
313
    return 0;
314
}