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