Rev 879 | Rev 1458 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed
using System;using System.Collections.Generic;using System.Text;using System.Threading;//this class should probably be integrated into canNMT insteadpublic class Downloader {private HexFile hf;private DaemonConnection dc;private bool isBiosUpdate;private ulong dlOffset = 0;//private Thread down;private byte receiveID;private uint hwid;private bool HWID_INUSE;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};private const byte CAN_NMT = 0x00;private const byte CAN_NMT_RESET = 0x04;private const byte CAN_NMT_BIOS_START = 0x08;private const byte CAN_NMT_PGM_START = 0x0C;private const byte CAN_NMT_PGM_DATA = 0x10;private const byte CAN_NMT_PGM_END = 0x14;private const byte CAN_NMT_PGM_COPY = 0x18;private const byte CAN_NMT_PGM_ACK = 0x1C;private const byte CAN_NMT_PGM_NACK = 0x20;private const byte CAN_NMT_START_APP = 0x24;private const byte CAN_NMT_APP_START = 0x28;private const byte CAN_NMT_HEARTBEAT = 0x2C;private const byte MY_ID = 0x00;//private const byte TARGET_ID = 0x78;private const byte MY_NID = 0x0;private const byte ADDR0_INDEX = 0;private const byte ADDR1_INDEX = 1;private const byte ADDR2_INDEX = 2;private const byte ADDR3_INDEX = 3;private const byte HWID0_INDEX = 4;private const byte HWID1_INDEX = 5;private const byte HWID2_INDEX = 6;private const byte HWID3_INDEX = 7;private const int TIMEOUT_MS = 1000;private const int TIMEOUT_SHORT_MS = 200;private long timeStart = 0;public Downloader(HexFile hf, DaemonConnection dc, byte receiveID, bool isBiosUpdate, bool HWID_INUSE, uint hwid) {this.hf = hf;this.dc = dc;this.receiveID = receiveID;this.isBiosUpdate = isBiosUpdate;this.hwid = hwid;this.HWID_INUSE = HWID_INUSE;}public int calcCRC(HexFile hf) {int crc=0;for (ulong i=hf.getAddrLower(); i <= hf.getAddrUpper(); i++) {crc = crc16_update(crc, hf.getByte(i));}return crc;}public int crc16_update(int crc, byte a) {int i;crc ^= a;for (i = 0; i < 8; ++i) {if ((crc & 1) != 0)crc = (crc >> 1) ^ 0xA001;elsecrc = (crc >> 1);}return crc;}public bool go() {if (dc==null || hf==null || hf.getLength()==0) return false;return downloader();}public void abort() {//if (down != null && down.IsAlive) down.Abort();}public bool downloader() {dState pgs = dState.SEND_START;int t = 0;int t2 = 0;CanPacket outCm = null;CanPacket cm = null;byte[] data = new byte[8];uint byteSent = 0;ulong currentAddress = 0;bool done = false;bool errorOccured = false;//int rotstate=0;//int dldisplaystate=0;double lastpercent=0;double lasttenpercent=0;int nrOfTicks=0;try {if (isBiosUpdate) {dlOffset = hf.getAddrLower();//Console.WriteLine(dlOffset);//dlOffset = 200;}CanNMT cpn = new CanNMT(HWID_INUSE);cpn.setReceiver(receiveID);bool hasMessage = false;while (!done) {Thread.Sleep(1);switch (pgs) {case dState.SEND_START:// Send boot start packet to target.// and wait for ack.currentAddress = hf.getAddrLower();//data[RID_INDEX] = TARGET_ID;data[ADDR0_INDEX] = (byte)((currentAddress-dlOffset) & 0x0000FF);data[ADDR1_INDEX] = (byte)(((currentAddress-dlOffset) & 0x00FF00) >> 8);data[ADDR2_INDEX] = (byte)(((currentAddress-dlOffset) & 0xFF0000) >> 16);data[ADDR3_INDEX] = 0;if (HWID_INUSE) {data[HWID0_INDEX] = (byte)((hwid) & 0xFF);data[HWID1_INDEX] = (byte)((hwid>>8) & 0xFF);data[HWID2_INDEX] = (byte)((hwid>>16) & 0xFF);data[HWID3_INDEX] = (byte)((hwid>>24) & 0xFF);}//outCm = new CanPacket(CAN_NMT, CAN_NMT_PGM_START, MY_ID, receiveID, 4, data);outCm = cpn.getPgmStartPacket(data);dc.sendCanPacket(outCm);t = Environment.TickCount;t2 = Environment.TickCount;pgs = dState.WAIT_ACK_PRG;timeStart = Environment.TickCount;Console.WriteLine("Downloading...");//Console.Write(" 0% [ ]\r");Console.Write(" 0% [");break;case dState.WAIT_ACK_PRG:// Check for timeout, resend start packet in that case..if ((Environment.TickCount - t) > TIMEOUT_MS) {Console.WriteLine("Timeout while waiting for start prg ack.");errorOccured = true;pgs = dState.SEND_RESET;}//Thread.Sleep(1);// If received ack.hasMessage = dc.getData(out cm);if (hasMessage) {CanNMT cpnin = new CanNMT(cm, HWID_INUSE);if (cpnin.isNMTPacket()) {//if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {// If no errorif (cpnin.getType() == CAN_NMT_PGM_ACK) {// Start sending program data..byteSent = 0;pgs = dState.SEND_PGM_DATA;}else if (cpnin.getType() == CAN_NMT_PGM_NACK ) {// else ..Console.WriteLine("Nack on CAN_NMT_PGM_START.");errorOccured = true;pgs = dState.SEND_RESET;}}}break;case dState.SEND_PGM_DATA:double percent = (double)byteSent*100/((double)hf.getAddrUpper()-(double)currentAddress);//Console.Write(" 0% [ ]");if (percent >= lastpercent+2.5) {//Console.WriteLine(percent);Console.Write("=");nrOfTicks++;lastpercent = lastpercent+2.5;}if (percent > lasttenpercent+10) {for (int i=nrOfTicks; i<40; i++) {Console.Write(" ");}Console.Write("]");Console.Write("\r");Console.Write(" "+Math.Round(percent,0)+"% [");lasttenpercent = lasttenpercent+10;for (int i=0; i<nrOfTicks; i++) {Console.Write("=");}}// Send program data.byte datalength = 2;for (ulong i = 0; i < 6; i++) {// Populate data.data[i+2] = hf.getByte(currentAddress + i + byteSent);if (currentAddress + i + byteSent > hf.getAddrUpper()) {break; //then done}datalength++;}data[0] = (byte)(byteSent & 0x00FF);data[1] = (byte)((byteSent & 0xFF00) >> 8);outCm = cpn.getPgmDataPacket(data, datalength);dc.sendCanPacket(outCm);t = Environment.TickCount;t2 = Environment.TickCount;byteSent += 6;pgs = dState.WAIT_ACK_DATA;break;case dState.WAIT_ACK_DATA:// Wait for pgm ack.if ((Environment.TickCount - t) > TIMEOUT_MS) {// Woops, error.Console.WriteLine("Timeout while waiting for data ack.");errorOccured = true;pgs = dState.SEND_RESET;}else if ((Environment.TickCount - t2) > TIMEOUT_SHORT_MS) {// Woops, error.//disable Console.Write(":");byteSent -= 6;pgs = dState.SEND_PGM_DATA;break;}//Thread.Sleep(1);// If received ack.hasMessage = dc.getData(out cm);if (hasMessage) {CanNMT cpnin = new CanNMT(cm, HWID_INUSE);if (cpnin.isNMTPacket()) {//if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {// If no errorif (cpnin.getType() == CAN_NMT_PGM_ACK) {//currentAddress += 2;// Check if end.if (currentAddress + byteSent > hf.getAddrUpper()) {// Yes, we are done, send done.pgs = dState.SEND_DONE;}else {// More to write.//byteSent = 0;pgs = dState.SEND_PGM_DATA;}}else if (cpnin.getType() == CAN_NMT_PGM_NACK ) {// else ..Console.WriteLine("Nack on CAN_NMT_PGM_DATA.");errorOccured = true;pgs = dState.SEND_RESET;}}}break;case dState.SEND_DONE:for (int i=nrOfTicks; i<40; i++) {Console.Write(" ");}Console.Write("]");Console.Write("\r");Console.Write("100% [========================================]");// Send doneoutCm = cpn.getPgmEndPacket();dc.sendCanPacket(outCm);t = Environment.TickCount;t2 = Environment.TickCount;pgs = dState.WAIT_DONE;break;case dState.WAIT_DONE:// Check for timeout, resend done packet in that case..if ((Environment.TickCount - t) > TIMEOUT_MS) {Console.WriteLine("Timeout while waiting for end prg ack.");errorOccured = true;pgs = dState.SEND_RESET;}//Thread.Sleep(1);hasMessage = dc.getData(out cm);if (hasMessage) {CanNMT cpnin = new CanNMT(cm, HWID_INUSE);if (cpnin.isNMTPacket()) {//if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {// If no errorif (cpnin.getType() == CAN_NMT_PGM_ACK) {Console.WriteLine("");//int crc = calcCRC(hf);if (cm.getDataLength() == 2) {byte[] cmdata = cm.getData();if ((cmdata[0] == (crc & 0xFF)) && (cmdata[1] == (crc>>8))) {if (!isBiosUpdate) {Console.WriteLine("Done, successfully programmed application.");pgs = dState.SEND_RESET;} else {Console.WriteLine("Done, successfully programmed bios to application space.");pgs = dState.SEND_BIOS_UPDATE;}} else {string nodecrc = String.Format("{0:x4}", (int)cmdata[0] + (int)(cmdata[1]<<8));nodecrc = "0x"+nodecrc;string realcrc = String.Format("{0:x4}", (int)(crc & 0xFF) + (int)(crc & 0xFF00));realcrc = "0x"+realcrc;Console.WriteLine("CRC failed. Node sent CRC "+nodecrc+" but should be "+realcrc+".");errorOccured = true;pgs = dState.SEND_RESET;}byteSent = 0;}//Console.WriteLine("crc: " + crc + " " + (crc>>8) + " " + (crc & 0xFF));//Console.WriteLine("ACKpkg with CRC: " + cm.ToString());//}else if (cpnin.getType() == CAN_NMT_PGM_NACK) {// else resend addr..Console.WriteLine("Nack on CAN_NMT_PGM_END.");errorOccured = true;pgs = dState.SEND_RESET;}}}break;case dState.SEND_BIOS_UPDATE:data[0] = (byte)(0 & 0x00FF);data[1] = (byte)((0 & 0xFF00) >> 8);data[2] = (byte)(dlOffset & 0x00FF);data[3] = (byte)((dlOffset & 0xFF00) >> 8);data[4] = (byte)((hf.getAddrUpper()-hf.getAddrLower()+1) & 0x00FF);data[5] = (byte)(((hf.getAddrUpper()-hf.getAddrLower()+1) & 0xFF00) >> 8);outCm = cpn.getPgmCopyPacket(data);Console.WriteLine("Now say a prayer, moving bios");dc.sendCanPacket(outCm);t = Environment.TickCount;t2 = Environment.TickCount;pgs = dState.WAIT_BOOT;//pgs = dState.DONE;break;case dState.WAIT_BOOT:// Wait for node reset answer (boot msg).if ((Environment.TickCount - t) > 3*TIMEOUT_MS) {// Woops, error.Console.WriteLine("Timeout while waiting for node to boot.");errorOccured = true;pgs = dState.SEND_DONE;}//Thread.Sleep(1);// If received boot msg.hasMessage = dc.getData(out cm);if (hasMessage) {CanNMT cpnin = new CanNMT(cm, HWID_INUSE);if (cpnin.isNMTPacket()) {//if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {// If no errorif (cpnin.getType() == CAN_NMT_BIOS_START) {pgs = dState.SEND_EMPTY_START;}else {// else ..}}}break;case dState.SEND_EMPTY_START:// Send boot start packet to target.// and wait for ack.//data[RID_INDEX] = TARGET_ID;data[ADDR0_INDEX] = (byte)((0) & 0x0000FF);data[ADDR1_INDEX] = (byte)(((0) & 0x00FF00) >> 8);data[ADDR2_INDEX] = (byte)(((0) & 0xFF0000) >> 16);data[ADDR3_INDEX] = 0;if (HWID_INUSE) {data[HWID0_INDEX] = (byte)((hwid) & 0xFF);data[HWID1_INDEX] = (byte)((hwid>>8) & 0xFF);data[HWID2_INDEX] = (byte)((hwid>>16) & 0xFF);data[HWID3_INDEX] = (byte)((hwid>>24) & 0xFF);}//outCm = new CanPacket(CAN_NMT, CAN_NMT_PGM_START, MY_ID, receiveID, 4, data);outCm = cpn.getPgmStartPacket(data);dc.sendCanPacket(outCm);t = Environment.TickCount;t2 = Environment.TickCount;pgs = dState.WAIT_ACK_PRG_EMPTY;break;case dState.WAIT_ACK_PRG_EMPTY:// Check for timeout, resend start packet in that case..if ((Environment.TickCount - t) > 3*TIMEOUT_MS) {Console.WriteLine("Timeout while waiting for start prg ack during empty-first-block-cycle.");errorOccured = true;pgs = dState.SEND_RESET;}//Thread.Sleep(1);// If received ack.hasMessage = dc.getData(out cm);if (hasMessage) {CanNMT cpnin = new CanNMT(cm, HWID_INUSE);if (cpnin.isNMTPacket()) {//if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {// If no errorif (cpnin.getType() == CAN_NMT_PGM_ACK) {// Start sending program data..byteSent = 0;pgs = dState.SEND_EMPTY_DATA;}else if (cpnin.getType() == CAN_NMT_PGM_NACK ) {// else ..Console.WriteLine("Nack on CAN_NMT_PGM_START.");errorOccured = true;pgs = dState.SEND_RESET;}}}break;case dState.SEND_EMPTY_DATA:// Send program data.data[0] = 0;data[1] = 0;data[2] = 0xff;data[3] = 0xff;outCm = cpn.getPgmDataPacket(data, 4);dc.sendCanPacket(outCm);t = Environment.TickCount;t2 = Environment.TickCount;byteSent += 6;pgs = dState.WAIT_ACK_EMPTY_DATA;break;case dState.WAIT_ACK_EMPTY_DATA:// Wait for pgm ack.if ((Environment.TickCount - t) > 2*TIMEOUT_MS) {// Woops, error.Console.WriteLine("Timeout while waiting for data ack.");errorOccured = true;pgs = dState.SEND_RESET;}//Thread.Sleep(1);// If received ack.hasMessage = dc.getData(out cm);if (hasMessage) {CanNMT cpnin = new CanNMT(cm, HWID_INUSE);if (cpnin.isNMTPacket()) {//if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {// If no errorif (cpnin.getType() == CAN_NMT_PGM_ACK) {pgs = dState.SEND_DONE_EMPTY;}else if (cpnin.getType() == CAN_NMT_PGM_NACK ) {// else ..Console.WriteLine("Nack on CAN_NMT_PGM_DATA.");errorOccured = true;pgs = dState.SEND_RESET;}}}break;case dState.SEND_DONE_EMPTY:// Send doneoutCm = cpn.getPgmEndPacket();dc.sendCanPacket(outCm);t = Environment.TickCount;t2 = Environment.TickCount;pgs = dState.WAIT_DONE_EMPTY;break;case dState.WAIT_DONE_EMPTY:// Check for timeout, resend done packet in that case..if ((Environment.TickCount - t) > TIMEOUT_MS) {Console.WriteLine("Timeout while waiting for end prg ack.");errorOccured = true;pgs = dState.SEND_RESET;}//Thread.Sleep(1);hasMessage = dc.getData(out cm);if (hasMessage) {CanNMT cpnin = new CanNMT(cm, HWID_INUSE);if (cpnin.isNMTPacket()) {//if (cpnin.isNMTPacket() && (cpnin.getSender() == receiveID)) {// If no errorif (cpnin.getType() == CAN_NMT_PGM_ACK) {Console.WriteLine("");//Console.WriteLine("Done, successfully cleaned application flash.");pgs = dState.SEND_RESET;}else if (cpnin.getType() == CAN_NMT_PGM_NACK) {// else resend addr..Console.WriteLine("Nack on CAN_NMT_PGM_END.");errorOccured = true;pgs = dState.SEND_RESET;}}}break;case dState.SEND_RESET:// Send resetcpn.doReset(dc, receiveID, hwid);t = Environment.TickCount;t2 = Environment.TickCount;pgs = dState.DONE;break;case dState.DONE:done = true;//down.Abort();if (!errorOccured) {long tsecs = ((Environment.TickCount - timeStart) / 1000);double bitRate = hf.getLength() / ((double)(Environment.TickCount - timeStart) / 1000.0);if (tsecs <= 0) tsecs = 1;long mins = tsecs / 60;long secs = tsecs % 60;string pad = "";if (secs < 10) {pad = "0";}Console.WriteLine("Time spent: " + mins + ":" + pad + secs + ", " + Math.Round(bitRate, 2) + " bytes/s");}//Console.Write("> ");break;}}} catch(Exception) {Console.WriteLine("Exception occured");//Console.WriteLine(e);//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}return !errorOccured;}}