Subversion Repositories HomeAutomation

Rev

Rev 1377 | Details | Compare with Previous | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
986 runge 1
 
2
function CanNode(hardwareId, numberOfModules)
3
{
4
    this.myHardwareId = hardwareId;
5
    this.myNumberOfModules = numberOfModules;
6
    this.myModules = new Array();
7
    this.myHeartbeatTime = 0;
8
    this.myIsOnline = false;
1008 runge 9
    this.stopProgramming();
986 runge 10
}
11
 
12
CanNode.prototype.myIsOnline = null;
13
CanNode.prototype.myHardwareId = null;
14
CanNode.prototype.myNumberOfModules = null;
15
CanNode.prototype.myModules = null;
16
CanNode.prototype.myHeartbeatTime = null;
1008 runge 17
CanNode.prototype.myProgrammingIsBios = null;
1043 arune 18
CanNode.prototype.myProgrammingBiosOffset = null;
1008 runge 19
CanNode.prototype.myProgramming = null;
20
CanNode.prototype.myProgrammingHex = null;
1013 arune 21
CanNode.prototype.myProgrammingHexAddress = null;
1020 arune 22
CanNode.prototype.myProgrammingOffset = null;
1008 runge 23
CanNode.prototype.myProgrammingCallback = null;
24
CanNode.prototype.myProgrammingWantAck = null;
1020 arune 25
CanNode.prototype.myProgrammingState = null;
1034 arune 26
CanNode.prototype.myProgrammingLastPercent = null;
27
CanNode.prototype.myProgrammingLastTenPercent = null;
28
CanNode.prototype.myProgrammingnrOfTicks = null;
29
CanNode.prototype.myProgrammingTimeout = null;
30
CanNode.prototype.myProgrammingResend = null;
31
CanNode.prototype.myProgrammingLastPacket = null;
1037 arune 32
CanNode.prototype.myProgrammingTimeStarted = null;
1040 runge 33
CanNode.prototype.myResetCallback = null;
34
CanNode.prototype.myResetTimer = null;
986 runge 35
 
36
CanNode.prototype.isOnline = function()
37
{
38
    return this.myIsOnline;
39
}
40
 
1008 runge 41
CanNode.prototype.start = function()
42
{
43
    var canMessage = new CanNMTMessage("nmt", "Start_App");
44
    canMessage.setData("HardwareId", this.myHardwareId);
45
    canMessage.send();
46
}
47
 
1040 runge 48
CanNode.prototype.reset = function(callback)
986 runge 49
{
1040 runge 50
    var self = this;
51
 
1042 runge 52
    if (callback)
1040 runge 53
    {
1042 runge 54
        this.myResetCallback = callback;
55
        if (this.myResetTimer)
56
        {
57
            this.myResetTimer.stop();
58
        }
59
 
60
        this.myResetTimer = new Interval(   function()
61
                            {
62
                                self.myResetTimer.stop();
63
                                self.myResetTimer = null;
64
                                self.myResetCallback(false);
65
                                self.myResetCallback = null;
66
                            }, 5000);
67
        this.myResetTimer.start();
1040 runge 68
    }
69
 
986 runge 70
    var canMessage = new CanNMTMessage("nmt", "Reset");
71
    canMessage.setData("HardwareId", this.myHardwareId);
1008 runge 72
    canMessage.send();
1040 runge 73
 
74
    this.setOffline();
986 runge 75
}
76
 
77
CanNode.prototype.startApplication = function()
78
{
79
    var canMessage = new CanNMTMessage("nmt", "Start_App");
80
    canMessage.setData("HardwareId", this.myHardwareId);
1008 runge 81
    canMessage.send();
986 runge 82
}
83
 
