using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO.Ports; using System.IO; using System.Text.RegularExpressions; using System.Configuration; using System.Timers; namespace Bubbler { public class SerialPortCommunication { string filename = null; private Form1 mainForm; //Reference to The Main Form //long TimeNow=DateTime.Now.ToFileTimeUtc(); //string UploadedFileName = "C:\\Documents and Settings\\mpeloso\\Desktop\\" + TimeNow.ToString() + ".txt"; //bool BSLMemAccessWarning=true; int _err = 1; const int SMALL_RAM_model = 0; //Ram Model Small const int LARGE_RAM_model = 1; //Ram Model Large const int loadedModel = 0x4567; const int ERR_VERIFY_FAILED = 98; const int ERR_ERASE_CHECK_FAILED = 97; const int MAX_FRAME_COUNT = 16; const int MAX_ERR_COUNT = 5; const int ACTION_PROGRAM = 0x01; const int ACTION_VERIFY = 0x02; const int ACTION_ERASE_CHECK = 0x04; const int ACTION_PASSWD = 0x08; const int ACTION_ERASE_CHECK_FAST = 0x10; const int ERR_NONE = 0; const int BSL_TXPWORD = 0x10; //Command To Send Password const int BSL_TXBLK = 0x12; //Command to Transmit Block const int BSL_RXBLK = 0x14; //Command to Recieve Block const int BSL_MERAS = 0x18; //Command to Mass Erase const int BSL_ECHECK = 0x1C; const int BSL_MEMOFFSET = 0x21; const int ERR_BSL_SYNC = 99; const int ERR_COM = 1; //Error Communication const int ERR_RX_HDR_TIMEOUT = 6; //Error Hardware Timeout const int ERR_RX_NAK = 7; //Error Password Not Accepted const int ERR_CMD_NOT_COMPLETED = 8; //Error Command Not Completed const int ERR_CMD_FAILED = 9; //Error Command Failed const int CMD_FAILED = 0x70; const int DATA_FRAME = 0x80; const int DATA_ACK = 0x90; //Data Acknowledged const int DATA_NAK = 0xA0; //Data Not Accepted const int DEFAULT_TIMEOUT = 500; const int DEFAULT_PROLONG = 10; const int MAX_FRAME_SIZE = 256; const int MAX_DATA_BYTES = 250; static uint bslerrbuf = 0x021E; static int maxData = 240; //Keeps the Data Frame from overrunning private int byteCtr = 0; //Byte Counter private byte rxHeader = 0; private uint prolongFactor = DEFAULT_PROLONG; private uint timeout = DEFAULT_TIMEOUT; private int lastError; private byte[] blkout = new byte[MAX_DATA_BYTES]; /* Transmit buffer */ private byte seqNo, reqNo; private byte[] rxFrame = new byte[MAX_FRAME_SIZE]; private byte[] blkin = new byte[MAX_DATA_BYTES]; /* Receive buffer */ private int error = ERR_NONE; private int meraseCycles = 20; bool ProgramF = true; bool MSP430X = false; const int MODE_BSL = 1; string passwdFile = null; const ushort protocolMode = MODE_BSL; const byte BSL_SYNC = 0x80; private SerialPort _serialPort; //Reference to SerialPort private List AllPorts; public SerialPortCommunication(Form1 parentForm,string PortName) { _serialPort = new SerialPort(); _serialPort.PortName = PortName; mainForm = parentForm; filename = mainForm.filename; AllPorts = parentForm.AllPorts; } public SerialPort _SERIALPORT { get { return _serialPort; } set { _serialPort = value; } } public int comInit(string PortName) { try { if (_serialPort.IsOpen == true) { _serialPort.Close(); } _serialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived); _serialPort.BaudRate = 9600; _serialPort.Parity = Parity.Even; _serialPort.DataBits = 8; _serialPort.StopBits = StopBits.One; _serialPort.DtrEnable = true; _serialPort.RtsEnable = true; _serialPort.ReadTimeout = 0; _serialPort.WriteTimeout = 50; _serialPort.WriteBufferSize = 512; _serialPort.ReadBufferSize = 256; seqNo = 0; reqNo = 0; _serialPort.ParityReplace = 0xff; _serialPort.Open(); _serialPort.DiscardInBuffer(); _serialPort.DiscardOutBuffer(); return 1; } catch { mainForm.textBox1.AppendText(PortName + " is not working\r\n"); return 1; } } public void bslReset(Boolean invokeBSL, string Portname) { try { if (_serialPort.IsOpen == true) { _serialPort.Close(); } _serialPort.Open(); setRstPin(true); setTestPin(true); System.Threading.Thread.Sleep(250); if (invokeBSL) { setRstPin(false); System.Threading.Thread.Sleep(10);/* TEST pin: GND */ setTestPin(true); System.Threading.Thread.Sleep(10);/* TEST pin: Vcc */ setTestPin(false); System.Threading.Thread.Sleep(10);/* TEST pin: GND */ setTestPin(true); System.Threading.Thread.Sleep(10); /* TEST pin: Vcc */ setTestPin(false); System.Threading.Thread.Sleep(10);/* TEST pin: GND */ setRstPin(true); System.Threading.Thread.Sleep(10);/* RST pin: Vcc */ setTestPin(true); /* TEST pin: GND */ } else { setRstPin(false); /* RST pin: GND */ System.Threading.Thread.Sleep(30); /* delays */ setRstPin(true); } System.Threading.Thread.Sleep(250); _serialPort.DiscardInBuffer(); _serialPort.DiscardOutBuffer(); mainForm.textBox1.AppendText(_serialPort.PortName + " is working\r\n"); } catch (Exception) { mainForm.textBox1.AppendText(_serialPort.PortName + " is not working\r\n"); } } public int MassErases() { int meraseCycles = 2; int i; mainForm.textBox1.AppendText("Mass Erase...\r\n"); mainForm.textBox1.Refresh(); for (i = 0; i < meraseCycles; i++) { if (i == 1) { mainForm.textBox1.AppendText("Additional mass erase cycles...\r\n"); //textBox1.Refresh(); } bslTxRx(BSL_MERAS, /* Command: Mass Erase */ 0xff00, /* Any address within flash memory. */ 0xa506, /* Required setting for mass erase! */ null, blkin); { } } passwdFile = null; /* No password file required! */ return 1; } public int txPasswd(string passwdFile) { int i; if (passwdFile == null) { /* Send "standard" password to get access to protected functions. */ /* Fill blkout with 0xff * (Flash is completely erased, the contents of all Flash cells is 0xff) */ for (i = 0; i < 0x20; i++) { blkout[i] = 0xff; } return (bslTxRx(BSL_TXPWORD, /* Command: Transmit Password */ 0xffe0, /* Address of interupt vectors */ 0x0020, /* Number of bytes */ blkout, blkin)); } else { /* Send TI TXT file holding interrupt vector data as password: */ // textBox1.Text = "Transmit PSW file"; // return (programTIText(passwdFile, ACTION_PASSWD)); return 1; } } public void setTestPin(Boolean level)//Controls TEST pin (0: VCC; 1: GND) { if (level == true) { _serialPort.RtsEnable = true; } else { _serialPort.RtsEnable = false; } _serialPort.RtsEnable = level ? _serialPort.RtsEnable = true : _serialPort.RtsEnable = false; } public void setRstPin(Boolean level)//Controls RST/NMI pin (0: GND; 1: VCC) { if (level == true) { _serialPort.DtrEnable = true; } else { _serialPort.DtrEnable = false; } _serialPort.DtrEnable = level ? _serialPort.DtrEnable = true : _serialPort.DtrEnable = false; } public int programBlk(uint addr, ushort len, uint action) { int error = ERR_NONE; if ((action & ACTION_PASSWD) != 0) { return (bslTxRx(BSL_TXPWORD, addr, len, blkout, blkin)); } /* if ACTION_PASSWD */ /* Check, if specified range is erased: */ if (action == ACTION_ERASE_CHECK) error = verifyBlk(addr, len, action & ACTION_ERASE_CHECK); else if (action == ACTION_ERASE_CHECK_FAST) error = verifyBlk(addr, len, action & ACTION_ERASE_CHECK_FAST); if (error != ERR_NONE) { return (error); } if ((action & ACTION_PROGRAM) != 0) { mainForm.textBox1.AppendText("Program starting at " + addr + " " + len + " bytes\r\n"); mainForm.textBox1.Refresh(); error = ERR_NONE; if (error != ERR_NONE) return (error); /* Set Offset: */ if (MSP430X == true) bslTxRx(BSL_MEMOFFSET, 0, (ushort)(addr >> 16), blkout, blkin); if (error != ERR_NONE) return (error); /* Program block: */ error = bslTxRx(BSL_TXBLK, addr, len, blkout, blkin); //printf("Error: %i\n", error); if (error != ERR_NONE) { return (error); /* Cancel, if error (ACTION_VERIFY is skipped!) */ } if (MSP430X == true) if (bslTxRx(BSL_MEMOFFSET, 0, (ushort)(0), null, blkin) != 0) return (error); } /* if ACTION_PROGRAM */ /* Verify block: */ error = verifyBlk(addr, len, action & ACTION_VERIFY); if (error != ERR_NONE) { return (error); } return (error); } /* programBlk */ public int ProgramFile(string filename) { if (ProgramF == true) { /* Parse file in TXT-Format and program data into flash memory. */ mainForm.textBox1.AppendText("Program" + filename + "\r\n"); if ((error = programTIText(filename, ACTION_PROGRAM)) != ERR_NONE) { // read out error address+3 from RAM (error address buffer) if ((loadedModel == LARGE_RAM_model) || (loadedModel == SMALL_RAM_model)) { if (MSP430X == true) if (bslTxRx(BSL_MEMOFFSET, 0, 0, null, blkin) != 0) signOff(error, true); if ((error = bslTxRx(BSL_RXBLK, bslerrbuf, 2, null, blkin)) == ERR_NONE) { _err = (blkin[1] << 8) + blkin[0]; } else return (signOff(error, false)); } else return (signOff(ERR_VERIFY_FAILED, false)); } else { mainForm.textBox1.AppendText(" " + byteCtr + " bytes programmed\r\n"); } } return 1; } public int bslSync() /* Transmits Synchronization character and expects to * receive Acknowledge character * Return == 0: OK * Return == 1: Sync. failed. */ { byte[] ch = new byte[1]; int chback; int loopcnt; const byte cLoopOut = 3; /* Max. trials to get synchronization */ for (loopcnt = 0; loopcnt < cLoopOut; loopcnt++) try { _serialPort.DiscardInBuffer(); ch[0] = BSL_SYNC; _serialPort.ReadTimeout = 50; _serialPort.Write(ch, 0, 1); chback = _serialPort.ReadByte(); if (chback == DATA_ACK) { return (ERR_NONE); } else return (ERR_BSL_SYNC); } catch (Exception ex) { } return (ERR_BSL_SYNC); } int comWaitForData(int count, uint timeout) /* exported! */ { int rxCount = 0; uint startTime = (uint)Environment.TickCount; do { int d = _serialPort.BytesToRead; } while (((rxCount = _serialPort.BytesToRead) < count) && (calcTimeout(startTime) <= timeout)); return (rxCount); } public uint calcTimeout(uint startTime) /* exported! */ { return ((uint)Environment.TickCount - startTime); } public void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { } private bool WriteTITextBytes(uint ulAddress, ushort wWordCount, ushort lpData) { uint i; return false; { } for (i = 0; i < (wWordCount * 2); i++) { return true; } } bool StartTITextOutput(byte FileName) { FileStream file = new FileStream("blink2.txt", FileMode.Open, FileAccess.Read, FileShare.Read); StreamReader sr = new StreamReader(file); string s = sr.ReadToEnd(); sr.Close(); file.Close(); return (s != null); } public int bslTxRx(byte cmd, uint addr, ushort len, byte[] blkout, byte[] blkin) { byte[] dataOut = new byte[MAX_FRAME_SIZE]; ushort length = 4; if (cmd == BSL_TXBLK) { /* Align to even start address */ if ((addr % 2) != 0) { /* Decrement address and */ addr--; /* fill first byte of blkout with 0xFF */ Array.Copy(blkout, 1, blkout, 0, len); blkout[0] = 0xFF; len++; } /* Make sure that len is even */ if ((len % 2) != 0) { /* Inc. len and fill last byte of blkout with 0xFF */ blkout[(len++)] = 0xFF; } } if (cmd == BSL_RXBLK) { /* Align to even start address */ if ((addr % 2) != 0) { /* Decrement address but */ addr--; /* request an additional byte. */ len++; } /* Make sure that len is even */ if ((len % 2) != 0) { len++; } } if ((cmd == BSL_TXBLK) || (cmd == BSL_TXPWORD)) { length = (ushort)(len + 4); } /* Add necessary information data to frame: */ dataOut[0] = (byte)(addr & 0x00ff); dataOut[1] = (byte)((addr >> 8) & 0x00ff); dataOut[2] = (byte)(len & 0x00ff); dataOut[3] = (byte)((len >> 8) & 0x00ff); if (blkout != null) { /* Copy data out of blkout into frame: */ Array.Copy(blkout, 0, dataOut, 4, len); } if (bslSync() != ERR_NONE) { return (ERR_BSL_SYNC); } /* Send frame: */ comTxRx(cmd, dataOut, (byte)length); if (blkin != null) { /* Copy received data out of frame buffer into blkin: */ Array.Copy(rxFrame, 4, blkin, 0, rxFrame[2]); } return (ERR_NONE); } public int comTxRx(byte cmd, byte[] dataOut, byte length) /* Sends the command cmd with the data given in dataOut to the * microcontroller and expects either an acknowledge or a frame * with result from the microcontroller. The results are stored * in dataIn (if not a NULL pointer is passed). * In this routine all the necessary protocol stuff is handled. * Returns zero if the function was successful. */ { byte[] txFrame = new byte[MAX_FRAME_SIZE]; ushort checksum = 0; int k = 0; int errCtr = 0; byte[] dataOut4096 = new byte[4096]; byte rxNum = 0; int resentFrame = 0; /* Transmitting part ----------------------------------------*/ /* Prepare data for transmit */ if ((length % 2) != 0) { /* Fill with one byte to have even number of bytes to send */ if (protocolMode == MODE_BSL) dataOut[length++] = 0xFF; // fill with 0xFF else dataOut[length++] = 0; // fill with zero } txFrame[0] = (byte)(DATA_FRAME | seqNo); txFrame[1] = cmd; txFrame[2] = length; txFrame[3] = length; reqNo = (byte)((seqNo + 1) % MAX_FRAME_COUNT); Array.Copy(dataOut, 0, txFrame, 4, length); checksum = calcChecksum(txFrame, (ushort)(length + 4)); txFrame[length + 4] = (byte)(checksum); txFrame[length + 5] = (byte)(checksum >> 8); { ushort accessAddr = (ushort)((0x0212 + (checksum ^ 0xffff)) & 0xfffe); //if (BSLMemAccessWarning && (accessAddr < BSL_CRITICAL_ADDR)) //{ // //textBox1.Text = "This command might change data at " + accessAddr; // /* 0x0212: Address of wCHKSUM */ //} } /* Transmit data: */ k = 0; /* Clear receiving queue: */ _serialPort.DiscardInBuffer(); Array.Clear(blkin, 0, 250); //PurgeComm(hComPort, PURGE_RXCLEAR | PURGE_RXABORT); do { _serialPort.Write(txFrame, k++, 1); } while (k < length + 6);//&& (_serialPort.BytesToRead == 0)); /* Check after each transmitted character, * if microcontroller did send a character (probably a NAK!). */ //int x = _serialPort.BytesToRead; /* Receiving part -------------------------------------------*/ rxFrame[2] = 0; rxFrame[3] = 0; /* Set lengths of received data to 0! */ do { lastError = 0; /* Clear last error */ if (comRxHeader(ref rxHeader, rxNum, (timeout * prolongFactor)) == 0) /* prolong timeout to allow execution of sent command */ { /* => Header received */ do { resentFrame = 0; switch (rxHeader) { case DATA_ACK: if (rxNum == reqNo) { seqNo = reqNo; return (lastError = ERR_NONE); /* Acknowledge received correctly => next frame */ } break; /* case DATA_ACK */ case DATA_NAK: return (lastError = ERR_RX_NAK); break; /* case DATA_NAK */ case DATA_FRAME: if (rxNum == reqNo) if (comRxFrame(rxHeader, rxNum) == 0) return (lastError = ERR_NONE); break; /* case DATA_FRAME */ case CMD_FAILED: /* Frame ok, but command failed. */ return (lastError = ERR_CMD_FAILED); break; /* case CMD_FAILED */ default: break; } /* switch */ errCtr = MAX_ERR_COUNT; } while ((resentFrame == 0) && (errCtr < MAX_ERR_COUNT)); } /* if (comRxHeader) */ else { /* => Timeout while receiving header */ errCtr = MAX_ERR_COUNT; } /* else (comRxHeader) */ } while (errCtr < MAX_ERR_COUNT); if (lastError == ERR_CMD_NOT_COMPLETED) { /* Accept QUERY_RESPONSE as real ACK and correct Seq.-No.: */ seqNo = reqNo; } if (lastError == ERR_NONE) return (lastError = ERR_COM); else return (lastError); } /* comTxRx */ public int comRxFrame(byte rxHeader, byte rxNum) { ushort checksum; byte rxLength; ushort rxLengthCRC; int x = 0; rxFrame[0] = (byte)(DATA_FRAME | rxNum); if (comWaitForData(3, timeout) >= 3) { _serialPort.Read(rxFrame, 1, 3); //_serialPort.Read(rxFrame, 1, 3); if ((rxFrame[1] == 0) && (rxFrame[2] == rxFrame[3])) { rxLength = rxFrame[2]; /* Pointer to rxFrame[2] */ rxLengthCRC = (ushort)(rxLength + 2); /* Add CRC-Bytes to length */ if (comWaitForData(rxLengthCRC, timeout) >= rxLengthCRC) { System.Threading.Thread.Sleep(10); _serialPort.Read(rxFrame, 4, rxLengthCRC); x = _serialPort.BytesToRead; /* Check received frame: */ checksum = calcChecksum(rxFrame, (ushort)(rxLength + 4)); /* rxLength+4: Length with header but w/o CRC */ if ((rxFrame[rxLength + 4] == (byte)checksum) && (rxFrame[rxLength + 5] == (byte)(checksum >> 8))) { return (ERR_NONE); /* Frame received correctly (=> send next frame) */ } /* if (Checksum correct?) */ } /* if (Data: no timeout?) */ } /* if (Add. header info. correct?) */ } /* if (Add. header info.: no timeout?) */ return (ERR_COM); /* Frame has errors! */ } /* comRxFrame */ public int comRxHeader(ref byte rxHeader, byte rxNum, uint timeout) { byte[] Hdr = new byte[1]; if (comWaitForData(1, timeout) >= 1) { _serialPort.Read(Hdr, 0, 1); rxHeader = (byte)(Hdr[0] & 0xf0); rxNum = (byte)(Hdr[0] & 0x0f); if (protocolMode == MODE_BSL) { reqNo = 0; seqNo = 0; rxNum = 0; } return (ERR_NONE); } else { rxHeader = 0; rxNum = 0; return (lastError = ERR_RX_HDR_TIMEOUT); } } public ushort calcChecksum(byte[] data, ushort length) { // The return value. ushort retVal = 0; // Cycle through the bytes. for (ushort index = 0; index < length / 2; ++index) { // Get the current unsigned short. ushort current = BitConverter.ToUInt16(data, index * 2); ushort test = current; // Alter the checksum. retVal ^= current; } // Return the checksum. return (ushort)(retVal ^ 0xffff); } public int programTIText(string filename, uint action) { int error = ERR_NONE; int linelen = 0; int linepos = 0; int KBytes, KBytesbefore = -1; ushort dataframelen = 0; uint currentAddr = 0; char[] strdata = new char[128]; string LinetoString; //StreamReader infile= new StreamReader(new FileStream("c:\\blink2.txt", FileMode.Open, FileAccess.Read, FileShare.Read)); StreamReader infile = new StreamReader(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)); byteCtr = 0; if (infile != null) /* Convert data for MSP430, TXT-File is parsed line by line: */ while (true) /* FRGR */ { /* Read one line: */ LinetoString = infile.ReadLine(); LinetoString = LinetoString + Environment.NewLine; for (int j = 0; j < LinetoString.Length; ++j) LinetoString.CopyTo(j, strdata, j, 1); if ((strdata[0] == null) || (strdata[0] == 'q')) { /* => send frame and quit */ if (dataframelen > 0) /* Data in frame? */ { error = programBlk(currentAddr, dataframelen, action); byteCtr += dataframelen; /* Byte Counter */ dataframelen = 0; } break; /* FRGR */ } linelen = LinetoString.Length; if (strdata[0] == '@') /* if @ => new address => send frame and set new addr. */ { if (dataframelen > 0) { error = programBlk(currentAddr, dataframelen, action); byteCtr += dataframelen; /* Byte Counter */ dataframelen = 0; } //currentAddr = 16384; UInt32.TryParse((LinetoString.Substring(1, 4)), System.Globalization.NumberStyles.HexNumber, null, out currentAddr); //sscanf(strdata[1], "%lx\n", currentAddr); continue; } /* Transfer data in line into blkout: */ for (linepos = 0; linepos < linelen - 3; linepos += 3, dataframelen++) { Byte.TryParse((LinetoString.Substring(linepos, 2)), System.Globalization.NumberStyles.HexNumber, null, out (blkout[dataframelen])); /* (Max 16 bytes per line!) */ } if (dataframelen > maxData - 16) /* if frame is getting full => send frame */ { error = programBlk(currentAddr, dataframelen, action); byteCtr += dataframelen; /* Byte Counter */ currentAddr += dataframelen; dataframelen = 0; /* bargraph: indicates succession, actualize only when changed. FRGR */ KBytes = (byteCtr + 512) / 1024; if (KBytesbefore != KBytes) { KBytesbefore = KBytes; //printf("\r%02d KByte ", KBytes); //printf("\xDE"); //for (i=0;i> 16), null, blkin) != 0) return (error); addr = addr & 0xFFFF; } error = bslTxRx(BSL_RXBLK, addr, len, null, blkin); //printf("Error: %i\n", error); if (error != ERR_NONE) { return (error); /* Cancel, if read error */ } else { for (i = 0; i < len; i++) { if ((action & ACTION_VERIFY) != 0) { /* Compare data in blkout and blkin: */ if (blkin[i] != blkout[i]) { //printf("Verification failed at %x (%x, %x)\n", addr+i, blkin[i], blkout[i]); return (ERR_VERIFY_FAILED); /* Verify failed! */ } continue; } if ((action & ACTION_ERASE_CHECK) != 0) { /* Compare data in blkin with erase pattern: */ if (blkin[i] != 0xff) { //printf("Erase Check failed at %x (%x)\n", addr+i, blkin[i]); return (ERR_ERASE_CHECK_FAILED); /* Erase Check failed! */ } continue; } /* if ACTION_ERASE_CHECK */ } /* for (i) */ } /* else */ if (MSP430X == true) if (bslTxRx(BSL_MEMOFFSET, 0, (ushort)(0), null, blkin) != 0) return (error); } /* if ACTION_VERIFY | ACTION_ERASE_CHECK */ else if ((action & ACTION_ERASE_CHECK_FAST) != 0) /* FRGR 02/01 */ { error = ERR_NONE; ; if (error != ERR_NONE) return (error); error = bslTxRx(BSL_ECHECK, addr, len, null, blkin); //printf("Error: %i\n", error); if (error != ERR_NONE) { return (ERR_ERASE_CHECK_FAILED); /* Erase Check failed! */ } } return (error); } public int signOff(int ERR_VERIFY_FAILED, bool xt) { return 1; } public int txPasswd2(string passwdFile) { int i; /* Send "standard" password to get access to protected functions. */ mainForm.textBox1.AppendText("Transmit standard password...\r\n"); mainForm.textBox1.Refresh(); /* Fill blkout with 0xff * (Flash is completely erased, the contents of all Flash cells is 0xff) */ for (i = 0; i < 0x1E; i++) { blkout[i] = 0xff; } blkout[30] = 0x00; blkout[31] = 0x40; if ( (bslTxRx(BSL_TXPWORD, /* Command: Transmit Password */ 0xffe0, /* Address of interupt vectors */ 0x0020, /* Number of bytes */ blkout, blkin) == ERR_BSL_SYNC)) { throw new System.IO.InvalidDataException(); } else { return 1; } } } }