KFDtool/sw/control/KFDtool.BSL430/BSLCoreCommandParser.cs

316 lines
11 KiB
C#

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;
/// <summary>
/// RX Data Block
/// The BSL core writes bytes D1 through Dn starting from the location
/// specified in the address fields.
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="address"></param>
/// <param name="data"></param>
/// <returns></returns>
public static byte[] RXDataBlockFast(int address, byte[] data)
{
byte[] cmd = RXDataBlock(address, data);
cmd[0] = RXDATABLOCKFAST;
return cmd;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
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;
}
/// <summary>
/// Erase Segment
/// The flash segment containing the given address is subjected to an erase.
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <returns></returns>
public static byte[] UnlockAndLockInfo()
{
byte[] coreCmd = new byte[1];
coreCmd[0] = UNLOCKANDLOCKINFO;
return coreCmd;
}
/// <summary>
/// Mass Erase
// All code Flash in the MSP430 is erased.This function does not erase Information Memory.
/// </summary>
/// <returns></returns>
public static byte[] MassErase()
{
byte[] coreCmd = new byte[1];
coreCmd[0] = MASSERASE;
return coreCmd;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="address"></param>
/// <param name="length"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
public static byte[] LoadPC(int address)
{
byte[] cmd = EraseSegment(address);
cmd[0] = LOADPC;
return cmd;
}
/// <summary>
/// No Description
/// </summary>
/// <param name="address"></param>
/// <param name="length"></param>
/// <returns></returns>
public static byte[] TXDataBlock(int address, int length)
{
byte[] cmd = CRCCheck(address, length);
cmd[0] = TXDATABLOCK;
return cmd;
}
/// <summary>
/// TX BSL Version
/// BSL transmits its version information(see Section 3.7.3 for more details).
/// </summary>
/// <returns></returns>
public static byte[] TXBSLVersion()
{
byte[] coreCmd = new byte[1];
coreCmd[0] = TXBSLVERSION;
return coreCmd;
}
/// <summary>
/// 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.
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// Returns the list of RXDataBlockFast to be sent to the device.
/// </summary>
/// <param name="codeSections">List of sections of the code to be uploaded.</param>
/// <param name="bufferSize">Nb of bytes for each cmd.</param>
/// <returns>List of commands to be sent 1-by-1</returns>
public static List<byte[]> listOfRxDataBlock(List<CodeSection> codeSections, int bufferSize,
bool fastBlock)
{
int address;
List<byte[]> commands = new List<byte[]>();
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;
}
}
}