84
CanNode.prototype.handleHeartbeat = function(numberOfModules)
85
{
1008 runge 86
    if (numberOfModules)
986 runge 87
    {
1008 runge 88
        this.myNumberOfModules = numberOfModules;
89
    }
90
 
91
    if (this.myNumberOfModules == null || this.myNumberOfModules > this.myModules.length)
92
    {
986 runge 93
        var canMessage = new CanMessage("mnmt", "To_Owner", "", 0, "List");
94
        canMessage.setData("HardwareId", this.myHardwareId);
1008 runge 95
        canMessage.send();
986 runge 96
    }
97
 
98
    this.onlineHandler();
99
}
100
 
1008 runge 101
CanNode.prototype.startProgramming = function(hexData, progressCallback, isBios)
102
{
1063 arune 103
    this.myProgrammingCallback = progressCallback;
1008 runge 104
    if (isBios)
105
    {
1013 arune 106
        this.myProgrammingIsBios = isBios;
1043 arune 107
        this.myProgrammingBiosOffset = hexData.getAddrLower();
1063 arune 108
        //this.myProgrammingCallback(true, "", "got IsBios, address: " + this.myProgrammingBiosOffset, false);
1008 runge 109
    }
110
    else
111
    {
112
        this.myProgrammingIsBios = false;
113
    }
114
 
115
    this.myProgramming = true;
116
    this.myProgrammingHex = hexData;
117
 
1014 runge 118
    CanProgrammingNode = this;
119
 
1034 arune 120
    var self = this;
121
    this.myProgrammingTimeout = new Interval(function() { self.programmingTimeout() }, 6000);
122
    this.myProgrammingTimeout.start();
123
    this.myProgrammingState = "RESET";
124
 
1008 runge 125
    this.reset();
126
}
127
 
1034 arune 128
CanNode.prototype.programmingTimeout = function()
129
{
130
    switch (this.myProgrammingState)
131
    {
132
    case "RESET":
133
        this.stopProgramming(true, "Timeout while waiting for node to reset");
134
        this.reset();
135
        break;
136
    case "DATA":
137
        this.stopProgramming(true, "Timeout while waiting for node to ack data packet");
138
        this.reset();
139
        break;
140
    case "END":
141
        this.stopProgramming(true, "Timeout while waiting for node to ack data packet*");
142
        this.reset();
143
        break;
144
    case "CRC":
145
        this.stopProgramming(true, "Timeout while waiting for node to send crc");
146
        this.reset();
147
        break;
148
    case "COPY":
149
        //this will never occur, bios does not send ack for copy command, it just moves data in flash then reset itself
1063 arune 150
        this.myProgrammingCallback(true, "ERROR", "Unexpected error 100", false);
1034 arune 151
        break;
1066 arune 152
    case "DONE":
153
        this.stopProgramming(true, "Timeout while waiting for node to start bios");
154
        this.reset();
155
        break;
1034 arune 156
    default:
1063 arune 157
        this.myProgrammingCallback(true, "ERROR", "Unexpected error 101, state: " + this.myProgrammingState, false);
1034 arune 158
        break;
159
    }
160
}
161
 
162
CanNode.prototype.programmingResend = function()
163
{
1043 arune 164
this.myProgrammingCallback(true, "", "Resend timeout, a packet was lost, either program data or ack", false);
165
    this.myProgrammingResend.reset();
1034 arune 166
    //if we did not got ack then try to resend the data
167
    this.myProgrammingLastPacket.send();
168
}
169
 
