Subversion Repositories HomeAutomation

Rev

Details | Last modification | View Log | SVN | RSS feed

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