Subversion Repositories HomeAutomation

Rev

Rev 250 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | SVN | RSS feed

Rev 250 Rev 253
Line 4... Line 4...
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
#include <stdio.h>
8
#include <stdio.h>
-
 
9
#include <string.h>
9
#include "flash.h"
10
#include "flash.h"
10
#include "vectors.h" // Must be included after sfr_defs.h but before any ISR()
11
#include "vectors.h" // Must be included after sfr_defs.h but before any ISR()
11
#include "mcp2515/mcp2515.h"
12
#include "mcp2515/mcp2515.h"
12
 
13
 
13
//---------------------------------------------------------------------------
14
//---------------------------------------------------------------------------
14
// Globals
15
// Globals
15
 
16
 
16
volatile long gMilliSecTick;
17
volatile long gMilliSecTick;
-
 
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
17
 
20
 
18
//---------------------------------------------------------------------------
21
//---------------------------------------------------------------------------
19
// Function definitions for the exported interface
22
// Function definitions for the exported interface
20
 
23
 
21
void reset(void) {
24
void reset(void) {
Line 49... Line 52...
49
    return res;
52
    return res;
50
}
53
}
51
 
54
 
52
// TODO: Insert can driver's Can_Send directly in bios interface.
55
// TODO: Insert can driver's Can_Send directly in bios interface.
53
Can_Return_t can_send(Can_Message_t* msg) {
56
Can_Return_t can_send(Can_Message_t* msg) {
54
    return CAN_FAIL;
57
    return Can_Send(msg);
55
}
58
}
56
 
-
 
57
//Can_Return_t can_receive(Can_Message_t *msg) {
-
 
58
//  return CAN_FAIL;
-
 
59
//}
-
 
60
 
59
 
61
//---------------------------------------------------------------------------
60
//---------------------------------------------------------------------------
62
// Function definitions for the private functions
61
// Function definitions for the private functions
63
 
62
 
64
static int console_getchar(FILE *stream) {
63
static int console_getchar(FILE *stream) {
Line 70... Line 69...
70
    return 0;
69
    return 0;
71
}
70
}
72
 
71
 
73
static FILE bios_stdio = FDEV_SETUP_STREAM(console_putchar, console_getchar,
72
static FILE bios_stdio = FDEV_SETUP_STREAM(console_putchar, console_getchar,
74
                                         _FDEV_SETUP_RW);
73
                                         _FDEV_SETUP_RW);
75
   
74
   
76
 
75
 
77
//---------------------------------------------------------------------------
76
//---------------------------------------------------------------------------
78
// Interrupt Service Routines
77
// Interrupt Service Routines
79
// Read app_vectors.h!
78
// Read app_vectors.h!
80
 
79
 
81
ISR(TIMEBASE_VECTOR) {
80
ISR(TIMEBASE_VECTOR) {
82
    TIMEBASE_COUNTER -= TIMEBASE_RELOAD;
81
    TIMEBASE_COUNTER -= TIMEBASE_RELOAD;
83
    gMilliSecTick++;
82
    gMilliSecTick++;
84
    wdt_reset();
83
    wdt_reset();
85
}
84
}
86
 
85
 
87
void Can_Process(Can_Message_t* msg) {
86
void Can_Process(Can_Message_t* msg) {
-
 
87
    if (!(msg->ExtendedFlag)) return;
-
 
88
   
88
    if (msg->ExtendedFlag && ((msg->Id & CAN_FUNCT_MASK) == CAN_MSG_TYPE_BIOS)) {
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)) {
89
        printf("BIOS received msg!\n");
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
        }      
90
    } else if (bios->can_callback) {
104
    } else if (bios->can_callback) {
91
        printf("Calling app callback.\n");
105
        //printf("Calling app callback.\n");
92
        bios->can_callback(msg);
106
        bios->can_callback(msg);
93
    } else {
-
 
94
        printf("BIOS received application msg but no handler installed!\n");
-
 
95
    }
107
    }
96
}
108
}
-
 
109
 
-
 
110
#define BIOS_APP    1
-
 
111
#define BIOS_NOAPP  2
-
 
112
#define BIOS_PGM    3
97
 
113
 