1008 runge 170
CanNode.prototype.handleBiosStart = function(biosVersion, hasApplication)
171
{
1040 runge 172
    if (this.myResetCallback)
173
    {
174
        this.myResetCallback(true);
175
        this.myResetCallback = null;
176
    }
177
 
178
    if (this.myResetTimer)
179
    {
180
        this.myResetTimer.stop();
181
        this.myResetTimer = null;
182
    }
183
 
1013 arune 184
//print("node was reset and bios just started, ver:" + biosVersion);
1008 runge 185
    if (this.myProgramming)
186
    {
1063 arune 187
        switch (this.myProgrammingState)
188
        {
189
        case "RESET":
190
            this.myProgrammingHexAddress = this.myProgrammingHex.getAddrLower();
191
            this.myProgrammingWantAck = (((this.myProgrammingHexAddress-this.myProgrammingBiosOffset)<<8)|((this.myProgrammingHexAddress-this.myProgrammingBiosOffset)>>8))&0xffff;
1043 arune 192
 
1063 arune 193
            var canMessage = new CanNMTMessage("nmt", "Pgm_Start");
194
            canMessage.setData("HardwareId", this.myHardwareId);
195
            canMessage.setData("Address0", (this.myProgrammingHexAddress-this.myProgrammingBiosOffset)&0xff);
196
            canMessage.setData("Address1", ((this.myProgrammingHexAddress-this.myProgrammingBiosOffset)>>8)&0xff);
197
            canMessage.setData("Address3", ((this.myProgrammingHexAddress-this.myProgrammingBiosOffset)>>16)&0xff);
198
            canMessage.setData("Address4", ((this.myProgrammingHexAddress-this.myProgrammingBiosOffset)>>24)&0xff);
199
            canMessage.send();
200
            this.myProgrammingState = "DATA";
1008 runge 201
 
1063 arune 202
            var self = this;
203
            this.myProgrammingTimeout.setTimeout(1000);
1034 arune 204
 
1063 arune 205
            this.myProgrammingResend = new Interval(function() { self.programmingResend() }, 1100);
206
            this.myProgrammingResend.start();
1034 arune 207
 
1063 arune 208
            var date = new Date();
209
            this.myProgrammingTimeStarted = date.getTime();
1037 arune 210
 
1063 arune 211
            this.myProgrammingCallback(true, "START", "Started programming of node", false);
212
            this.myProgrammingCallback(true, "", "  0% [", true);
213
            break;
214
        case "COPY":
215
            //bios was moved and now started (so it seems like it was successfully programmed and moved)
216
            //now we should send a new programming with one empty packet to erase application area
217
            this.myProgrammingWantAck = 0;
218
            var canMessage = new CanNMTMessage("nmt", "Pgm_Start");
219
            canMessage.setData("HardwareId", this.myHardwareId);
220
            canMessage.setData("Address0", 0);
221
            canMessage.setData("Address1", 0);
222
            canMessage.setData("Address3", 0);
223
            canMessage.setData("Address4", 0);
224
            canMessage.send();
225
            this.myProgrammingState = "APPCLEANDATA";
226
            break;
227
        case "DONE":
228
            this.stopProgramming(true, "Done, successful");
229
            break;
230
        default:
231
            this.myProgrammingCallback(true, "ERROR", "Unexpected error 105, state: " + this.myProgrammingState, false);
232
            break;
233
        }
234
 
1008 runge 235
    }
236
}
237
 
1020 arune 238
CanNode.prototype.handleNack = function(data)
239
{
1043 arune 240
    this.stopProgramming(true, "Failed, got NACK, sending reset");
1020 arune 241
    this.reset();
242
    if (false) 
243
    {
244
    }
245
}
246
 
