Subversion Repositories HomeAutomation

Rev

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

Rev 294 Rev 315
Line 88... Line 88...
88
    gMilliSecTick++;
88
    gMilliSecTick++;
89
    wdt_reset();
89
    wdt_reset();
90
}
90
}
91
 
91
 
92
void Can_Process(Can_Message_t* msg) {
92
void Can_Process(Can_Message_t* msg) {
93
    if (!(msg->ExtendedFlag)) return;
93
    if (!(msg->ExtendedFlag)) return; // We don't care about standard CAN frames.
-
 
94
   
-
 
95
    if ((msg->Id & CAN_MASK_CLASS)>>CAN_SHIFT_CLASS == CAN_NMT) {
-
 
96
       
-
 
97
        if ((msg->Id & CAN_MASK_NMT_TYPE)>>CAN_SHIFT_NMT_TYPE == CAN_NMT_TIME) {
-
 
98
            // Reset watchdog as long as time messages from the master node
-
 
99
            // are received periodically. If anything hangs the CAN communication
-
 
100
            // or the master node is not up, the node will be reset.
-
 
101
            wdt_reset();
-
 
102
            //TODO: Don't care about time right now... Figure out what to do with it. 
-
 
103
        }
-
 
104
       
-
 
105
        if ((msg->Id & CAN_MASK_NMT_RID)>>CAN_SHIFT_NMT_RID == NODE_ID) {
94
   
106
 
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) {
107
            if ((msg->Id & CAN_MASK_NMT_TYPE)>>CAN_SHIFT_NMT_TYPE == CAN_NMT_RESET) {
99
                reset();
108
                reset();
100
            }
109
            }
101
            // Copy message to bios buffer if bios is done with the previous message.
110
            // 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
111
            // This is also a check to see if bios is still running. When app is
Line 104... Line 113...
104
            // NMT communication except reset is ignored. 
113
            // NMT communication except reset is ignored. 
105
            if (!(bios_msg_full)) {
114
            if (!(bios_msg_full)) {
106
                memcpy(bios_msg_ptr, msg, sizeof(Can_Message_t));
115
                memcpy(bios_msg_ptr, msg, sizeof(Can_Message_t));
107
                bios_msg_full = 1;
116
                bios_msg_full = 1;
108
            }
117
            }
109
        }      
118
        }      
110
    } else if (bios->can_callback) {
119
    } else if (bios->can_callback) {
111
        //printf("Calling app callback.\n");
120
        //printf("Calling app callback.\n");
112
        bios->can_callback(msg);
121
        bios->can_callback(msg);
113
    }
122
    }
114
}
123
}
115
 
124
 
116
#define BIOS_APP    1
125
#define BIOS_APP    1
117
#define BIOS_NOAPP  2
126
#define BIOS_NOAPP  2
118
#define BIOS_PGM    3
127
#define BIOS_PGM    3
119
 
128
 
