Subversion Repositories HomeAutomation

Rev

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