1008 runge 247
CanNode.prototype.handleAck = function(data)
248
{
1042 runge 249
    this.myProgrammingTimeout.reset();
1034 arune 250
 
1020 arune 251
    if (data == this.myProgrammingWantAck) 
1008 runge 252
    {
1020 arune 253
        switch (this.myProgrammingState)
1008 runge 254
        {
1020 arune 255
        case "DATA":
256
            var offset = this.myProgrammingHexOffset;
1043 arune 257
            this.myProgrammingResend.setTimeout(100);
258
            this.myProgrammingResend.reset();
1008 runge 259
 
1022 arune 260
            this.myProgrammingWantAck = ((offset<<8)|(offset>>8))&0xffff;
1020 arune 261
            var bytesLeft = this.myProgrammingHex.getLength() - this.myProgrammingHexOffset;
262
 
263
            //here we must handle the possibility that data is less then 48 bits
264
            var canMessage = new CanNMTMessage("nmt", "Pgm_Data_48");
265
            switch (bytesLeft)
266
            {
267
            case 1:
268
                canMessage = new CanNMTMessage("nmt", "Pgm_Data_8");
269
                break;
270
            case 2:
271
                canMessage = new CanNMTMessage("nmt", "Pgm_Data_16");
272
                break;
273
            case 3:
274
                canMessage = new CanNMTMessage("nmt", "Pgm_Data_24");
275
                break;
276
            case 4:
277
                canMessage = new CanNMTMessage("nmt", "Pgm_Data_32");
278
                break;
279
            case 5:
280
                canMessage = new CanNMTMessage("nmt", "Pgm_Data_40");
281
                break;
282
            }
283
 
1022 arune 284
            canMessage.setData("Offset0", offset&0xff);
285
            canMessage.setData("Offset1", (offset>>8)&0xff);
1020 arune 286
            for (var i=0; i<bytesLeft && i<6; i++)
287
            {
288
                switch (i)
289
                {
290
                case 0:
1043 arune 291
                    canMessage.setData("Data0", this.myProgrammingHex.getByte(this.myProgrammingHexAddress+offset));
1020 arune 292
                    break;
293
                case 1:
1043 arune 294
                    canMessage.setData("Data1", this.myProgrammingHex.getByte(this.myProgrammingHexAddress+offset));
1020 arune 295
                    break;
296
                case 2:
1043 arune 297
                    canMessage.setData("Data2", this.myProgrammingHex.getByte(this.myProgrammingHexAddress+offset));
1020 arune 298
                    break;
299
                case 3:
1043 arune 300
                    canMessage.setData("Data3", this.myProgrammingHex.getByte(this.myProgrammingHexAddress+offset));
1020 arune 301
                    break;
302
                case 4:
1043 arune 303
                    canMessage.setData("Data4", this.myProgrammingHex.getByte(this.myProgrammingHexAddress+offset));
1020 arune 304
                    break;
305
                case 5:
1043 arune 306
                    canMessage.setData("Data5", this.myProgrammingHex.getByte(this.myProgrammingHexAddress+offset));
1020 arune 307
                    break;
308
                }
309
                offset++;
310
            }
1008 runge 311
            canMessage.send();
1020 arune 312
            this.myProgrammingHexOffset = offset;
313
 
314
            if (this.myProgrammingHexOffset >= this.myProgrammingHex.getLength()) {
315
                this.myProgrammingState = "END";
316
            }
1008 runge 317
 
1034 arune 318
            //this.myProgrammingCallback(true, "PROGRESS", this.myProgrammingHexOffset + ":" + this.myProgrammingHex.getLength(), false);
319
            var percent = 100*this.myProgrammingHexOffset / this.myProgrammingHex.getLength();
320
            if (percent >= this.myProgrammingLastPercent+2.5)
321
            {
322
                this.myProgrammingCallback(true, "", "=", true);
323
                this.myProgrammingLastPercent+=2.5;
324
                this.myProgrammingnrOfTicks++;
325
            }
326
            if (percent > this.myProgrammingLastTenPercent+10)
327
            {
328
                for (var i=this.myProgrammingnrOfTicks; i<40; i++) this.myProgrammingCallback(true, "", " ", true);
329
                this.myProgrammingCallback(true, "", "]", true);
330
                this.myProgrammingCallback(true, "", "\r", true);
331
                this.myProgrammingCallback(true, "", " "+Math.round(percent)+"% [", true);
332
                this.myProgrammingLastTenPercent+=10;
333
                for (var i=0; i<this.myProgrammingnrOfTicks; i++) this.myProgrammingCallback(true, "", "=", true);
334
            }
335
 
336
            this.myProgrammingLastPacket = canMessage;
1008 runge 337
            break;
338
 
1020 arune 339
        case "END":
1022 arune 340
            this.myProgrammingWantAck = ((this.myProgrammingHex.getCRC16()<<8)|(this.myProgrammingHex.getCRC16()>>8))&0xffff;
1037 arune 341
 
342
            var timeElapsed = 0;
343
            var printTime = "";
344
            if (this.myProgrammingTimeStarted>0)
345
            {
346
                var date = new Date();
347
                timeElapsed = date.getTime() - this.myProgrammingTimeStarted;
348
                printTime = " in " + Math.round(timeElapsed/1000) + "s, " + Math.round(this.myProgrammingHex.getLength()*1000/timeElapsed)+"bytes/s";
349
            }
350
 
1008 runge 351
            var canMessage = new CanNMTMessage("nmt", "Pgm_End");
352
            canMessage.send();
1020 arune 353
 
354
            this.myProgrammingState = "CRC";
1034 arune 355
            for (var i=this.myProgrammingnrOfTicks; i<40; i++) this.myProgrammingCallback(true, "", " ", true);
356
            this.myProgrammingCallback(true, "", "]", true);
357
            this.myProgrammingCallback(true, "", "\r", true);
1037 arune 358
            this.myProgrammingCallback(true, "", "100% [========================================]"+printTime, true);
1034 arune 359
 
360
            if (this.myProgrammingResend != null)
361
            {
362
                /* Stop the interval */
363
                this.myProgrammingResend.stop();
364
            }
365
 
1020 arune 366
            break;
1008 runge 367
 
1020 arune 368
        case "CRC":
1066 arune 369
            this.myProgrammingTimeout.setTimeout(6000);
1020 arune 370
            //is this a bios programming?
1043 arune 371
            if (this.myProgrammingIsBios)
1020 arune 372
            {
373
                this.myProgrammingState = "COPY";
1043 arune 374
                this.myProgrammingCallback(true, "\nBIOS", "Start to copy bios to new location", false);
1020 arune 375
                var canMessage = new CanNMTMessage("nmt", "Pgm_Copy");
1043 arune 376
                canMessage.setData("Source0", 0);
377
                canMessage.setData("Source1", 0);
378
                canMessage.setData("Destination0", this.myProgrammingBiosOffset&0xff);
379
                canMessage.setData("Destination1", (this.myProgrammingBiosOffset>>8)&0xff);
1063 arune 380
                canMessage.setData("Length0", (this.myProgrammingHex.getLength())&0xff);
381
                canMessage.setData("Length1", (this.myProgrammingHex.getLength()>>8)&0xff);
1020 arune 382
                canMessage.send();
1063 arune 383
                //this.stopProgramming();
1020 arune 384
            }
385
            else
386
            {
1063 arune 387
                this.myProgrammingState = "DONE";
1020 arune 388
                this.reset();
389
            }
1008 runge 390
            break;
391
 
1020 arune 392
        case "COPY":    //this will never occur, bios does not send ack for copy command, it just moves data in flash then reset itself
1008 runge 393
            break;
1063 arune 394
        case "APPCLEANDATA":
395
            var canMessage = new CanNMTMessage("nmt", "Pgm_Data_16");
396
            this.myProgrammingWantAck = 0;
397
            this.myProgrammingState = "APPCLEANEND";
398
            canMessage.setData("Data0", 0xff);
399
            canMessage.setData("Data1", 0xff);
400
            canMessage.send();
401
            break;
402
        case "APPCLEANEND":
403
            this.myProgrammingWantAck = 0x1b0;
404
            this.myProgrammingState = "APPCLEANCRC";
405
            var canMessage = new CanNMTMessage("nmt", "Pgm_End");
406
            canMessage.send();
407
            break;
408
        case "APPCLEANCRC":
409
            this.myProgrammingState = "DONE";
410
            this.reset();
411
            break;
412
 
1008 runge 413
        default:
1063 arune 414
            this.myProgrammingCallback(true, "ERROR", "Unexpected error 104, state: " + this.myProgrammingState, false);
1020 arune 415
            break;
1008 runge 416
        }
417
    }
418
    else
419
    {
1020 arune 420
        switch (this.myProgrammingState)
421
        {
422
        case "DATA":
423
            //Fall through
424
        case "END":
425
            ///TODO: We got something that was not correct... we should abort
426
            this.stopProgramming(true, "Failed to program, ack had wrong offset, expected data: "+this.myProgrammingWantAck+" got: "+data);
427
            this.reset();
428
            break;
429
        case "CRC":
430
            this.stopProgramming(true, "Failed to program, CRC not matching, expected data: "+this.myProgrammingWantAck+" got: "+data);
431
            this.reset();
432
            break;
433
        case "COPY":    //this will never occur, bios does not send ack for copy command, it just moves data in flash then reset itself
1063 arune 434
            this.myProgrammingCallback(true, "ERROR", "Unexpected error 103", false);
1020 arune 435
            break;
436
        default:
1063 arune 437
            this.myProgrammingCallback(true, "ERROR", "Unexpected error 102, state: " + this.myProgrammingState, false);
1020 arune 438
            break;
439
        }
1008 runge 440
    }
441
}
442
 
