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