Subversion Repositories HomeAutomation

Rev

Rev 634 | Rev 770 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
453 arune 1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4
using System.Threading;
5
 
6
//this class should probably be integrated into canNMT instead
7
 
8
public class Downloader {
9
    private HexFile hf;
10
    private DaemonConnection dc;
11
    private bool isBiosUpdate;
12
    private ulong dlOffset = 0;
13
    //private Thread down;
14
    private byte receiveID;
15
 
586 arune 16
    private enum dState { SEND_START, WAIT_ACK_PRG, SEND_PGM_DATA, WAIT_ACK_DATA, RESEND_ADDR, WAIT_DONE, SEND_DONE, SEND_BIOS_UPDATE, SEND_RESET, DONE, DEBUG_STATE2, WAIT_BOOT, SEND_EMPTY_START, WAIT_ACK_PRG_EMPTY, SEND_EMPTY_DATA, WAIT_ACK_EMPTY_DATA, SEND_DONE_EMPTY, WAIT_DONE_EMPTY};
453 arune 17
 
18
    private const byte CAN_NMT              = 0x00;
19
 
20
    private const byte CAN_NMT_RESET        = 0x04;
21
    private const byte CAN_NMT_BIOS_START   = 0x08;
22
    private const byte CAN_NMT_PGM_START    = 0x0C;
23
    private const byte CAN_NMT_PGM_DATA     = 0x10;
24
    private const byte CAN_NMT_PGM_END      = 0x14;
25
    private const byte CAN_NMT_PGM_COPY     = 0x18;
26
    private const byte CAN_NMT_PGM_ACK      = 0x1C;
27
    private const byte CAN_NMT_PGM_NACK     = 0x20;
28
    private const byte CAN_NMT_START_APP    = 0x24;
29
    private const byte CAN_NMT_APP_START    = 0x28;
30
    private const byte CAN_NMT_HEARTBEAT    = 0x2C;
31
 
32
    private const byte MY_ID = 0x00;
33
    //private const byte TARGET_ID = 0x78;
34
    private const byte MY_NID = 0x0;
35
    private const byte ADDR0_INDEX = 0;
36
    private const byte ADDR1_INDEX = 1;
37
    private const byte ADDR2_INDEX = 2;
38
    private const byte ADDR3_INDEX = 3;
39
 
632 arune 40
    private const int TIMEOUT_MS = 1000;
41
    private const int TIMEOUT_SHORT_MS = 200;
453 arune 42
 
43
    private long timeStart = 0;
44
 
45
    public Downloader(HexFile hf, DaemonConnection dc, byte receiveID, bool isBiosUpdate) {
46
        this.hf = hf;
47
        this.dc = dc;
48
        this.receiveID = receiveID;
49
        this.isBiosUpdate = isBiosUpdate;
50
    }
51
 
52
    public int calcCRC(HexFile hf) {
53
        int crc=0;
54
        for (ulong i=hf.getAddrLower(); i <= hf.getAddrUpper(); i++) {
55
            crc = crc16_update(crc, hf.getByte(i));
56
        }
57
        return crc;
58
    }
59
 
60
    public int crc16_update(int crc, byte a) {
61
        int i;
62
        crc ^= a;
63
        for (i = 0; i < 8; ++i) {
64
            if ((crc & 1) != 0)
65
                crc = (crc >> 1) ^ 0xA001;
66
            else
67
                crc = (crc >> 1);
68
        }
69
        return crc;
70
    }
71
 
72
    public bool go() {
73
        if (dc==null || hf==null || hf.getLength()==0) return false;
74
        return downloader();
75
    }
76
 
77
    public void abort() {
78
        //if (down != null && down.IsAlive) down.Abort();
79
    }
80
 
81
    public bool downloader() {
82
        dState pgs = dState.SEND_START;
83
        int t = 0;
632 arune 84
        int t2 = 0;
453 arune 85
        CanPacket outCm = null;
86
        CanPacket cm = null;
87
        byte[] data = new byte[8];
88
        uint byteSent = 0;
89
        ulong currentAddress = 0;
90
        bool done = false;
91
        bool errorOccured = false;
92
 
93
        try {
94
            if (isBiosUpdate) {
95
                dlOffset = hf.getAddrLower();
96
                //Console.WriteLine(dlOffset);
97
                //dlOffset = 200;
98
            }
99
 
100
            CanNMT cpn = new CanNMT();
101
            cpn.setReceiver(receiveID);
102
            bool hasMessage = false;
103
 
104
            while (!done) {
105
                Thread.Sleep(1);
106
 
107
                switch (pgs) {
108
                    case dState.SEND_START:
109
                        // Send boot start packet to target.
110
                        // and wait for ack.
111
                        currentAddress = hf.getAddrLower();
112
                        //data[RID_INDEX] = TARGET_ID;
113
                        data[ADDR0_INDEX] = (byte)((currentAddress-dlOffset) & 0x0000FF);
114
                        data[ADDR1_INDEX] = (byte)(((currentAddress-dlOffset) & 0x00FF00) >> 8);
115
                        data[ADDR2_INDEX] = (byte)(((currentAddress-dlOffset) & 0xFF0000) >> 16);
116
                        data[ADDR3_INDEX] = 0;
117
                        //outCm = new CanPacket(CAN_NMT, CAN_NMT_PGM_START, MY_ID, receiveID, 4, data);
118
                        outCm = cpn.getPgmStartPacket(data);
119
                        dc.sendCanPacket(outCm);
120
                        t = Environment.TickCount;
632 arune 121
                        t2 = Environment.TickCount;
453 arune 122
                        pgs = dState.WAIT_ACK_PRG;
123
                        timeStart = Environment.TickCount;
124
                        break;
125
 
126
 
127
                    case dState.WAIT_ACK_PRG:
128
                        // Check for timeout, resend start packet in that case..
129
                        if ((Environment.TickCount - t) > TIMEOUT_MS) {
130
                            Console.WriteLine("Timeout while waiting for start prg ack.");
131
                            errorOccured = true;
132
                            pgs = dState.SEND_RESET;
133
                        }
467 arune 134
                        //Thread.Sleep(1);
453 arune 135
                        // If received ack.
136
                        hasMessage = dc.getData(out cm);
137
                        if (hasMessage) {
138
                            CanNMT cpnin = new CanNMT(cm);
139
                            if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
140
                                // If no error
141
                                if (cpnin.getType() == CAN_NMT_PGM_ACK) {
142
                                    // Start sending program data..
143
                                    byteSent = 0;
144
                                    pgs = dState.SEND_PGM_DATA;
145
                                }
146
                                else if (cpnin.getType() == CAN_NMT_PGM_NACK ) {
147
                                    // else ..
148
                                    Console.WriteLine("Nack on CAN_NMT_PGM_START.");
149
                                    errorOccured = true;
150
                                    pgs = dState.SEND_RESET;
151
                                }
152
 
153
                            }
154
                        }
155
                        break;
156
 
157
                    case dState.SEND_PGM_DATA:
158
                        //Console.WriteLine("byteSent = "+byteSent);
159
                        Console.Write(".");
160
                        // Send program data.
161
                        byte datalength = 2;
162
                        for (ulong i = 0; i < 6; i++) {
163
                            // Populate data.
164
                            data[i+2] = hf.getByte(currentAddress + i + byteSent);
165
                            if (currentAddress + i + byteSent > hf.getAddrUpper()) {
166
                                break;  //then done
167
                            }
168
                            datalength++;
169
                        }
170
                        data[0] = (byte)(byteSent & 0x00FF);
171
                        data[1] = (byte)((byteSent & 0xFF00) >> 8);
172
 
173
                        outCm = cpn.getPgmDataPacket(data, datalength);
174
                        dc.sendCanPacket(outCm);
175
 
176
                        t = Environment.TickCount;
632 arune 177
                        t2 = Environment.TickCount;
453 arune 178
                        byteSent += 6;
179
                        pgs = dState.WAIT_ACK_DATA;
180
                        break;
181
 
182
 
183
                    case dState.WAIT_ACK_DATA:
184
                        // Wait for pgm ack.
632 arune 185
                        if ((Environment.TickCount - t) > TIMEOUT_MS) {
453 arune 186
                            // Woops, error. 
187
                            Console.WriteLine("Timeout while waiting for data ack.");
188
                            errorOccured = true;
189
                            pgs = dState.SEND_RESET;
190
                        }
634 arune 191
                        else if ((Environment.TickCount - t2) > TIMEOUT_SHORT_MS) {
632 arune 192
                            // Woops, error. 
193
                            Console.Write(":");
194
                            byteSent -= 6;
195
                            pgs = dState.SEND_PGM_DATA;
196
                            break;
197
                        }
467 arune 198
                        //Thread.Sleep(1);
453 arune 199
                        // If received ack.
200
                        hasMessage = dc.getData(out cm);
201
                        if (hasMessage) {
202
                            CanNMT cpnin = new CanNMT(cm);
203
                            if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
204
                                // If no error
205
                                if (cpnin.getType() == CAN_NMT_PGM_ACK) {
206
                                    //currentAddress += 2;
207
                                    // Check if end.
208
                                    if (currentAddress + byteSent > hf.getAddrUpper()) {
209
                                        // Yes, we are done, send done.
210
                                        pgs = dState.SEND_DONE;
211
                                    }
212
                                    else {
213
                                        // More to write.
214
                                        //byteSent = 0;
215
                                        pgs = dState.SEND_PGM_DATA;
216
                                    }
217
                                }
218
                                else if (cpnin.getType() == CAN_NMT_PGM_NACK ) {
219
                                    // else ..
220
                                    Console.WriteLine("Nack on CAN_NMT_PGM_DATA.");
221
                                    errorOccured = true;
222
                                    pgs = dState.SEND_RESET;
223
                                }
224
 
225
                            }
226
                        }
227
                        break;
228
 
229
                    case dState.SEND_DONE:
230
                        // Send done
231
                        outCm = cpn.getPgmEndPacket();
232
                        dc.sendCanPacket(outCm);
233
 
234
                        t = Environment.TickCount;
632 arune 235
                        t2 = Environment.TickCount;
453 arune 236
                        pgs = dState.WAIT_DONE;
237
                        break;
238
 
239
 
240
                    case dState.WAIT_DONE:
241
                        // Check for timeout, resend done packet in that case..
242
                        if ((Environment.TickCount - t) > TIMEOUT_MS) {
243
                            Console.WriteLine("Timeout while waiting for end prg ack.");
244
                            errorOccured = true;
245
                            pgs = dState.SEND_RESET;
246
                        }
467 arune 247
                        //Thread.Sleep(1);
453 arune 248
 
249
                        hasMessage = dc.getData(out cm);
250
                        if (hasMessage) {
251
                            CanNMT cpnin = new CanNMT(cm);
252
                            if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
253
                                // If no error
254
                                if (cpnin.getType() == CAN_NMT_PGM_ACK) {
255
                                    Console.WriteLine("");
256
                                    //
257
                                    int crc = calcCRC(hf);
258
 
259
                                    if (cm.getDataLength() == 2) {
260
                                        byte[] cmdata = cm.getData();
261
                                        if ((cmdata[0] == (crc & 0xFF)) && (cmdata[1] == (crc>>8))) {
262
                                            if (!isBiosUpdate) {
263
                                                Console.WriteLine("Done, successfully programmed application.");
264
                                                pgs = dState.SEND_RESET;
265
                                            } else {
266
                                                Console.WriteLine("Done, successfully programmed bios to application space.");
267
                                                pgs = dState.SEND_BIOS_UPDATE;
268
                                            }
269
                                        } else {
270
                                            string nodecrc = String.Format("{0:x4}", (int)cmdata[0] + (int)(cmdata[1]<<8));
271
                                            nodecrc = "0x"+nodecrc;
272
                                            string realcrc = String.Format("{0:x4}", (int)(crc & 0xFF) + (int)(crc & 0xFF00));
273
                                            realcrc = "0x"+realcrc;
274
                                            Console.WriteLine("CRC failed. Node sent CRC "+nodecrc+" but should be "+realcrc+".");
275
                                            errorOccured = true;
276
                                            pgs = dState.SEND_RESET;
277
                                        }
278
 
279
                                        byteSent = 0;
280
                                    }
281
                                    //Console.WriteLine("crc: " + crc + " " + (crc>>8) + " " + (crc & 0xFF));
282
                                    //Console.WriteLine("ACKpkg with CRC: " + cm.ToString());
283
                                    // 
284
                                }
285
                                else if (cpnin.getType() == CAN_NMT_PGM_NACK) {
286
                                    // else resend addr..
287
                                    Console.WriteLine("Nack on CAN_NMT_PGM_END.");
288
                                    errorOccured = true;
289
                                    pgs = dState.SEND_RESET;
290
                                }
291
                            }
292
                        }
293
                        break;
294
 
295
                    case dState.SEND_BIOS_UPDATE:
296
                        data[0] = (byte)(0 & 0x00FF);
297
                        data[1] = (byte)((0 & 0xFF00) >> 8);
298
                        data[2] = (byte)(dlOffset & 0x00FF);
299
                        data[3] = (byte)((dlOffset & 0xFF00) >> 8);
300
                        data[4] = (byte)((hf.getAddrUpper()-hf.getAddrLower()+1) & 0x00FF);
301
                        data[5] = (byte)(((hf.getAddrUpper()-hf.getAddrLower()+1) & 0xFF00) >> 8);
302
 
303
                        outCm = cpn.getPgmCopyPacket(data);
304
                        Console.WriteLine("Now say a prayer, moving bios");
305
                        dc.sendCanPacket(outCm);
306
                        t = Environment.TickCount;
632 arune 307
                        t2 = Environment.TickCount;
586 arune 308
                        pgs = dState.WAIT_BOOT;
309
                        //pgs = dState.DONE;
453 arune 310
                        break;
586 arune 311
 
312
                    case dState.WAIT_BOOT:
313
                        // Wait for node reset answer (boot msg).
637 arune 314
                        if ((Environment.TickCount - t) > 3*TIMEOUT_MS) {
586 arune 315
                            // Woops, error. 
316
                            Console.WriteLine("Timeout while waiting for node to boot.");
317
                            errorOccured = true;
318
                            pgs = dState.SEND_DONE;
319
                        }
320
                        //Thread.Sleep(1);
321
                        // If received boot msg.
322
                        hasMessage = dc.getData(out cm);
323
                        if (hasMessage) {
324
                            CanNMT cpnin = new CanNMT(cm);
325
                            if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
326
                                // If no error
327
                                if (cpnin.getType() == CAN_NMT_BIOS_START) {
328
                                    pgs = dState.SEND_EMPTY_START;
329
                                }
330
                                else {
331
                                    // else ..
332
                                }
333
                            }
334
                        }
335
                        break;
453 arune 336
 
586 arune 337
                    case dState.SEND_EMPTY_START:
338
                        // Send boot start packet to target.
339
                        // and wait for ack.
340
 
341
                        //data[RID_INDEX] = TARGET_ID;
342
                        data[ADDR0_INDEX] = (byte)((0) & 0x0000FF);
343
                        data[ADDR1_INDEX] = (byte)(((0) & 0x00FF00) >> 8);
344
                        data[ADDR2_INDEX] = (byte)(((0) & 0xFF0000) >> 16);
345
                        data[ADDR3_INDEX] = 0;
346
                        //outCm = new CanPacket(CAN_NMT, CAN_NMT_PGM_START, MY_ID, receiveID, 4, data);
347
                        outCm = cpn.getPgmStartPacket(data);
348
                        dc.sendCanPacket(outCm);
349
                        t = Environment.TickCount;
632 arune 350
                        t2 = Environment.TickCount;
586 arune 351
                        pgs = dState.WAIT_ACK_PRG_EMPTY;
352
                        timeStart = Environment.TickCount;
353
                        break;
354
 
355
 
356
                    case dState.WAIT_ACK_PRG_EMPTY:
357
                        // Check for timeout, resend start packet in that case..
637 arune 358
                        if ((Environment.TickCount - t) > 3*TIMEOUT_MS) {
586 arune 359
                            Console.WriteLine("Timeout while waiting for start prg ack.");
360
                            errorOccured = true;
361
                            pgs = dState.SEND_RESET;
362
                        }
363
                        //Thread.Sleep(1);
364
                        // If received ack.
365
                        hasMessage = dc.getData(out cm);
366
                        if (hasMessage) {
367
                            CanNMT cpnin = new CanNMT(cm);
368
                            if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
369
                                // If no error
370
                                if (cpnin.getType() == CAN_NMT_PGM_ACK) {
371
                                    // Start sending program data..
372
                                    byteSent = 0;
373
                                    pgs = dState.SEND_EMPTY_DATA;
374
                                }
375
                                else if (cpnin.getType() == CAN_NMT_PGM_NACK ) {
376
                                    // else ..
377
                                    Console.WriteLine("Nack on CAN_NMT_PGM_START.");
378
                                    errorOccured = true;
379
                                    pgs = dState.SEND_RESET;
380
                                }
381
 
382
                            }
383
                        }