443
CanNode.prototype.stopProgramming = function(status, text)
444
{
445
    if (status && text)
446
    {
1034 arune 447
        this.myProgrammingCallback(status, "\nSTOP", text, false);
1008 runge 448
    }
1020 arune 449
 
1008 runge 450
    this.myProgrammingIsBios = false;
451
    this.myProgramming = false;
452
    this.myProgrammingHex = new Array();
1013 arune 453
    this.myProgrammingHexAddress = 0;
1020 arune 454
    this.myProgrammingHexOffset = 0;
1008 runge 455
    this.myProgrammingCallback = function() {};
456
    this.myProgrammingWantAck = null;
1020 arune 457
    this.myProgrammingState = "";
1034 arune 458
    this.myProgrammingLastPercent = 0;
459
    this.myProgrammingLastTenPercent = 0;
460
    this.myProgrammingnrOfTicks = 0;
1037 arune 461
    this.myProgrammingTimeStarted = 0;
1043 arune 462
    this.myProgrammingBiosOffset = 0;
1034 arune 463
 
464
    if (this.myProgrammingTimeout != null)
465
    {
466
        /* Stop the interval */
467
        this.myProgrammingTimeout.stop();
468
    }
469
    if (this.myProgrammingResend != null)
470
    {
471
        /* Stop the interval */
472
        this.myProgrammingResend.stop();
473
    }
474
 
1014 runge 475
    CanProgrammingNode = null;
1008 runge 476
}
477
 
