Subversion Repositories HomeAutomation

Rev

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

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Threading;
  5.  
  6. //this class should probably be integrated into canNMT instead
  7.  
  8. public class Downloader {
  9.     private HexFile hf;
  10.     private DaemonConnection dc;
  11.     private bool isBiosUpdate;
  12.     private ulong dlOffset = 0;
  13.     //private Thread down;
  14.     private byte receiveID;
  15.    
  16.     private enum dState { SEND_START, WAIT_ACK_PRG, SEND_PGM_DATA, WAIT_ACK_DATA, RESEND_ADDR, WAIT_DONE, SEND_DONE, SEND_BIOS_UPDATE, SEND_RESET, DONE, DEBUG_STATE2, WAIT_BOOT, SEND_EMPTY_START, WAIT_ACK_PRG_EMPTY, SEND_EMPTY_DATA, WAIT_ACK_EMPTY_DATA, SEND_DONE_EMPTY, WAIT_DONE_EMPTY};
  17.    
  18.     private const byte CAN_NMT              = 0x00;
  19.    
  20.     private const byte CAN_NMT_RESET        = 0x04;
  21.     private const byte CAN_NMT_BIOS_START   = 0x08;
  22.     private const byte CAN_NMT_PGM_START    = 0x0C;
  23.     private const byte CAN_NMT_PGM_DATA     = 0x10;
  24.     private const byte CAN_NMT_PGM_END      = 0x14;
  25.     private const byte CAN_NMT_PGM_COPY     = 0x18;
  26.     private const byte CAN_NMT_PGM_ACK      = 0x1C;
  27.     private const byte CAN_NMT_PGM_NACK     = 0x20;
  28.     private const byte CAN_NMT_START_APP    = 0x24;
  29.     private const byte CAN_NMT_APP_START    = 0x28;
  30.     private const byte CAN_NMT_HEARTBEAT    = 0x2C;
  31.    
  32.     private const byte MY_ID = 0x00;
  33.     //private const byte TARGET_ID = 0x78;
  34.     private const byte MY_NID = 0x0;
  35.     private const byte ADDR0_INDEX = 0;
  36.     private const byte ADDR1_INDEX = 1;
  37.     private const byte ADDR2_INDEX = 2;
  38.     private const byte ADDR3_INDEX = 3;
  39.    
  40.     private const int TIMEOUT_MS = 1000;
  41.     private const int TIMEOUT_SHORT_MS = 200;
  42.    
  43.     private long timeStart = 0;
  44.    
  45.     public Downloader(HexFile hf, DaemonConnection dc, byte receiveID, bool isBiosUpdate) {
  46.         this.hf = hf;
  47.         this.dc = dc;
  48.         this.receiveID = receiveID;
  49.         this.isBiosUpdate = isBiosUpdate;
  50.     }
  51.    
  52.     public int calcCRC(HexFile hf) {
  53.         int crc=0;
  54.         for (ulong i=hf.getAddrLower(); i <= hf.getAddrUpper(); i++) {
  55.             crc = crc16_update(crc, hf.getByte(i));
  56.         }
  57.         return crc;
  58.     }
  59.    
  60.     public int crc16_update(int crc, byte a) {
  61.         int i;
  62.         crc ^= a;
  63.         for (i = 0; i < 8; ++i) {
  64.             if ((crc & 1) != 0)
  65.                 crc = (crc >> 1) ^ 0xA001;
  66.             else
  67.                 crc = (crc >> 1);
  68.         }
  69.         return crc;
  70.     }
  71.    
  72.     public bool go() {
  73.         if (dc==null || hf==null || hf.getLength()==0) return false;
  74.         return downloader();
  75.     }
  76.    
  77.     public void abort() {
  78.         //if (down != null && down.IsAlive) down.Abort();
  79.     }
  80.    
  81.     public bool downloader() {
  82.         dState pgs = dState.SEND_START;
  83.         int t = 0;
  84.         int t2 = 0;
  85.         CanPacket outCm = null;
  86.         CanPacket cm = null;
  87.         byte[] data = new byte[8];
  88.         uint byteSent = 0;
  89.         ulong currentAddress = 0;
  90.         bool done = false;
  91.         bool errorOccured = false;
  92.        
  93.         try {
  94.             if (isBiosUpdate) {
  95.                 dlOffset = hf.getAddrLower();
  96.                 //Console.WriteLine(dlOffset);
  97.                 //dlOffset = 200;
  98.             }
  99.  
  100.             CanNMT cpn = new CanNMT();
  101.             cpn.setReceiver(receiveID);
  102.             bool hasMessage = false;
  103.            
  104.             while (!done) {
  105.                 Thread.Sleep(1);
  106.                
  107.                 switch (pgs) {
  108.                     case dState.SEND_START:
  109.                         // Send boot start packet to target.
  110.                         // and wait for ack.
  111.                         currentAddress = hf.getAddrLower();
  112.                         //data[RID_INDEX] = TARGET_ID;
  113.                         data[ADDR0_INDEX] = (byte)((currentAddress-dlOffset) & 0x0000FF);
  114.                         data[ADDR1_INDEX] = (byte)(((currentAddress-dlOffset) & 0x00FF00) >> 8);
  115.                         data[ADDR2_INDEX] = (byte)(((currentAddress-dlOffset) & 0xFF0000) >> 16);
  116.                         data[ADDR3_INDEX] = 0;
  117.                         //outCm = new CanPacket(CAN_NMT, CAN_NMT_PGM_START, MY_ID, receiveID, 4, data);
  118.                         outCm = cpn.getPgmStartPacket(data);
  119.                         dc.sendCanPacket(outCm);
  120.                         t = Environment.TickCount;
  121.                         t2 = Environment.TickCount;
  122.                         pgs = dState.WAIT_ACK_PRG;
  123.                         timeStart = Environment.TickCount;
  124.                         break;
  125.                    
  126.                    
  127.                     case dState.WAIT_ACK_PRG:
  128.                         // Check for timeout, resend start packet in that case..
  129.                         if ((Environment.TickCount - t) > TIMEOUT_MS) {
  130.                             Console.WriteLine("Timeout while waiting for start prg ack.");
  131.                             errorOccured = true;
  132.                             pgs = dState.SEND_RESET;
  133.                         }
  134.                         //Thread.Sleep(1);
  135.                         // If received ack.
  136.                         hasMessage = dc.getData(out cm);
  137.                         if (hasMessage) {
  138.                             CanNMT cpnin = new CanNMT(cm);
  139.                             if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
  140.                                 // If no error
  141.                                 if (cpnin.getType() == CAN_NMT_PGM_ACK) {
  142.                                     // Start sending program data..
  143.                                     byteSent = 0;
  144.                                     pgs = dState.SEND_PGM_DATA;
  145.                                 }
  146.                                 else if (cpnin.getType() == CAN_NMT_PGM_NACK ) {
  147.                                     // else ..
  148.                                     Console.WriteLine("Nack on CAN_NMT_PGM_START.");
  149.                                     errorOccured = true;
  150.                                     pgs = dState.SEND_RESET;
  151.                                 }
  152.                                
  153.                             }
  154.                         }
  155.                         break;
  156.                        
  157.                     case dState.SEND_PGM_DATA:
  158.                         //Console.WriteLine("byteSent = "+byteSent);
  159.                         Console.Write(".");
  160.                         // Send program data.
  161.                         byte datalength = 2;
  162.                         for (ulong i = 0; i < 6; i++) {
  163.                             // Populate data.
  164.                             data[i+2] = hf.getByte(currentAddress + i + byteSent);
  165.                             if (currentAddress + i + byteSent > hf.getAddrUpper()) {
  166.                                 break;  //then done
  167.                             }
  168.                             datalength++;
  169.                         }
  170.                         data[0] = (byte)(byteSent & 0x00FF);
  171.                         data[1] = (byte)((byteSent & 0xFF00) >> 8);
  172.  
  173.                         outCm = cpn.getPgmDataPacket(data, datalength);
  174.                         dc.sendCanPacket(outCm);
  175.                        
  176.                         t = Environment.TickCount;
  177.                         t2 = Environment.TickCount;
  178.                         byteSent += 6;
  179.                         pgs = dState.WAIT_ACK_DATA;
  180.                         break;
  181.                        
  182.                        
  183.                     case dState.WAIT_ACK_DATA:
  184.                         // Wait for pgm ack.
  185.                         if ((Environment.TickCount - t) > TIMEOUT_MS) {
  186.                             // Woops, error.
  187.                             Console.WriteLine("Timeout while waiting for data ack.");
  188.                             errorOccured = true;
  189.                             pgs = dState.SEND_RESET;
  190.                         }
  191.                         if ((Environment.TickCount - t2) > TIMEOUT_SHORT_MS) {
  192.                             // Woops, error.
  193.                             Console.Write(":");
  194.                             byteSent -= 6;
  195.                             pgs = dState.SEND_PGM_DATA;
  196.                             break;
  197.                         }
  198.                         //Thread.Sleep(1);
  199.                         // If received ack.
  200.                         hasMessage = dc.getData(out cm);
  201.                         if (hasMessage) {
  202.                             CanNMT cpnin = new CanNMT(cm);
  203.                             if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
  204.                                 // If no error
  205.                                 if (cpnin.getType() == CAN_NMT_PGM_ACK) {
  206.                                     //currentAddress += 2;
  207.                                     // Check if end.
  208.                                     if (currentAddress + byteSent > hf.getAddrUpper()) {
  209.                                         // Yes, we are done, send done.
  210.                                         pgs = dState.SEND_DONE;
  211.                                     }
  212.                                     else {
  213.                                         // More to write.
  214.                                         //byteSent = 0;
  215.                                         pgs = dState.SEND_PGM_DATA;
  216.                                     }
  217.                                 }
  218.                                 else if (cpnin.getType() == CAN_NMT_PGM_NACK ) {
  219.                                     // else ..
  220.                                     Console.WriteLine("Nack on CAN_NMT_PGM_DATA.");
  221.                                     errorOccured = true;
  222.                                     pgs = dState.SEND_RESET;
  223.                                 }
  224.                                
  225.                             }
  226.                         }
  227.                         break;
  228.                        
  229.                     case dState.SEND_DONE:
  230.                         // Send done
  231.                         outCm = cpn.getPgmEndPacket();
  232.                         dc.sendCanPacket(outCm);
  233.  
  234.                         t = Environment.TickCount;
  235.                         t2 = Environment.TickCount;
  236.                         pgs = dState.WAIT_DONE;
  237.                         break;
  238.                        
  239.                        
  240.                     case dState.WAIT_DONE:
  241.                         // Check for timeout, resend done packet in that case..
  242.                         if ((Environment.TickCount - t) > TIMEOUT_MS) {
  243.                             Console.WriteLine("Timeout while waiting for end prg ack.");
  244.                             errorOccured = true;
  245.                             pgs = dState.SEND_RESET;
  246.                         }
  247.                         //Thread.Sleep(1);
  248.                        
  249.                         hasMessage = dc.getData(out cm);
  250.                         if (hasMessage) {
  251.                             CanNMT cpnin = new CanNMT(cm);
  252.                             if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
  253.                                 // If no error
  254.                                 if (cpnin.getType() == CAN_NMT_PGM_ACK) {
  255.                                     Console.WriteLine("");
  256.                                     //
  257.                                     int crc = calcCRC(hf);
  258.                                
  259.                                     if (cm.getDataLength() == 2) {
  260.                                         byte[] cmdata = cm.getData();
  261.                                         if ((cmdata[0] == (crc & 0xFF)) && (cmdata[1] == (crc>>8))) {
  262.                                             if (!isBiosUpdate) {
  263.                                                 Console.WriteLine("Done, successfully programmed application.");
  264.                                                 pgs = dState.SEND_RESET;
  265.                                             } else {
  266.                                                 Console.WriteLine("Done, successfully programmed bios to application space.");
  267.                                                 pgs = dState.SEND_BIOS_UPDATE;
  268.                                             }
  269.                                         } else {
  270.                                             string nodecrc = String.Format("{0:x4}", (int)cmdata[0] + (int)(cmdata[1]<<8));
  271.                                             nodecrc = "0x"+nodecrc;
  272.                                             string realcrc = String.Format("{0:x4}", (int)(crc & 0xFF) + (int)(crc & 0xFF00));
  273.                                             realcrc = "0x"+realcrc;
  274.                                             Console.WriteLine("CRC failed. Node sent CRC "+nodecrc+" but should be "+realcrc+".");
  275.                                             errorOccured = true;
  276.                                             pgs = dState.SEND_RESET;
  277.                                         }
  278.                                        
  279.                                         byteSent = 0;
  280.                                     }
  281.                                     //Console.WriteLine("crc: " + crc + " " + (crc>>8) + " " + (crc & 0xFF));
  282.                                     //Console.WriteLine("ACKpkg with CRC: " + cm.ToString());
  283.                                     //
  284.                                 }
  285.                                 else if (cpnin.getType() == CAN_NMT_PGM_NACK) {
  286.                                     // else resend addr..
  287.                                     Console.WriteLine("Nack on CAN_NMT_PGM_END.");
  288.                                     errorOccured = true;
  289.                                     pgs = dState.SEND_RESET;
  290.                                 }
  291.                             }
  292.                         }
  293.                         break;
  294.                        
  295.                     case dState.SEND_BIOS_UPDATE:
  296.                         data[0] = (byte)(0 & 0x00FF);
  297.                         data[1] = (byte)((0 & 0xFF00) >> 8);
  298.                         data[2] = (byte)(dlOffset & 0x00FF);
  299.                         data[3] = (byte)((dlOffset & 0xFF00) >> 8);
  300.                         data[4] = (byte)((hf.getAddrUpper()-hf.getAddrLower()+1) & 0x00FF);
  301.                         data[5] = (byte)(((hf.getAddrUpper()-hf.getAddrLower()+1) & 0xFF00) >> 8);
  302.                        
  303.                         outCm = cpn.getPgmCopyPacket(data);
  304.                         Console.WriteLine("Now say a prayer, moving bios");
  305.                         dc.sendCanPacket(outCm);
  306.                         t = Environment.TickCount;
  307.                         t2 = Environment.TickCount;
  308.                         pgs = dState.WAIT_BOOT;
  309.                         //pgs = dState.DONE;
  310.                         break;
  311.  
  312.                     case dState.WAIT_BOOT:
  313.                         // Wait for node reset answer (boot msg).
  314.                         if ((Environment.TickCount - t) > 2*TIMEOUT_MS) {
  315.                             // Woops, error.
  316.                             Console.WriteLine("Timeout while waiting for node to boot.");
  317.                             errorOccured = true;
  318.                             pgs = dState.SEND_DONE;
  319.                         }
  320.                         //Thread.Sleep(1);
  321.                         // If received boot msg.
  322.                         hasMessage = dc.getData(out cm);
  323.                         if (hasMessage) {
  324.                             CanNMT cpnin = new CanNMT(cm);
  325.                             if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
  326.                                 // If no error
  327.                                 if (cpnin.getType() == CAN_NMT_BIOS_START) {
  328.                                     pgs = dState.SEND_EMPTY_START;
  329.                                 }
  330.                                 else {
  331.                                     // else ..
  332.                                 }
  333.                             }
  334.                         }
  335.                         break;
  336.                        
  337.                     case dState.SEND_EMPTY_START:
  338.                         // Send boot start packet to target.
  339.                         // and wait for ack.
  340.                        
  341.                         //data[RID_INDEX] = TARGET_ID;
  342.                         data[ADDR0_INDEX] = (byte)((0) & 0x0000FF);
  343.                         data[ADDR1_INDEX] = (byte)(((0) & 0x00FF00) >> 8);
  344.                         data[ADDR2_INDEX] = (byte)(((0) & 0xFF0000) >> 16);
  345.                         data[ADDR3_INDEX] = 0;
  346.                         //outCm = new CanPacket(CAN_NMT, CAN_NMT_PGM_START, MY_ID, receiveID, 4, data);
  347.                         outCm = cpn.getPgmStartPacket(data);
  348.                         dc.sendCanPacket(outCm);
  349.                         t = Environment.TickCount;
  350.                         t2 = Environment.TickCount;
  351.                         pgs = dState.WAIT_ACK_PRG_EMPTY;
  352.                         timeStart = Environment.TickCount;
  353.                         break;
  354.                    
  355.                    
  356.                     case dState.WAIT_ACK_PRG_EMPTY:
  357.                         // Check for timeout, resend start packet in that case..
  358.                         if ((Environment.TickCount - t) > TIMEOUT_MS) {
  359.                             Console.WriteLine("Timeout while waiting for start prg ack.");
  360.                             errorOccured = true;
  361.                             pgs = dState.SEND_RESET;
  362.                         }
  363.                         //Thread.Sleep(1);
  364.                         // If received ack.
  365.                         hasMessage = dc.getData(out cm);
  366.                         if (hasMessage) {
  367.                             CanNMT cpnin = new CanNMT(cm);
  368.                             if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
  369.                                 // If no error
  370.                                 if (cpnin.getType() == CAN_NMT_PGM_ACK) {
  371.                                     // Start sending program data..
  372.                                     byteSent = 0;
  373.                                     pgs = dState.SEND_EMPTY_DATA;
  374.                                 }
  375.                                 else if (cpnin.getType() == CAN_NMT_PGM_NACK ) {
  376.                                     // else ..
  377.                                     Console.WriteLine("Nack on CAN_NMT_PGM_START.");
  378.                                     errorOccured = true;
  379.                                     pgs = dState.SEND_RESET;
  380.                                 }
  381.                                
  382.                             }
  383.                         }
  384.                         break;
  385.                        
  386.                     case dState.SEND_EMPTY_DATA:
  387.                         // Send program data.
  388.                         data[0] = 0;
  389.                         data[1] = 0;
  390.                         data[2] = 0xff;
  391.                         data[3] = 0xff;
  392.  
  393.                         outCm = cpn.getPgmDataPacket(data, 4);
  394.                         dc.sendCanPacket(outCm);
  395.                        
  396.                         t = Environment.TickCount;
  397.                         t2 = Environment.TickCount;
  398.                         byteSent += 6;
  399.                         pgs = dState.WAIT_ACK_EMPTY_DATA;
  400.                         break;
  401.                        
  402.                        
  403.                     case dState.WAIT_ACK_EMPTY_DATA:
  404.                         // Wait for pgm ack.
  405.                         if ((Environment.TickCount - t) > 2*TIMEOUT_MS) {
  406.                             // Woops, error.
  407.                             Console.WriteLine("Timeout while waiting for data ack.");
  408.                             errorOccured = true;
  409.                             pgs = dState.SEND_RESET;
  410.                         }
  411.                         //Thread.Sleep(1);
  412.                         // If received ack.
  413.                         hasMessage = dc.getData(out cm);
  414.                         if (hasMessage) {
  415.                             CanNMT cpnin = new CanNMT(cm);
  416.                             if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
  417.                                 // If no error
  418.                                 if (cpnin.getType() == CAN_NMT_PGM_ACK) {
  419.                                     pgs = dState.SEND_DONE_EMPTY;
  420.                                 }
  421.                                 else if (cpnin.getType() == CAN_NMT_PGM_NACK ) {
  422.                                     // else ..
  423.                                     Console.WriteLine("Nack on CAN_NMT_PGM_DATA.");
  424.                                     errorOccured = true;
  425.                                     pgs = dState.SEND_RESET;
  426.                                 }
  427.                                
  428.                             }
  429.                         }
  430.                         break;
  431.                        
  432.                     case dState.SEND_DONE_EMPTY:
  433.                         // Send done
  434.                         outCm = cpn.getPgmEndPacket();
  435.                         dc.sendCanPacket(outCm);
  436.  
  437.                         t = Environment.TickCount;
  438.                         t2 = Environment.TickCount;
  439.                         pgs = dState.WAIT_DONE_EMPTY;
  440.                         break;
  441.                        
  442.                        
  443.                     case dState.WAIT_DONE_EMPTY:
  444.                         // Check for timeout, resend done packet in that case..
  445.                         if ((Environment.TickCount - t) > TIMEOUT_MS) {
  446.                             Console.WriteLine("Timeout while waiting for end prg ack.");
  447.                             errorOccured = true;
  448.                             pgs = dState.SEND_RESET;
  449.                         }
  450.                         //Thread.Sleep(1);
  451.                        
  452.                         hasMessage = dc.getData(out cm);
  453.                         if (hasMessage) {
  454.                             CanNMT cpnin = new CanNMT(cm);
  455.                             if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
  456.                                 // If no error
  457.                                 if (cpnin.getType() == CAN_NMT_PGM_ACK) {
  458.                                     Console.WriteLine("");
  459.                                     //
  460.                                     Console.WriteLine("Done, successfully cleaned application flash.");
  461.                                     pgs = dState.SEND_RESET;
  462.                                 }
  463.                                 else if (cpnin.getType() == CAN_NMT_PGM_NACK) {
  464.                                     // else resend addr..
  465.                                     Console.WriteLine("Nack on CAN_NMT_PGM_END.");
  466.                                     errorOccured = true;
  467.                                     pgs = dState.SEND_RESET;
  468.                                 }
  469.                             }
  470.                         }
  471.                         break;                     
  472.                     case dState.SEND_RESET:
  473.                         // Send reset
  474.                         cpn.doReset(dc, receiveID);
  475.                         t = Environment.TickCount;
  476.                         t2 = Environment.TickCount;
  477.                         pgs = dState.DONE;
  478.                         break;
  479.                        
  480.                        
  481.                     case dState.DONE:
  482.                         done = true;
  483.                         //down.Abort();
  484.                         if (!errorOccured) {
  485.                             long tsecs = ((Environment.TickCount - timeStart) / 1000);
  486.                             double bitRate = hf.getLength() / ((double)(Environment.TickCount - timeStart) / 1000.0);
  487.                            
  488.                             if (tsecs <= 0) tsecs = 1;
  489.                             long mins = tsecs / 60;
  490.                             long secs = tsecs % 60;
  491.                             string pad = "";
  492.                             if (secs < 10) {
  493.                                 pad = "0";
  494.                             }
  495.                             Console.WriteLine("Time spent: " + mins + ":" + pad + secs + ", " + Math.Round(bitRate, 2) + " bytes/s");
  496.                         }
  497.                         //Console.Write("> ");
  498.                         break;
  499.                 }
  500.             }
  501.            
  502.         } catch(Exception) {
  503.             Console.WriteLine("Exception occured");
  504.             //Console.WriteLine(e);
  505.             //skriva ut antal bytes skrivna vore bra här, kanske nån annan form av hjälp för debug, något gick snett liksom
  506.            
  507.         }
  508.        
  509.         return !errorOccured;
  510.     }
  511. }
  512.