Subversion Repositories HomeAutomation

Rev

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