Subversion Repositories HomeAutomation

Rev

Rev 453 | Rev 586 | 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
 
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 };
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;
295
                        pgs = dState.DONE;
296
                        break;
297
 
298
                    case dState.SEND_RESET:
299
                        // Send reset
300
                        cpn.doReset(dc, receiveID);
301
                        t = Environment.TickCount;
302
                        pgs = dState.DONE;
303
                        break;
304
 
305
 
306
                    case dState.DONE:
307
                        done = true;
308
                        //down.Abort();
309
                        if (!errorOccured) {
310
                            long tsecs = ((Environment.TickCount - timeStart) / 1000);
311
                            double bitRate = hf.getLength() / ((double)(Environment.TickCount - timeStart) / 1000.0);
312
 
313
                            if (tsecs <= 0) tsecs = 1;
314
                            long mins = tsecs / 60;
315
                            long secs = tsecs % 60;
316
                            string pad = "";
317
                            if (secs < 10) {
318
                                pad = "0";
319
                            }
320
                            Console.WriteLine("Time spent: " + mins + ":" + pad + secs + ", " + Math.Round(bitRate, 2) + " bytes/s");
321
                        }
322
                        //Console.Write("> ");
323
                        break;
324
                }
325
            }
326
 
327
        } catch(Exception) {
328
            Console.WriteLine("Exception occured");
329
            //Console.WriteLine(e);
330
            //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
331
 
332
        }
333
 
334
        return !errorOccured;
335
    }
336
}