120
int main() {
129
int main() {
121
    void (*app_reset)(void) = 0;
130
    void (*app_reset)(void) = 0; // Function pointer to jump to application reset vector.
122
    uint8_t bios_state;
131
    uint8_t bios_state;
123
    uint8_t nmt_type;
132
    uint8_t nmt_type;
-
 
133
    uint8_t pagebuf[SPM_PAGESIZE];
124
    // This unneccessary initialization uses 8 bytes flash, just to make the compiler happy!
134
    // These unneccessary initializations uses 12 bytes flash, just to make the compiler happy!
125
    uint16_t base_addr = 0;
135
    uint16_t base_addr = 0;
126
    uint16_t offset = 0;
136
    uint16_t offset = 0;
127
    uint16_t addr;
137
    uint16_t addr = 0;
128
    uint8_t len;
138
    uint8_t len;
129
    uint16_t i;
-
 
130
    uint16_t data;
139
    uint16_t data;
131
    uint8_t send_msg = 0;
140
    uint8_t send_msg = 0;
132
    Can_Message_t tx_msg;
141
    Can_Message_t tx_msg;
133
    Can_Message_t bios_msg;
142
    Can_Message_t bios_msg;
134
    bios_msg_ptr = &bios_msg;
143
    bios_msg_ptr = &bios_msg;
Line 139... Line 148...
139
    stdout = &bios_stdio;
148
    stdout = &bios_stdio;
140
    stdin = &bios_stdio;
149
    stdin = &bios_stdio;
141
#endif
150
#endif
142
   
151
   
143
    // Initialize a suitable hardware timer to create a 1KHz interrupt.
152
    // Initialize a suitable hardware timer to create a 1KHz interrupt.
-
 
153
    //TODO: Any point in having timebase in bios after wdt_reset() is moved to Can_Process?
144
    TIMEBASE_INIT();
154
    TIMEBASE_INIT();
145
   
155
   
146
    // Enable watchdog timer to protect against an application locking the
156
    // Enable watchdog timer to protect against an application locking the
147
    // node by leaving interrupts disabled. 
157
    // node by leaving interrupts disabled. 
148
    wdt_enable(WDTO_500MS);
158
    wdt_enable(WDTO_2S);
149
   
159
   
150
    // Move interrupt vectors to start of bootloader section and enable interrupts
160
    // Move interrupt vectors to start of bootloader section and enable interrupts
151
    IVSEL_REG = _BV(IVCE);
161
    IVSEL_REG = _BV(IVCE);
152
    IVSEL_REG = _BV(IVSEL);
162
    IVSEL_REG = _BV(IVSEL);
153
    sei();
163
    sei();
Line 162... Line 172...
162
#ifdef BIOS_UART
172
#ifdef BIOS_UART
163
    printf("BIOS start\n");
173
    printf("BIOS start\n");
164
#endif
174
#endif
165
    if (pgm_read_word(0) == 0xffff) {
175
    if (pgm_read_word(0) == 0xffff) {
166
        // No application in flash
176
        // No application in flash
167
        //send CAN_NMT_BIOS_START(BIOS_VERSION, 0)
177
        // Send CAN_NMT_BIOS_START(BIOS_VERSION, 0)
168
        tx_msg.Data.bytes[2] = 0;
178
        tx_msg.Data.bytes[2] = 0;
169
        bios_state = BIOS_NOAPP;
179
        bios_state = BIOS_NOAPP;
170
    } else {
180
    } else {
171
        // Application exists
181
        // Application exists
172
        //send CAN_NMT_BIOS_START(BIOS_VERSION, 1)
182
        // Send CAN_NMT_BIOS_START(BIOS_VERSION, 1)
173
        tx_msg.Data.bytes[2] = 1;
183
        tx_msg.Data.bytes[2] = 1;
174
        bios_state = BIOS_APP;
184
        bios_state = BIOS_APP;
175
    }
185
    }
176
   
186
   
177
    while (Can_Send(&tx_msg) != CAN_OK);
187
    while (Can_Send(&tx_msg) != CAN_OK);
178
 
188
 
179
    tx_msg.DataLength = 2;
189
    tx_msg.DataLength = 2; // All msg sent after BIOS_START are length 2 so set it once.
180
   
190
   
181
    // main loop
191
    // Main loop
182
    while (1) {
192
    while (1) {
183
        // Wait for message
193
        // Wait for message
184
        while (!bios_msg_full);
194
        while (!bios_msg_full);
-
 
195
       
185
        nmt_type = (bios_msg.Id & CAN_MASK_NMT_TYPE)>>CAN_SHIFT_NMT_TYPE;
196
        nmt_type = (bios_msg.Id & CAN_MASK_NMT_TYPE)>>CAN_SHIFT_NMT_TYPE;
186
       
197
       
187
        switch (bios_state) {
198
        switch (bios_state) {
188
        case BIOS_APP:
199
        case BIOS_APP:
189
            if (nmt_type == CAN_NMT_START_APP) {
200
            if (nmt_type == CAN_NMT_START_APP) {
Line 192... Line 203...
192
            // Fall through
203
            // Fall through
193
        case BIOS_NOAPP:
204
        case BIOS_NOAPP:
194
            if (nmt_type == CAN_NMT_PGM_START) {
205
            if (nmt_type == CAN_NMT_PGM_START) {
195
                // Set base address
206
                // Set base address
196
                base_addr = bios_msg.Data.words[0];
207
                base_addr = bios_msg.Data.words[0];
197
                flash_init();
208
                flash_init(pagebuf);
198
                //send CAN_NMT_PGM_ACK(offset)
209
                //send CAN_NMT_PGM_ACK(offset)
199
                tx_msg.Id = CAN_ID_NMT_PGM_ACK;
210
                tx_msg.Id = CAN_ID_NMT_PGM_ACK;
200
                tx_msg.Data.words[0] = base_addr;
211
                tx_msg.Data.words[0] = base_addr;
201
                send_msg = 1;
212
                send_msg = 1;
202
                bios_state = BIOS_PGM;
213
                bios_state = BIOS_PGM;
203
            }
214
            }
204
            if (nmt_type == CAN_NMT_PGM_COPY) {
215
            if (nmt_type == CAN_NMT_PGM_COPY) {
205
                // For BIOS updating over CAN. Upload bios to application area,
216
                // For BIOS updating over CAN. Upload bios to application area,
206
                // send this message with correct parameters to copy data from
217
                // send this message with correct parameters to copy data from
207
                // application to bios area and pray it will come alive again.
218
                // 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],
219
                flash_copy_data(bios_msg.Data.words[0],
212
                                bios_msg.Data.words[1],
220
                                bios_msg.Data.words[1],
213
                                bios_msg.Data.words[2]);
221
                                bios_msg.Data.words[2]);
214
                // flash_copy_data will never return.
222
                // flash_copy_data will never return.
215
            }
223
            }
216
            break;
224
            break;
217
        case BIOS_PGM:
225
        case BIOS_PGM:
218
            if (nmt_type == CAN_NMT_PGM_DATA) {
226
            if (nmt_type == CAN_NMT_PGM_DATA) {
219
                // Set address = base address + offset
227
                // Set address = base address + offset.
220
                offset = bios_msg.Data.words[0];
228
                offset = bios_msg.Data.words[0];
221
                addr = base_addr + offset;
229
                addr = base_addr + offset;
-
 
230
               
-
 
231
                // One of ACK and NACK will be sent, both have offset as data.
222
                tx_msg.Data.words[0] = offset;
232
                tx_msg.Data.words[0] = offset;
-
 
233
                send_msg = 1;
223
                // TODO: Check (addr + dlc) valid instead
234
                // Default to send CAN_NMT_PGM_ACK(offset)
224
                if (addr < (uint16_t)&__bios_start) { //address valid
235
                tx_msg.Id = CAN_ID_NMT_PGM_ACK;
-
 
236
 
225
                    //flash data at address
237
                // Flash all data sent, beginning at addr.
226
                    len = (bios_msg.DataLength+1)/2; // Number of words in message, rounded up.
238
                len = (bios_msg.DataLength+1)/2; // Number of words in message, rounded up.
-
 
239
                uint8_t i;
227
                    for (i=1; i<len; i++) { // Skip first word (offset)
240
                for (i=1; i<len; i++) { // Skip first word (offset).
-
 
241
                   
-
 
242
                    // Abort if trying to write in BIOS area.
-
 
243
                    if (addr >= (uint16_t)&__bios_start) {
-
 
244
                        // Send CAN_NMT_PGM_NACK(offset).
-
 
245
                        tx_msg.Id = CAN_ID_NMT_PGM_NACK;
-
 
246
                        break; //for loop
-
 
247
                    }
-
 
248
 
228
                        data = bios_msg.Data.words[i];
249
                    data = bios_msg.Data.words[i];
229
                        flash_write_word(addr, data);
250
                    flash_write_word(addr, data);
230
                        addr += 2;
251
                    addr += 2;
231
                    }
252
                }
232
                    //update crc //cannot update crc here, data not written yet /arune
253
                // Adjust addr if an odd number of bytes were sent, for use in crc calc.
233
                    offset += bios_msg.DataLength - 2;  //let offset be last address to simplify crc calc later
-
 
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)
254
                addr -= bios_msg.DataLength & 1;
238
                    tx_msg.Id = CAN_ID_NMT_PGM_NACK;
-
 
239
                }
-
 
240
                send_msg = 1;
-
 
241
            }
255
            }
242
            if (nmt_type == CAN_NMT_PGM_END) {
256
            if (nmt_type == CAN_NMT_PGM_END) {
-
 
257
                // Make sure a partly filled page will be flashed.
243
                flash_flush_buffer();
258
                flash_flush_buffer();
-
 
259
               
244
                //check crc
260
                // Calculate crc on written data.
-
 
261
                //TODO: This will not work if data is not sent sequentially without
-
 
262
                // holes, starting with offset=0. We might want to send a NACK if the
-
 
263
                // offset in a CAN_NMT_PGM_DATA msg differs from the expected offset.
245
                uint16_t calccrc = 0;
264
                uint16_t loc, crc = 0;
246
                for (i=0; i < offset; i++) {
265
                for (loc = base_addr; loc < addr - 2; loc++) { // addr will be last location written + 2.
247
                    calccrc = _crc16_update(calccrc, pgm_read_byte(base_addr+i));
266
                    crc = _crc16_update(crc, pgm_read_byte(loc));
248
                }
267
                }
-
 
268
               
249
                tx_msg.Data.words[0] = calccrc;
269
                tx_msg.Data.words[0] = crc;
250
                tx_msg.Id = CAN_ID_NMT_PGM_ACK;
270
                tx_msg.Id = CAN_ID_NMT_PGM_ACK;
251
                send_msg = 1;
271
                send_msg = 1;
252
                bios_state = BIOS_NOAPP;
272
                bios_state = BIOS_NOAPP;
253
            }
273
            }
254
        }
274
        }