Subversion Repositories HomeAutomation

Rev

Rev 1034 | Rev 1040 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

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