384
                        break;
385
 
386
                    case dState.SEND_EMPTY_DATA:
387
                        // Send program data.
388
                        data[0] = 0;
389
                        data[1] = 0;
390
                        data[2] = 0xff;
391
                        data[3] = 0xff;
392
 
393
                        outCm = cpn.getPgmDataPacket(data, 4);
394
                        dc.sendCanPacket(outCm);
395
 
396
                        t = Environment.TickCount;
632 arune 397
                        t2 = Environment.TickCount;
586 arune 398
                        byteSent += 6;
399
                        pgs = dState.WAIT_ACK_EMPTY_DATA;
400
                        break;
401
 
402
 
403
                    case dState.WAIT_ACK_EMPTY_DATA:
404
                        // Wait for pgm ack.
405
                        if ((Environment.TickCount - t) > 2*TIMEOUT_MS) {
406
                            // Woops, error. 
407
                            Console.WriteLine("Timeout while waiting for data ack.");
408
                            errorOccured = true;
409
                            pgs = dState.SEND_RESET;
410
                        }
411
                        //Thread.Sleep(1);
412
                        // If received ack.
413
                        hasMessage = dc.getData(out cm);
414
                        if (hasMessage) {
415
                            CanNMT cpnin = new CanNMT(cm);
416
                            if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
417
                                // If no error
418
                                if (cpnin.getType() == CAN_NMT_PGM_ACK) {
419
                                    pgs = dState.SEND_DONE_EMPTY;
420
                                }
421
                                else if (cpnin.getType() == CAN_NMT_PGM_NACK ) {
422
                                    // else ..
423
                                    Console.WriteLine("Nack on CAN_NMT_PGM_DATA.");
424
                                    errorOccured = true;
425
                                    pgs = dState.SEND_RESET;
426
                                }
427
 
428
                            }
