private HexLoader(string fileName, bool bBootLoaderCode) { this.fileName = fileName; // Assume failure until finished loading. hexLoaded = false; applicationRowCount = 0; crc = 0; // Parse the lines of the hex file. If the entire file is parsed successfully, set // hexLoaded to true to indicate the file was successfully loaded. Otherwise if // an unrecognized line is reached, return early with hexLoaded = false. string[] hexLines = System.IO.File.ReadAllLines(fileName); if (hexLines != null) { // Loop to load hex records from the input file. The format is as follows: // // :BBAAAATTHHHH....HHHCC // // where: // // BB A two digit hexadecimal byte count representing the number of data // bytes that will appear on the line. // AAAA A four digit hexadecimal address representing the starting address of // the data record. // TT A two digit record type: // 00 - Data record // 01 - End of File record // 02 - Segment address record // 04 - Linear address record // HH A two digit hexadecimal data byte, presented in low byte/high byte // combinations. // CC A two digit hexadecimal checksum that is the two's complement of the // sum of all preceding bytes in the record. // uint baseAddress = 0; bool endOfFileReached = false; foreach (string line in hexLines) { if (endOfFileReached) { return; // Failed; extra data found after end-of-file marker. } // Parse the line from the hex file. if ((line.Length < 11) || (line[0] != ':') || ((line.Length & 1) == 0)) { return; // Line does not have minimum length, does not start with ':', or does not have an even number of hex digits. } // Extract field values. uint dataByteCount = Convert.ToUInt32(line.Substring(1, 2), 16); uint address = Convert.ToUInt32(line.Substring(3, 4), 16); RecordType recordType = (RecordType)Convert.ToUInt32(line.Substring(7, 2), 16); uint checksumDigit = Convert.ToUInt32(line.Substring(line.Length - 2, 2), 16); byte checksum = (byte)(dataByteCount + (address >> 8) + (address & 0x00FF) + (uint)recordType + checksumDigit); int dataDigitIndex = 9; int dataDigitEnd = line.Length - 2; MyDebug.Assert(2 * dataByteCount == dataDigitEnd - dataDigitIndex); byte[] dataBytes = new byte[dataByteCount]; uint dataByteIndex = 0; while (dataDigitIndex < dataDigitEnd) { byte dataByte = Convert.ToByte(line.Substring(dataDigitIndex, 2), 16); dataDigitIndex += 2; dataBytes[dataByteIndex++] = dataByte; checksum += dataByte; } // The final byte is the checksum byte. All of the bytes in the string should add up to zero. if (checksum != 0) { return; // Checksum failed. } switch (recordType) { case RecordType.Data: AddData(baseAddress + address, dataBytes); break; case RecordType.EndOfFile: endOfFileReached = true; break; case RecordType.SegmentAddress: return; // Unexpected record type. case RecordType.LinearAddress: MyDebug.Assert(address == 0); baseAddress = (((uint)dataBytes[0] << 8) | dataBytes[1]) << 16; break; default: return; // Unexpected record type. } } } // Hex file has loaded successfully. Calculate the row count and CRC. if (CalculateRowCountAndCRC(bBootLoaderCode, out applicationRowCount, out totalRowCount, out crc)) { if (applicationRowCount == 0) { throw new Exception("File contains no application data."); } hexLoaded = true; // Success! } }
private bool CalculateRowCountAndCRC(bool bBootLoaderCode, out uint applicationRowCount, out uint totalRowCount, out ushort crc) { applicationRowCount = 0; totalRowCount = 0; crc = 0; uint startAllowableRowIndex; uint endAllowableRowIndex; if (bBootLoaderCode) { startAllowableRowIndex = FirstBootLoaderRowIndex; endAllowableRowIndex = EndBootLoaderRowIndex; } else { startAllowableRowIndex = FirstApplicationRowIndex; endAllowableRowIndex = LastAllowableApplicationRow; } MyDebug.Assert(BlankRow.Length == BytesPerRow); uint currentRowIndex = 0; uint rowIndex; byte[] row; bool bFirst = true; CRC crcCalculator = new CRC(); while (EnumerateRows(bFirst, out row, out rowIndex)) { bFirst = false; totalRowCount++; MyDebug.Assert(row.Length == BytesPerRow); MyDebug.Assert(rowIndex >= currentRowIndex); // Failure indicates a bug in EnumerateRows(). // The CRC calculation does not include flash memory above the user program flash // memory area, as defined in chapter 3 of the dsPIC33FJXXXMCX06/X08/X10 Motor // Control Family datasheet. Skip any such data. if (rowIndex >= LastAllowableApplicationRow) { MyDebug.Assert((rowIndex == 0x1F000) || IsBlank(row)); // Only the single processor configuration row is expected. continue; } // Take care of any rows that are skipped in the hex file. while (currentRowIndex < rowIndex) { // Ignore blank rows in the protected area. They are not included in the CRC calculation. if ((currentRowIndex < FirstPageAllowableRows) || (currentRowIndex >= startAllowableRowIndex)) { // Assume the skipped row is all 0xFF's. crcCalculator.addBuffer(BlankRow); } currentRowIndex++; } if ((rowIndex < FirstPageAllowableRows) || ((rowIndex >= startAllowableRowIndex) && (rowIndex < endAllowableRowIndex))) { // Update the CRC with this row. crcCalculator.addBuffer(row); } else { // Code was specified for the protected areas. If the specified code is // something other than all FF's, fail the hex loading. foreach (byte rowByte in row) { if (rowByte != 0xFF) { throw new Exception("File contains flash data in a protected page."); } } } currentRowIndex++; } if (currentRowIndex > startAllowableRowIndex) { applicationRowCount = currentRowIndex - startAllowableRowIndex; } crc = crcCalculator.crc; return(true); }
private void AddData(uint address, byte[] dataBytes) { // A page contains 512 instruction words (1536 bytes) but has an address space range // of 1024 from the processor's point of view, but 2048 from the .hex file's point of // view. Although each instruction is 24 bits, they are specified in 32 bits, so they // will be stored in pageList as 32 bits. MyDebug.Assert((address & 3) == 0); // Address must be multiple of 4 for 16-bit processor. MyDebug.Assert((dataBytes.Length & 3) == 0); // Data is expected in 4-byte words for 16-bit processor. uint dataWords = (uint)dataBytes.Length / 4; uint wordIndex = address / 4; uint pageIndex = wordIndex / InstructionWordsPerPage; uint dstWordIndex = wordIndex % InstructionWordsPerPage; uint srcByteIndex = 0; uint srcByteEndIndex = (uint)dataBytes.Length; uint srcByteEndIndexNextPass = 0; // If the byte series overlaps pages, restrict the number of bytes that will be copied // on the first pass. if (dstWordIndex + dataWords > InstructionWordsPerPage) { srcByteEndIndexNextPass = srcByteEndIndex; srcByteEndIndex -= 4 * (dstWordIndex + dataWords - InstructionWordsPerPage); } // The following loops one or two times depending on if the data overlaps a page boundary. while (true) { // Find the page for the specified address. If it hasn't yet been created, allocate // it now and initialize its contents to all 0xFFs. UInt32[] page = (UInt32[])pageList[pageIndex]; while (page == null) { page = new UInt32[InstructionWordsPerPage]; for (int i = 0; i < page.Length; i++) { page[i] = 0x00FFFFFF; // Only 24 bits are actually stored. } pageList.Add(pageIndex, page); } // Add the new data from srcByteIndex to srcByteEndIndex to its destination page. while (srcByteIndex < srcByteEndIndex) { UInt32 word = 0; for (int i = 0; i < 32; i += 8) { word |= (UInt32)dataBytes[srcByteIndex++] << i; } MyDebug.Assert(word < 0x01000000); // If any word is specified multiple times in the .hex file, make sure they // always specify the same value. MyDebug.Assert((page[dstWordIndex] == 0x00FFFFFF) || (page[dstWordIndex] == word)); page[dstWordIndex++] = word; } // Break out of the loop if all of the data has been saved. if (srcByteEndIndexNextPass == 0) { break; } // The data byte series overlaps two pages. Set up for the next page and loop to // copy to the second page. pageIndex++; dstWordIndex = 0; srcByteEndIndex = srcByteEndIndexNextPass; srcByteEndIndexNextPass = 0; } }
/// <summary> /// Overide method RS232Port.OnMessageReceived(). This is called by the base class when a complete /// inbound message has been received. /// </summary> /// <param name="message">full message receive to sort and process</param> public override void OnMessageReceived(string message) { const string completionTag = "Tunnel|"; const string asyncEventTag = "AsyncEvent|"; if (message.StartsWith(completionTag)) { // MyDebug.Assert(completionPacket == null,"Error in OnMessageReceived 1"); int dstBytes = (message.Length - completionTag.Length) / 2; byte[] newCompletionPacket = new byte[dstBytes]; int srcIndex = completionTag.Length; uint dstIndex = 0; while (srcIndex < message.Length) { newCompletionPacket[dstIndex++] = (byte)Convert.ToUInt32(message.Substring(srcIndex, 2), 16); srcIndex += 2; } MyDebug.Assert(dstIndex == dstBytes, "Error in OnMessageReceived 2"); completionPacket = newCompletionPacket; if (completionEvent != null) { completionEvent.Set(); } } else if (message.StartsWith(asyncEventTag)) { int dstBytes = 2 + (message.Length - asyncEventTag.Length) / 2; byte[] newAsyncEventPacket = new byte[dstBytes]; int srcIndex = asyncEventTag.Length; ushort command = (ushort)CommandType.PBCMD_AsyncEvent; newAsyncEventPacket[0] = (byte)(command & 0xFF); newAsyncEventPacket[1] = (byte)((command >> 8) & 0xFF); uint dstIndex = 2; while (srcIndex < message.Length) { newAsyncEventPacket[dstIndex++] = (byte)Convert.ToUInt32(message.Substring(srcIndex, 2), 16); srcIndex += 2; } MyDebug.Assert(dstIndex == dstBytes, "Error in OnMessageReceived 3"); lock (lockObj) { asyncEventQueue.Enqueue(newAsyncEventPacket); } if (asyncEventEvent != null) { asyncEventEvent.Set(); } } else if (message.StartsWith("PowerOFF")) { int dstBytes = 10; byte[] newAsyncEventPacket = new byte[dstBytes]; int srcIndex = asyncEventTag.Length; ushort command = (ushort)CommandType.PBCMD_AsyncEvent; newAsyncEventPacket[0] = (byte)(command & 0xFF); newAsyncEventPacket[1] = (byte)((command >> 8) & 0xFF); uint dstIndex = 2; newAsyncEventPacket[dstIndex++] = (byte)Convert.ToUInt32("FF", 16); srcIndex += 2; newAsyncEventPacket[dstIndex++] = (byte)Convert.ToUInt32("FF", 16); srcIndex += 2; lock (lockObj) { asyncEventQueue.Enqueue(newAsyncEventPacket); } if (asyncEventEvent != null) { asyncEventEvent.Set(); } } else if (message.StartsWith("PowerON")) { int dstBytes = 10; byte[] newAsyncEventPacket = new byte[dstBytes]; int srcIndex = asyncEventTag.Length; ushort command = (ushort)CommandType.PBCMD_AsyncEvent; newAsyncEventPacket[0] = (byte)(command & 0xFF); newAsyncEventPacket[1] = (byte)((command >> 8) & 0xFF); uint dstIndex = 2; newAsyncEventPacket[dstIndex++] = (byte)Convert.ToUInt32("EE", 16); srcIndex += 2; newAsyncEventPacket[dstIndex++] = (byte)Convert.ToUInt32("EE", 16); srcIndex += 2; lock (lockObj) { asyncEventQueue.Enqueue(newAsyncEventPacket); } if (asyncEventEvent != null) { asyncEventEvent.Set(); } } else { if (inboundMessageQueue != null) { inboundMessageQueue.Enqueue(message); if (inboundMessageEvent != null) { inboundMessageEvent.Set(); } } } }