Subversion Repositories HomeAutomation

Rev

Rev 467 | 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 };
  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 = 2000;
  41.    
  42.     private long timeStart = 0;
  43.    
  44.     public Downloader(HexFile hf, DaemonConnection dc, byte receiveID, bool isBiosUpdate) {
  45.         this.hf = hf;
  46.         this.dc = dc;
  47.         this.receiveID = receiveID;
  48.         this.isBiosUpdate = isBiosUpdate;
  49.     }
  50.    
  51.     public int calcCRC(HexFile hf) {
  52.         int crc=0;
  53.         for (ulong i=hf.getAddrLower(); i <= hf.getAddrUpper(); i++) {
  54.             crc = crc16_update(crc, hf.getByte(i));
  55.         }
  56.         return crc;
  57.     }
  58.    
  59.     public int crc16_update(int crc, byte a) {
  60.         int i;
  61.         crc ^= a;
  62.         for (i = 0; i < 8; ++i) {
  63.             if ((crc & 1) != 0)
  64.                 crc = (crc >> 1) ^ 0xA001;
  65.             else
  66.                 crc = (crc >> 1);
  67.         }
  68.         return crc;
  69.     }
  70.    
  71.     public bool go() {
  72.         if (dc==null || hf==null || hf.getLength()==0) return false;
  73.         return downloader();
  74.     }
  75.    
  76.     public void abort() {
  77.         //if (down != null && down.IsAlive) down.Abort();
  78.     }
  79.    
  80.     public bool downloader() {
  81.         dState pgs = dState.SEND_START;
  82.         int t = 0;
  83.         CanPacket outCm = null;
  84.         CanPacket cm = null;
  85.         byte[] data = new byte[8];
  86.         uint byteSent = 0;
  87.         ulong currentAddress = 0;
  88.         bool done = false;
  89.         bool errorOccured = false;
  90.        
  91.         try {
  92.             if (isBiosUpdate) {
  93.                 dlOffset = hf.getAddrLower();
  94.                 //Console.WriteLine(dlOffset);
  95.                 //dlOffset = 200;
  96.             }
  97.  
  98.             CanNMT cpn = new CanNMT();
  99.             cpn.setReceiver(receiveID);
  100.             bool hasMessage = false;
  101.            
  102.             while (!done) {
  103.                 Thread.Sleep(1);
  104.                
  105.                 switch (pgs) {
  106.                     case dState.SEND_START:
  107.                         // Send boot start packet to target.
  108.                         // and wait for ack.
  109.                         currentAddress = hf.getAddrLower();
  110.                         //data[RID_INDEX] = TARGET_ID;
  111.                         data[ADDR0_INDEX] = (byte)((currentAddress-dlOffset) & 0x0000FF);
  112.                         data[ADDR1_INDEX] = (byte)(((currentAddress-dlOffset) & 0x00FF00) >> 8);
  113.                         data[ADDR2_INDEX] = (byte)(((currentAddress-dlOffset) & 0xFF0000) >> 16);
  114.                         data[ADDR3_INDEX] = 0;
  115.                         //outCm = new CanPacket(CAN_NMT, CAN_NMT_PGM_START, MY_ID, receiveID, 4, data);
  116.                         outCm = cpn.getPgmStartPacket(data);
  117.                         dc.sendCanPacket(outCm);
  118.                         t = Environment.TickCount;
  119.                         pgs = dState.WAIT_ACK_PRG;
  120.                         timeStart = Environment.TickCount;
  121.                         break;
  122.                    
  123.                    
  124.                     case dState.WAIT_ACK_PRG:
  125.                         // Check for timeout, resend start packet in that case..
  126.                         if ((Environment.TickCount - t) > TIMEOUT_MS) {
  127.                             Console.WriteLine("Timeout while waiting for start prg ack.");
  128.                             errorOccured = true;
  129.                             pgs = dState.SEND_RESET;
  130.                         }
  131.                         //Thread.Sleep(1);
  132.                         // If received ack.
  133.                         hasMessage = dc.getData(out cm);
  134.                         if (hasMessage) {
  135.                             CanNMT cpnin = new CanNMT(cm);
  136.                             if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
  137.                                 // If no error
  138.                                 if (cpnin.getType() == CAN_NMT_PGM_ACK) {
  139.                                     // Start sending program data..
  140.                                     byteSent = 0;
  141.                                     pgs = dState.SEND_PGM_DATA;
  142.                                 }
  143.                                 else if (cpnin.getType() == CAN_NMT_PGM_NACK ) {
  144.                                     // else ..
  145.                                     Console.WriteLine("Nack on CAN_NMT_PGM_START.");
  146.                                     errorOccured = true;
  147.                                     pgs = dState.SEND_RESET;
  148.                                 }
  149.                                
  150.                             }
  151.                         }
  152.                         break;
  153.                        
  154.                     case dState.SEND_PGM_DATA:
  155.                         //Console.WriteLine("byteSent = "+byteSent);
  156.                         Console.Write(".");
  157.                         // Send program data.
  158.                         byte datalength = 2;
  159.                         for (ulong i = 0; i < 6; i++) {
  160.                             // Populate data.
  161.                             data[i+2] = hf.getByte(currentAddress + i + byteSent);
  162.                             if (currentAddress + i + byteSent > hf.getAddrUpper()) {
  163.                                 break;  //then done
  164.                             }
  165.                             datalength++;
  166.                         }
  167.                         data[0] = (byte)(byteSent & 0x00FF);
  168.                         data[1] = (byte)((byteSent & 0xFF00) >> 8);
  169.  
  170.                         outCm = cpn.getPgmDataPacket(data, datalength);
  171.                         dc.sendCanPacket(outCm);
  172.                        
  173.                         t = Environment.TickCount;
  174.                         byteSent += 6;
  175.                         pgs = dState.WAIT_ACK_DATA;
  176.                         break;
  177.                        
  178.                        
  179.                     case dState.WAIT_ACK_DATA:
  180.                         // Wait for pgm ack.
  181.                         if ((Environment.TickCount - t) > 2*TIMEOUT_MS) {
  182.                             // Woops, error.
  183.                             Console.WriteLine("Timeout while waiting for data ack.");
  184.                             errorOccured = true;
  185.                             pgs = dState.SEND_RESET;
  186.                         }
  187.                         //Thread.Sleep(1);
  188.                         // If received ack.
  189.                         hasMessage = dc.getData(out cm);
  190.                         if (hasMessage) {
  191.                             CanNMT cpnin = new CanNMT(cm);
  192.                             if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
  193.                                 // If no error
  194.                                 if (cpnin.getType() == CAN_NMT_PGM_ACK) {
  195.                                     //currentAddress += 2;
  196.                                     // Check if end.
  197.                                     if (currentAddress + byteSent > hf.getAddrUpper()) {
  198.                                         // Yes, we are done, send done.
  199.                                         pgs = dState.SEND_DONE;
  200.                                     }
  201.                                     else {
  202.                                         // More to write.
  203.                                         //byteSent = 0;
  204.                                         pgs = dState.SEND_PGM_DATA;
  205.                                     }
  206.                                 }
  207.                                 else if (cpnin.getType() == CAN_NMT_PGM_NACK ) {
  208.                                     // else ..
  209.                                     Console.WriteLine("Nack on CAN_NMT_PGM_DATA.");
  210.                                     errorOccured = true;
  211.                                     pgs = dState.SEND_RESET;
  212.                                 }
  213.                                
  214.                             }
  215.                         }
  216.                         break;
  217.                        
  218.                     case dState.SEND_DONE:
  219.                         // Send done
  220.                         outCm = cpn.getPgmEndPacket();
  221.                         dc.sendCanPacket(outCm);
  222.  
  223.                         t = Environment.TickCount;
  224.                         pgs = dState.WAIT_DONE;
  225.                         break;
  226.                        
  227.                        
  228.                     case dState.WAIT_DONE:
  229.                         // Check for timeout, resend done packet in that case..
  230.                         if ((Environment.TickCount - t) > TIMEOUT_MS) {
  231.                             Console.WriteLine("Timeout while waiting for end prg ack.");
  232.                             errorOccured = true;
  233.                             pgs = dState.SEND_RESET;
  234.                         }
  235.                         //Thread.Sleep(1);
  236.                        
  237.                         hasMessage = dc.getData(out cm);
  238.                         if (hasMessage) {
  239.                             CanNMT cpnin = new CanNMT(cm);
  240.                             if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {
  241.                                 // If no error
  242.                                 if (cpnin.getType() == CAN_NMT_PGM_ACK) {
  243.                                     Console.WriteLine("");
  244.                                     //
  245.                                     int crc = calcCRC(hf);
  246.                                
  247.                                     if (cm.getDataLength() == 2) {
  248.                                         byte[] cmdata = cm.getData();
  249.                                         if ((cmdata[0] == (crc & 0xFF)) && (cmdata[1] == (crc>>8))) {
  250.                                             if (!isBiosUpdate) {
  251.                                                 Console.WriteLine("Done, successfully programmed application.");
  252.                                                 pgs = dState.SEND_RESET;
  253.                                             } else {
  254.                                                 Console.WriteLine("Done, successfully programmed bios to application space.");
  255.                                                 pgs = dState.SEND_BIOS_UPDATE;
  256.                                             }
  257.                                         } else {
  258.                                             string nodecrc = String.Format("{0:x4}", (int)cmdata[0] + (int)(cmdata[1]<<8));
  259.                                             nodecrc = "0x"+nodecrc;
  260.                                             string realcrc = String.Format("{0:x4}", (int)(crc & 0xFF) + (int)(crc & 0xFF00));
  261.                                             realcrc = "0x"+realcrc;
  262.                                             Console.WriteLine("CRC failed. Node sent CRC "+nodecrc+" but should be "+realcrc+".");
  263.                                             errorOccured = true;
  264.                                             pgs = dState.SEND_RESET;
  265.                                         }
  266.                                        
  267.                                         byteSent = 0;
  268.                                     }
  269.                                     //Console.WriteLine("crc: " + crc + " " + (crc>>8) + " " + (crc & 0xFF));
  270.                                     //Console.WriteLine("ACKpkg with CRC: " + cm.ToString());
  271.                                     //
  272.                                 }
  273.                                 else if (cpnin.getType() == CAN_NMT_PGM_NACK) {
  274.                                     // else resend addr..
  275.                                     Console.WriteLine("Nack on CAN_NMT_PGM_END.");
  276.                                     errorOccured = true;
  277.                                     pgs = dState.SEND_RESET;
  278.                                 }
  279.                             }
  280.                         }
  281.                         break;
  282.                        
  283.                     case dState.SEND_BIOS_UPDATE:
  284.                         data[0] = (byte)(0 & 0x00FF);
  285.                         data[1] = (byte)((0 & 0xFF00) >> 8);
  286.                         data[2] = (byte)(dlOffset & 0x00FF);
  287.                         data[3] = (byte)((dlOffset & 0xFF00) >> 8);
  288.                         data[4] = (byte)((hf.getAddrUpper()-hf.getAddrLower()+1) & 0x00FF);
  289.                         data[5] = (byte)(((hf.getAddrUpper()-hf.getAddrLower()+1) & 0xFF00) >> 8);
  290.                        
  291.                         outCm = cpn.getPgmCopyPacket(data);
  292.                         Console.WriteLine("Now say a prayer, moving bios");
  293.                         dc.sendCanPacket(outCm);
  294.                         t = Environment.TickCount;
  295.                         pgs = dState.DONE;
  296.                         break;
  297.                        
  298.                     case dState.SEND_RESET:
  299.                         // Send reset
  300.                         cpn.doReset(dc, receiveID);
  301.                         t = Environment.TickCount;
  302.                         pgs = dState.DONE;
  303.                         break;
  304.                        
  305.                        
  306.                     case dState.DONE:
  307.                         done = true;
  308.                         //down.Abort();
  309.                         if (!errorOccured) {
  310.                             long tsecs = ((Environment.TickCount - timeStart) / 1000);
  311.                             double bitRate = hf.getLength() / ((double)(Environment.TickCount - timeStart) / 1000.0);
  312.                            
  313.                             if (tsecs <= 0) tsecs = 1;
  314.                             long mins = tsecs / 60;
  315.                             long secs = tsecs % 60;
  316.                             string pad = "";
  317.                             if (secs < 10) {
  318.                                 pad = "0";
  319.                             }
  320.                             Console.WriteLine("Time spent: " + mins + ":" + pad + secs + ", " + Math.Round(bitRate, 2) + " bytes/s");
  321.                         }
  322.                         //Console.Write("> ");
  323.                         break;
  324.                 }
  325.             }
  326.            
  327.         } catch(Exception) {
  328.             Console.WriteLine("Exception occured");
  329.             //Console.WriteLine(e);
  330.             //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
  331.            
  332.         }
  333.        
  334.         return !errorOccured;
  335.     }
  336. }
  337.