478
 
479
 
986 runge 480
CanNode.prototype.addService = function(sequenceNumber, service)
481
{
482
    this.myModules[sequenceNumber] = service;
483
    service.setOnline();
484
}
485
 
486
CanNode.prototype.onlineHandler = function()
487
{
488
    var date = new Date();
489
    this.myHeartbeatTime = date.getTimestamp();
490
 
491
    if (!this.myIsOnline)
492
    {
493
        this.myIsOnline = true;
494
 
495
        log(uint2hex(this.myHardwareId, 32) + "> Node went online\n");
496
 
497
        for (var n in this.myModules)
498
        {
499
            this.myModules[n].setOnline();
500
        }
501
    }
502
}
503
 
504
CanNode.prototype.checkOffline = function()
505
{
506
    if (this.myIsOnline)
507
    {
508
        var date = new Date();
1377 arune 509
        if (this.myHeartbeatTime + 21 < date.getTimestamp())
986 runge 510
        {
1380 linlun 511
            log(uint2hex(this.myHardwareId, 32) + "> Offline time: "+(date.getTimestamp()-this.myHeartbeatTime)+"\n");
986 runge 512
            this.setOffline();
513
        }
514
    }
515
}
516
 
517
CanNode.prototype.setOffline = function()
518
{
519
    if (this.myIsOnline)
520
    {
521
        this.myIsOnline = false;
522
 
523
        log(uint2hex(this.myHardwareId, 32) + "> Node went offline\n");
524
 
525
        for (var n in this.myModules)
526
        {
527
            this.myModules[n].setOffline();
528
        }
529
    }
530
}