Subversion Repositories HomeAutomation

Rev

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