Subversion Repositories HomeAutomation

Rev

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