429
                        }
430
                        break;
431
 
432
                    case dState.SEND_DONE_EMPTY:
433
                        // Send done
434
                        outCm = cpn.getPgmEndPacket();
435
                        dc.sendCanPacket(outCm);
436
 
437
                        t = Environment.TickCount;
632 arune 438
                        t2 = Environment.TickCount;
586 arune 439
                        pgs = dState.WAIT_DONE_EMPTY;
440
                        break;
441
 
442
 
443
                    case dState.WAIT_DONE_EMPTY:
444
                        // Check for timeout, resend done packet in that case..
445
                        if ((Environment.TickCount - t) > TIMEOUT_MS) {
446
                            Console.WriteLine("Timeout while waiting for end prg ack.");
447
                            errorOccured = true;
448
                            pgs = dState.SEND_RESET;
449
                        }
450
                        //Thread.Sleep(1);
451
 
452
                        hasMessage = dc.getData(out cm);
453
                        if (hasMessage) {
454
                            CanNMT cpnin = new CanNMT(cm);
455
                            if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
456
                                // If no error
457
                                if (cpnin.getType() == CAN_NMT_PGM_ACK) {
458
                                    Console.WriteLine("");
459
                                    //
460
                                    Console.WriteLine("Done, successfully cleaned application flash.");
461
                                    pgs = dState.SEND_RESET;
462
                                }
463
                                else if (cpnin.getType() == CAN_NMT_PGM_NACK) {
464
                                    // else resend addr..
465
                                    Console.WriteLine("Nack on CAN_NMT_PGM_END.");
466
                                    errorOccured = true;
467
                                    pgs = dState.SEND_RESET;
468
                                }
469
                            }
