Subversion Repositories HomeAutomation

Rev

Rev 1066 | 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.     this.myProgrammingCallback = progressCallback;
  104.     if (isBios)
  105.     {
  106.         this.myProgrammingIsBios = isBios;
  107.         this.myProgrammingBiosOffset = hexData.getAddrLower();
  108.         //this.myProgrammingCallback(true, "", "got IsBios, address: " + this.myProgrammingBiosOffset, false);
  109.     }
  110.     else
  111.     {
  112.         this.myProgrammingIsBios = false;
  113.     }
  114.    
  115.     this.myProgramming = true;
  116.     this.myProgrammingHex = hexData;
  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.         this.myProgrammingCallback(true, "ERROR", "Unexpected error 100", false);
  151.         break;
  152.     case "DONE":
  153.         this.stopProgramming(true, "Timeout while waiting for node to start bios");
  154.         this.reset();
  155.         break;
  156.     default:
  157.         this.myProgrammingCallback(true, "ERROR", "Unexpected error 101, state: " + this.myProgrammingState, false);
  158.         break;
  159.     }
  160. }
  161.  
  162. CanNode.prototype.programmingResend = function()
  163. {
  164. this.myProgrammingCallback(true, "", "Resend timeout, a packet was lost, either program data or ack", false);
  165.     this.myProgrammingResend.reset();
  166.     //if we did not got ack then try to resend the data
  167.     this.myProgrammingLastPacket.send();
  168. }
  169.  
  170. CanNode.prototype.handleBiosStart = function(biosVersion, hasApplication)
  171. {
  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.  
  184. //print("node was reset and bios just started, ver:" + biosVersion);
  185.     if (this.myProgramming)
  186.     {
  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;
  192.  
  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";
  201.        
  202.             var self = this;
  203.             this.myProgrammingTimeout.setTimeout(1000);
  204.        
  205.             this.myProgrammingResend = new Interval(function() { self.programmingResend() }, 1100);
  206.             this.myProgrammingResend.start();
  207.  
  208.             var date = new Date();
  209.             this.myProgrammingTimeStarted = date.getTime();
  210.  
  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.    
  235.     }
  236. }
  237.  
  238. CanNode.prototype.handleNack = function(data)
  239. {
  240.     this.stopProgramming(true, "Failed, got NACK, sending reset");
  241.     this.reset();
  242.     if (false) 
  243.     {
  244.     }
  245. }
  246.  
  247. CanNode.prototype.handleAck = function(data)
  248. {
  249.     this.myProgrammingTimeout.reset();
  250.  
  251.     if (data == this.myProgrammingWantAck) 
  252.     {
  253.         switch (this.myProgrammingState)
  254.         {
  255.         case "DATA":
  256.             var offset = this.myProgrammingHexOffset;
  257.             this.myProgrammingResend.setTimeout(100);
  258.             this.myProgrammingResend.reset();
  259.        
  260.             this.myProgrammingWantAck = ((offset<<8)|(offset>>8))&0xffff;
  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.            
  284.             canMessage.setData("Offset0", offset&0xff);
  285.             canMessage.setData("Offset1", (offset>>8)&0xff);
  286.             for (var i=0; i<bytesLeft && i<6; i++)
  287.             {
  288.                 switch (i)
  289.                 {
  290.                 case 0:
  291.                     canMessage.setData("Data0", this.myProgrammingHex.getByte(this.myProgrammingHexAddress+offset));
  292.                     break;
  293.                 case 1:
  294.                     canMessage.setData("Data1", this.myProgrammingHex.getByte(this.myProgrammingHexAddress+offset));
  295.                     break;
  296.                 case 2:
  297.                     canMessage.setData("Data2", this.myProgrammingHex.getByte(this.myProgrammingHexAddress+offset));
  298.                     break;
  299.                 case 3:
  300.                     canMessage.setData("Data3", this.myProgrammingHex.getByte(this.myProgrammingHexAddress+offset));
  301.                     break;
  302.                 case 4:
  303.                     canMessage.setData("Data4", this.myProgrammingHex.getByte(this.myProgrammingHexAddress+offset));
  304.                     break;
  305.                 case 5:
  306.                     canMessage.setData("Data5", this.myProgrammingHex.getByte(this.myProgrammingHexAddress+offset));
  307.                     break;
  308.                 }
  309.                 offset++;
  310.             }
  311.             canMessage.send();
  312.             this.myProgrammingHexOffset = offset;
  313.  
  314.             if (this.myProgrammingHexOffset >= this.myProgrammingHex.getLength()) {
  315.                 this.myProgrammingState = "END";
  316.             }
  317.            
  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;
  337.             break;
  338.        
  339.         case "END":
  340.             this.myProgrammingWantAck = ((this.myProgrammingHex.getCRC16()<<8)|(this.myProgrammingHex.getCRC16()>>8))&0xffff;
  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.            
  351.             var canMessage = new CanNMTMessage("nmt", "Pgm_End");
  352.             canMessage.send();
  353.  
  354.             this.myProgrammingState = "CRC";
  355.             for (var i=this.myProgrammingnrOfTicks; i<40; i++) this.myProgrammingCallback(true, "", " ", true);
  356.             this.myProgrammingCallback(true, "", "]", true);
  357.             this.myProgrammingCallback(true, "", "\r", true);
  358.             this.myProgrammingCallback(true, "", "100% [========================================]"+printTime, true);
  359.  
  360.             if (this.myProgrammingResend != null)
  361.             {
  362.                 /* Stop the interval */
  363.                 this.myProgrammingResend.stop();
  364.             }
  365.  
  366.             break;
  367.            
  368.         case "CRC":
  369.             this.myProgrammingTimeout.setTimeout(6000);
  370.             //is this a bios programming?
  371.             if (this.myProgrammingIsBios)
  372.             {
  373.                 this.myProgrammingState = "COPY";
  374.                 this.myProgrammingCallback(true, "\nBIOS", "Start to copy bios to new location", false);
  375.                 var canMessage = new CanNMTMessage("nmt", "Pgm_Copy");
  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);
  380.                 canMessage.setData("Length0", (this.myProgrammingHex.getLength())&0xff);
  381.                 canMessage.setData("Length1", (this.myProgrammingHex.getLength()>>8)&0xff);
  382.                 canMessage.send();
  383.                 //this.stopProgramming();
  384.             }
  385.             else
  386.             {
  387.                 this.myProgrammingState = "DONE";
  388.                 this.reset();
  389.             }
  390.             break;
  391.        
  392.         case "COPY":    //this will never occur, bios does not send ack for copy command, it just moves data in flash then reset itself
  393.             break;
  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.        
  413.         default:
  414.             this.myProgrammingCallback(true, "ERROR", "Unexpected error 104, state: " + this.myProgrammingState, false);
  415.             break;
  416.         }
  417.     }
  418.     else
  419.     {
  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
  434.             this.myProgrammingCallback(true, "ERROR", "Unexpected error 103", false);
  435.             break;
  436.         default:
  437.             this.myProgrammingCallback(true, "ERROR", "Unexpected error 102, state: " + this.myProgrammingState, false);
  438.             break;
  439.         }
  440.     }
  441. }
  442.  
  443. CanNode.prototype.stopProgramming = function(status, text)
  444. {
  445.     if (status && text)
  446.     {
  447.         this.myProgrammingCallback(status, "\nSTOP", text, false);
  448.     }
  449.  
  450.     this.myProgrammingIsBios = false;
  451.     this.myProgramming = false;
  452.     this.myProgrammingHex = new Array();
  453.     this.myProgrammingHexAddress = 0;
  454.     this.myProgrammingHexOffset = 0;
  455.     this.myProgrammingCallback = function() {};
  456.     this.myProgrammingWantAck = null;
  457.     this.myProgrammingState = "";
  458.     this.myProgrammingLastPercent = 0;
  459.     this.myProgrammingLastTenPercent = 0;
  460.     this.myProgrammingnrOfTicks = 0;
  461.     this.myProgrammingTimeStarted = 0;
  462.     this.myProgrammingBiosOffset = 0;
  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.  
  475.     CanProgrammingNode = null;
  476. }
  477.  
  478.  
  479.  
  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();
  509.         if (this.myHeartbeatTime + 10 < date.getTimestamp())
  510.         {
  511.             this.setOffline();
  512.         }
  513.     }
  514. }
  515.  
  516. CanNode.prototype.setOffline = function()
  517. {
  518.     if (this.myIsOnline)
  519.     {
  520.         this.myIsOnline = false;
  521.  
  522.         log(uint2hex(this.myHardwareId, 32) + "> Node went offline\n");
  523.        
  524.         for (var n in this.myModules)
  525.         {
  526.             this.myModules[n].setOffline();
  527.         }
  528.     }
  529. }
  530.