using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace KFDtool.BSL430 { public class BSLCoreCommandParser { // PC --> MSP430 COMMANDS // Subset of CMDs in flash private const byte RXDATABLOCKFAST = 0x1B; private const byte RXPASSWORD = 0x11; private const byte LOADPC = 0x17; // Full set of RAM CMDs private const byte RXDATABLOCK = 0x10; private const byte ERASESGMENT = 0x12; private const byte UNLOCKANDLOCKINFO = 0x13; private const byte RESERVED = 0x14; private const byte MASSERASE = 0x15; private const byte CRCCHECK = 0x16; private const byte TXDATABLOCK = 0x18; private const byte TXBSLVERSION = 0x19; // Not implemented in MSP430 F5xx/6xx private const byte TXBUFFERSIZE = 0x1A; // MSP430 --> PC RESPONSES private const byte MULTIPLEBYTESRESONSE = 0x3A; private const byte SINGLEBYTERESONSE = 0x3B; public const byte MSG_NOTAMESSAGE = 0xFF; public const byte MSG_SUCCESSFULL = 0x00; public const byte MSG_FLASHWRITEFAILED = 0x01; public const byte MSG_FLASHFAILBIT = 0x02; public const byte MSG_VOLTAGECHANGE = 0x03; public const byte MSG_BSLLOCKED = 0x04; public const byte MSG_PASSWORDERROR = 0x05; public const byte MSG_WRITEFORBIDDEN = 0x06; public const byte MSG_UNKNOWNCMD = 0x07; public const byte MSG_PACKETTOOLONG = 0x08; /// /// RX Data Block /// The BSL core writes bytes D1 through Dn starting from the location /// specified in the address fields. /// /// /// public static byte[] RXDataBlock(int address, byte[] data) { int length = data.Length + 4; byte[] coreCmd = new byte[length]; byte[] add = BitConverter.GetBytes(address); if (BitConverter.IsLittleEndian) Array.Reverse(add); coreCmd[0] = RXDATABLOCK; coreCmd[1] = add[3]; coreCmd[2] = add[2]; coreCmd[3] = add[1]; // Copy data int i = 4; foreach (byte b in data) { coreCmd[i] = b; i++; } return coreCmd; } /// /// RX Data Block Fast // This command is identical to RX Data Block, // except there is no reply indicating the data was correctly // programmed. It is used primarily to speed up USB programming. /// /// /// /// public static byte[] RXDataBlockFast(int address, byte[] data) { byte[] cmd = RXDataBlock(address, data); cmd[0] = RXDATABLOCKFAST; return cmd; } /// /// RX Password /// The BSL core receives the password contained in the packet and unlocks the BSL protected /// commands if the password matches the top 16 words in the BSL interrupt vector table(located /// between addresses 0xFFE0 and 0xFFFF). When an incorrect password is given, a mass erase is /// initiated.This means all code flash is erased, but not Information Memory. /// Known bug: The password for the BSL is the bytes between addresses 0xFFF0 and 0xFFFF. /// This means that this BSL version expects only 16 bytes for a password in the RX Password /// command.Sending 32 bytes returns an error. /// /// /// public static byte[] RXPassword(byte[] password) { byte[] coreCmd = new byte[1 + password.Length]; coreCmd[0] = RXPASSWORD; // Copy data int i = 1; foreach (byte b in password) { coreCmd[i] = b; i++; } return coreCmd; } /// /// Erase Segment /// The flash segment containing the given address is subjected to an erase. /// /// /// public static byte[] EraseSegment(int address) { byte[] coreCmd = new byte[4]; byte[] add = BitConverter.GetBytes(address); if (BitConverter.IsLittleEndian) Array.Reverse(add); coreCmd[0] = ERASESGMENT; coreCmd[1] = add[3]; coreCmd[2] = add[2]; coreCmd[3] = add[1]; return coreCmd; } /// /// Unlock and Lock Info /// This command causes the INFO_A lock to toggle to either protect or lock the INFO_A segment.See /// the MSP430x5xx and MSP430x6xx Family User's Guide for more detail on this lock. This command /// must be sent before an erase segment command for INFO_A but is not required before a mass erase. /// /// public static byte[] UnlockAndLockInfo() { byte[] coreCmd = new byte[1]; coreCmd[0] = UNLOCKANDLOCKINFO; return coreCmd; } /// /// Mass Erase // All code Flash in the MSP430 is erased.This function does not erase Information Memory. /// /// public static byte[] MassErase() { byte[] coreCmd = new byte[1]; coreCmd[0] = MASSERASE; return coreCmd; } /// /// The MSP430 performs a 16-bit CRC check using the CCITT standard. The address given is the first /// byte of the CRC check.Two bytes are used for the length. /// /// /// /// public static byte[] CRCCheck(int address, int length) { byte[] coreCmd = new byte[6]; byte[] add = BitConverter.GetBytes(address); if (BitConverter.IsLittleEndian) Array.Reverse(add); byte[] len = BitConverter.GetBytes(length); if (BitConverter.IsLittleEndian) Array.Reverse(len); coreCmd[0] = RXDATABLOCK; coreCmd[1] = add[3]; coreCmd[2] = add[2]; coreCmd[3] = add[1]; coreCmd[4] = len[3]; coreCmd[5] = len[2]; return coreCmd; } /// /// Load PC /// Causes the BSL to begin execution at the given address using a CALLA instruction.As BSL code is /// immediately exited with this instruction, no core response can be expected. /// /// /// public static byte[] LoadPC(int address) { byte[] cmd = EraseSegment(address); cmd[0] = LOADPC; return cmd; } /// /// No Description /// /// /// /// public static byte[] TXDataBlock(int address, int length) { byte[] cmd = CRCCheck(address, length); cmd[0] = TXDATABLOCK; return cmd; } /// /// TX BSL Version /// BSL transmits its version information(see Section 3.7.3 for more details). /// /// public static byte[] TXBSLVersion() { byte[] coreCmd = new byte[1]; coreCmd[0] = TXBSLVERSION; return coreCmd; } /// /// The BSL transmits a value that represents the number of bytes available in its data buffer for sending /// or receiving BSL core data packets. /// The TX Buffer Size command is currently not implemented in the BSL on MSP430 F5xx/6xx. /// /// public static byte[] TXBufferSize() { byte[] coreCmd = new byte[1]; coreCmd[0] = TXBUFFERSIZE; return coreCmd; } public static int readMessage(byte[] data) { if (data[0] != SINGLEBYTERESONSE) return MSG_NOTAMESSAGE; if (data[1] >= 0x00 && data[1] <= MSG_PACKETTOOLONG) return data[1]; return MSG_NOTAMESSAGE; } /// /// Returns the list of RXDataBlockFast to be sent to the device. /// /// List of sections of the code to be uploaded. /// Nb of bytes for each cmd. /// List of commands to be sent 1-by-1 public static List listOfRxDataBlock(List codeSections, int bufferSize, bool fastBlock) { int address; List commands = new List(); foreach (CodeSection section in codeSections) { int i, j; address = section.StartAddress; for (i = 0; i < section.binaryCode.Length; i += bufferSize - 4) { // Copy the content byte[] data = new byte[bufferSize - 4]; for (j = 0; j < bufferSize - 4 && i + j < section.binaryCode.Length; j++) data[j] = section.binaryCode[i + j]; // If last command is not full, fill with 0xFF if (i + j == section.binaryCode.Length) for (; j < bufferSize - 4; j++) data[j] = 0xFF; // Prepare the command if (fastBlock) commands.Add(RXDataBlockFast(address, data)); else commands.Add(RXDataBlock(address, data)); // Update the address address += bufferSize - 4; } } return commands; } } }