470
                        }
471
                        break;                     
453 arune 472
                    case dState.SEND_RESET:
473
                        // Send reset
474
                        cpn.doReset(dc, receiveID);
475
                        t = Environment.TickCount;
632 arune 476
                        t2 = Environment.TickCount;
453 arune 477
                        pgs = dState.DONE;
478
                        break;
479
 
480
 
481
                    case dState.DONE:
482
                        done = true;
483
                        //down.Abort();
484
                        if (!errorOccured) {
485
                            long tsecs = ((Environment.TickCount - timeStart) / 1000);
486
                            double bitRate = hf.getLength() / ((double)(Environment.TickCount - timeStart) / 1000.0);
487
 
488
                            if (tsecs <= 0) tsecs = 1;
489
                            long mins = tsecs / 60;
490
                            long secs = tsecs % 60;
491
                            string pad = "";
492
                            if (secs < 10) {
493
                                pad = "0";
494
                            }
495
                            Console.WriteLine("Time spent: " + mins + ":" + pad + secs + ", " + Math.Round(bitRate, 2) + " bytes/s");
496
                        }
497
                        //Console.Write("> ");
498
                        break;
499
                }
500
            }
501
 
502
        } catch(Exception) {
503
            Console.WriteLine("Exception occured");
504
            //Console.WriteLine(e);
505
            //skriva ut antal bytes skrivna vore bra här, kanske nån annan form av hjälp för debug, något gick snett liksom
506
 
507
        }
508
 
509
        return !errorOccured;
510
    }
511
}