98
int main() {
114
int main() {
99
    void (*app_reset)(void) = 0;
115
    void (*app_reset)(void) = 0;
-
 
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;
100
   
127
   
101
    // Setup USART for debug channel
128
    // Setup USART for debug channel
102
    UART_INIT();
129
    UART_INIT();
103
    stdout = &bios_stdio;
130
    stdout = &bios_stdio;
104
    stdin = &bios_stdio;
131
    stdin = &bios_stdio;
105
   
132
   
106
    // Initialize a suitable hardware timer to create a 1KHz interrupt.
133
    // Initialize a suitable hardware timer to create a 1KHz interrupt.
107
    TIMEBASE_INIT();
134
    TIMEBASE_INIT();
108
   
135
   
109
    // Enable watchdog timer to protect against an application locking the
136
    // Enable watchdog timer to protect against an application locking the
110
    // node by leaving interrupts disabled. 
137
    // node by leaving interrupts disabled. 
Line 112... Line 139...
112
   
139
   
113
    // Move interrupt vectors to start of bootloader section and enable interrupts
140
    // Move interrupt vectors to start of bootloader section and enable interrupts
114
    IVSEL_REG = _BV(IVCE);
141
    IVSEL_REG = _BV(IVCE);
115
    IVSEL_REG = _BV(IVSEL);
142
    IVSEL_REG = _BV(IVSEL);
116
    sei();
143
    sei();
117
   
144
   
118
    printf("AVR BIOS\n");
145
    if (Can_Init() != CAN_OK) reset();
119
   
146
   
120
    if (pgm_read_word(0) != 0xffff) {
147
    tx_msg.RemoteFlag = 0;
-
 
148
    tx_msg.ExtendedFlag = 1;
121
        printf("Starting application.\n");
149
    tx_msg.Id = CAN_ID_NMT_BIOS_START;
122
        app_reset();
150
    tx_msg.DataLength = 3;
123
    }
-
 
124
   
-
 
125
    printf("No application found.\n");
151
    tx_msg.Data.words[0] = BIOS_VERSION;
126
   
152
           
127
    printf("\n------------------------------------------------------------\n");
153
    if (pgm_read_word(0) == 0xffff) {
128
    printf(  "   CAN Test: Periodic Transmission\n");
154
        // No application in flash
129
    printf(  "------------------------------------------------------------\n");
155
        //send CAN_NMT_BIOS_START(BIOS_VERSION, 0)
130
   
-
 
131
    printf("CanInit...\n");
156
        tx_msg.Data.bytes[2] = 0;
132
    if (Can_Init() != CAN_OK) {
157
        bios_state = BIOS_NOAPP;
133
        printf("FAILED!\n");
-
 
134
    }
-
 
135
    else {
158
    } else {
136
        printf("OK!\n");
159
        // Application exists
-
 
160
        //send CAN_NMT_BIOS_START(BIOS_VERSION, 1)
-
 
161
        tx_msg.Data.bytes[2] = 1;
-
 
162
        bios_state = BIOS_APP;
137
    }
163
    }
138
   
164
   
139
    uint32_t timeStamp = 0;
165
    while (Can_Send(&tx_msg) != CAN_OK);
140
   
166
 
141
    Can_Message_t txMsg;
-
 
142
    //The databytes are just what happens to be in the memory. They are never set.
-
 
143
    txMsg.RemoteFlag = 0;
-
 
144
    txMsg.ExtendedFlag = 1;
-
 
145
#define NODENUMBER 2
-
 
146
#if NODENUMBER == 1
-
 
147
    txMsg.Id = 16;
-
 
148
    txMsg.DataLength = 2;
167
    tx_msg.DataLength = 2;
149
#elif NODENUMBER == 2
-
 
150
    txMsg.Id = 32;
-
 
151
    txMsg.DataLength = 5;
-
 
152
#else
-
 
153
# error NODENUMBER not set!
-
 
154
#endif
-
 
155
   
168
   
156
    /* main loop */
169
    // main loop
157
    while (1) {
170
    while (1) {
-
 
171
        // Wait for message
-
 
172
        while (!bios_msg_full);
-
 
173
        nmt_type = (bios_msg.Id & CAN_MASK_NMT_TYPE)>>CAN_SHIFT_NMT_TYPE;
158
       
174
       
-
 
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
159
        /* send CAN message and check for CAN errors once every second */
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
            }
160
        if ((timebase_get() - timeStamp) >= 1000) {
211
            if (nmt_type == CAN_NMT_PGM_END) {
161
            timeStamp = timebase_get();
212
                flash_flush_buffer();
-
 
213
                //check crc
-
 
214
                //tx_msg.Data.words[0] = crc;
162
            /* send txMsg */
215
                if (1) { //crc ok
-
 
216
                    //send CAN_NMT_PGM_ACK(crc)
-
 
217
                    tx_msg.Id = CAN_ID_NMT_PGM_ACK;
163
            txMsg.Id++;
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
            }
164
            Can_Send(&txMsg);
224
            while (Can_Send(&tx_msg) != CAN_OK);
165
        }
225
        }
-
 
226
 
-
 
227
        bios_msg_full = 0; // We're done with this message, ready for the next.
166
    }
228
    }
167
 
229
 
168
    return 0;
230
    return 0;
169
}
231
}