mirror of https://github.com/duggerd/KFDtool.git
700 lines
18 KiB
C#
700 lines
18 KiB
C#
using KFDtool.Adapter.Protocol.Serial;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace KFDtool.Adapter.Protocol.Adapter
|
|
{
|
|
public class AdapterProtocol
|
|
{
|
|
private const int AP_TIMEOUT = 1000; // 1 second
|
|
|
|
/* COMMAND OPCODES */
|
|
private const byte CMD_READ = 0x11;
|
|
private const byte CMD_WRITE_INFO = 0x12;
|
|
private const byte CMD_ENTER_BSL_MODE = 0x13;
|
|
private const byte CMD_RESET = 0x14;
|
|
private const byte CMD_SELF_TEST = 0x15;
|
|
private const byte CMD_SEND_KEY_SIG = 0x16;
|
|
private const byte CMD_SEND_BYTE = 0x17;
|
|
|
|
/* RESPONSE OPCODES */
|
|
private const byte RSP_ERROR = 0x20;
|
|
private const byte RSP_READ = 0x21;
|
|
private const byte RSP_WRITE_INFO = 0x22;
|
|
private const byte RSP_ENTER_BSL_MODE = 0x23;
|
|
private const byte RSP_RESET = 0x24;
|
|
private const byte RSP_SELF_TEST = 0x25;
|
|
private const byte RSP_SEND_KEY_SIG = 0x26;
|
|
private const byte RSP_SEND_BYTE = 0x27;
|
|
|
|
/* BROADCAST OPCODES */
|
|
private const byte BCST_RECEIVE_BYTE = 0x31;
|
|
|
|
/* READ OPCODES */
|
|
private const byte READ_AP_VER = 0x01;
|
|
private const byte READ_FW_VER = 0x02;
|
|
private const byte READ_UNIQUE_ID = 0x03;
|
|
private const byte READ_MODEL_ID = 0x04;
|
|
private const byte READ_HW_REV = 0x05;
|
|
private const byte READ_SER_NUM = 0x06;
|
|
|
|
/* WRITE OPCODES */
|
|
private const byte WRITE_MDL_REV = 0x01;
|
|
private const byte WRITE_SER = 0x02;
|
|
|
|
/* ERROR OPCODES */
|
|
private const byte ERR_OTHER = 0x00;
|
|
private const byte ERR_INVALID_CMD_LENGTH = 0x01;
|
|
private const byte ERR_INVALID_CMD_OPCODE = 0x02;
|
|
private const byte ERR_INVALID_READ_OPCODE = 0x03;
|
|
private const byte ERR_READ_FAILED = 0x04;
|
|
private const byte ERR_INVALID_WRITE_OPCODE = 0x05;
|
|
private const byte ERR_WRITE_FAILED = 0x06;
|
|
|
|
private SerialProtocol Lower;
|
|
|
|
public AdapterProtocol(string portName)
|
|
{
|
|
Lower = new SerialProtocol(portName);
|
|
}
|
|
|
|
public void Open()
|
|
{
|
|
Lower.Open();
|
|
}
|
|
|
|
public void Close()
|
|
{
|
|
Lower.Close();
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
Lower.Clear();
|
|
}
|
|
|
|
public byte[] ReadAdapterProtocolVersion()
|
|
{
|
|
List<byte> cmd = new List<byte>();
|
|
|
|
/*
|
|
* CMD: READ AP VERSION
|
|
*
|
|
* [0] CMD_READ
|
|
* [1] READ_AP_VER
|
|
*/
|
|
|
|
cmd.Add(CMD_READ);
|
|
cmd.Add(READ_AP_VER);
|
|
|
|
Lower.Send(cmd);
|
|
|
|
List<byte> rsp = Lower.Read(AP_TIMEOUT);
|
|
|
|
/*
|
|
* RSP: READ AP VERSION
|
|
*
|
|
* [0] RSP_READ
|
|
* [1] READ_AP_VER
|
|
* [2] api major version
|
|
* [3] api minor version
|
|
* [4] api patch version
|
|
*/
|
|
|
|
if (rsp.Count == 5)
|
|
{
|
|
if (rsp[0] == RSP_READ)
|
|
{
|
|
if (rsp[1] == READ_AP_VER)
|
|
{
|
|
byte[] ver = new byte[3];
|
|
ver[0] = rsp[2];
|
|
ver[1] = rsp[3];
|
|
ver[2] = rsp[4];
|
|
return ver;
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid read opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response length");
|
|
}
|
|
}
|
|
|
|
public byte[] ReadFirmwareVersion()
|
|
{
|
|
List<byte> cmd = new List<byte>();
|
|
|
|
/*
|
|
* CMD: READ FW VERSION
|
|
*
|
|
* [0] CMD_READ
|
|
* [1] READ_FW_VER
|
|
*/
|
|
|
|
cmd.Add(CMD_READ);
|
|
cmd.Add(READ_FW_VER);
|
|
|
|
Lower.Send(cmd);
|
|
|
|
List<byte> rsp = Lower.Read(AP_TIMEOUT);
|
|
|
|
/*
|
|
* RSP: READ FW VERSION
|
|
*
|
|
* [0] RSP_READ
|
|
* [1] READ_FW_VER
|
|
* [2] fw major version
|
|
* [3] fw minor version
|
|
* [4] fw patch version
|
|
*/
|
|
|
|
if (rsp.Count == 5)
|
|
{
|
|
if (rsp[0] == RSP_READ)
|
|
{
|
|
if (rsp[1] == READ_FW_VER)
|
|
{
|
|
byte[] ver = new byte[3];
|
|
ver[0] = rsp[2];
|
|
ver[1] = rsp[3];
|
|
ver[2] = rsp[4];
|
|
return ver;
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid read opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response length");
|
|
}
|
|
}
|
|
|
|
public byte[] ReadUniqueId()
|
|
{
|
|
List<byte> cmd = new List<byte>();
|
|
|
|
/*
|
|
* CMD: READ UNIQUE ID
|
|
*
|
|
* [0] CMD_READ
|
|
* [1] READ_UNIQUE_ID
|
|
*/
|
|
|
|
cmd.Add(CMD_READ);
|
|
cmd.Add(READ_UNIQUE_ID);
|
|
|
|
Lower.Send(cmd);
|
|
|
|
List<byte> rsp = Lower.Read(AP_TIMEOUT);
|
|
|
|
/*
|
|
* RSP: READ UNIQUE ID
|
|
*
|
|
* [0] RSP_READ
|
|
* [1] READ_UNIQUE_ID
|
|
* [2] unique id length
|
|
* [3 to 3 + unique id length] raw unique id if unique id length > 0
|
|
*/
|
|
|
|
if (rsp.Count >= 3)
|
|
{
|
|
if (rsp[0] == RSP_READ)
|
|
{
|
|
if (rsp[1] == READ_UNIQUE_ID)
|
|
{
|
|
if (rsp[2] == 0) // no unique id
|
|
{
|
|
return new byte[0];
|
|
}
|
|
else if (rsp[2] == (rsp.Count - 3))
|
|
{
|
|
int len = rsp[2];
|
|
byte[] num = new byte[len];
|
|
Array.Copy(rsp.ToArray(), 3, num, 0, len);
|
|
return num;
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("message length field and message length mismatch");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid read opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response length");
|
|
}
|
|
}
|
|
|
|
public byte ReadModelId()
|
|
{
|
|
List<byte> cmd = new List<byte>();
|
|
|
|
/*
|
|
* CMD: READ MODEL ID
|
|
*
|
|
* [0] CMD_READ
|
|
* [1] READ_MODEL_ID
|
|
*/
|
|
|
|
cmd.Add(CMD_READ);
|
|
cmd.Add(READ_MODEL_ID);
|
|
|
|
Lower.Send(cmd);
|
|
|
|
List<byte> rsp = Lower.Read(AP_TIMEOUT);
|
|
|
|
/*
|
|
* RSP: READ MODEL ID
|
|
*
|
|
* [0] RSP_READ
|
|
* [1] READ_MODEL_ID
|
|
* [2] model id
|
|
*/
|
|
|
|
if (rsp.Count == 3)
|
|
{
|
|
if (rsp[0] == RSP_READ)
|
|
{
|
|
if (rsp[1] == READ_MODEL_ID)
|
|
{
|
|
return rsp[2];
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid read opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response length");
|
|
}
|
|
}
|
|
|
|
public byte[] ReadHardwareRevision()
|
|
{
|
|
List<byte> cmd = new List<byte>();
|
|
|
|
/*
|
|
* CMD: READ HARDWARE REVISION
|
|
*
|
|
* [0] CMD_READ
|
|
* [1] READ_HW_REV
|
|
*/
|
|
|
|
cmd.Add(CMD_READ);
|
|
cmd.Add(READ_HW_REV);
|
|
|
|
Lower.Send(cmd);
|
|
|
|
List<byte> rsp = Lower.Read(AP_TIMEOUT);
|
|
|
|
/*
|
|
* RSP: READ HARDWARE REVISION
|
|
*
|
|
* [0] RSP_READ
|
|
* [1] READ_HW_REV
|
|
* [2] hw rev major version
|
|
* [3] hw rev minor version
|
|
*/
|
|
|
|
if (rsp.Count == 4)
|
|
{
|
|
if (rsp[0] == RSP_READ)
|
|
{
|
|
if (rsp[1] == READ_HW_REV)
|
|
{
|
|
byte[] ver = new byte[2];
|
|
ver[0] = rsp[2];
|
|
ver[1] = rsp[3];
|
|
return ver;
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid read opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response length");
|
|
}
|
|
}
|
|
|
|
public byte[] ReadSerialNumber()
|
|
{
|
|
List<byte> cmd = new List<byte>();
|
|
|
|
/*
|
|
* CMD: READ SERIAL NUMBER
|
|
*
|
|
* [0] CMD_READ
|
|
* [1] READ_SER_NUM
|
|
*/
|
|
|
|
cmd.Add(CMD_READ);
|
|
cmd.Add(READ_SER_NUM);
|
|
|
|
Lower.Send(cmd);
|
|
|
|
List<byte> rsp = Lower.Read(AP_TIMEOUT);
|
|
|
|
/*
|
|
* RSP: READ SERIAL NUMBER
|
|
*
|
|
* [0] RSP_READ
|
|
* [1] READ_SER_NUM
|
|
* [2] serial number length
|
|
* [3 to 3 + serial number length] serial number if serial number length > 0
|
|
*/
|
|
|
|
if (rsp.Count >= 3)
|
|
{
|
|
if (rsp[0] == RSP_READ)
|
|
{
|
|
if (rsp[1] == READ_SER_NUM)
|
|
{
|
|
if (rsp[2] == 0) // no serial number
|
|
{
|
|
return new byte[0];
|
|
}
|
|
else if (rsp[2] == (rsp.Count - 3))
|
|
{
|
|
int len = rsp[2];
|
|
byte[] num = new byte[len];
|
|
Array.Copy(rsp.ToArray(), 3, num, 0, len);
|
|
|
|
// TODO validate ascii characters to only accept 0-9, A-Z
|
|
|
|
return num;
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("message length field and message length mismatch");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid read opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response length");
|
|
}
|
|
}
|
|
|
|
public void WriteInfo(byte mdlId, byte hwRevMaj, byte hwRevMin)
|
|
{
|
|
List<byte> cmd = new List<byte>();
|
|
|
|
/*
|
|
* CMD: WRITE INFO
|
|
*
|
|
* [0] CMD_WRITE_INFO
|
|
* [1] WRITE_MDL_REV
|
|
* [2] model id
|
|
* [3] hardware revision major version
|
|
* [4] hardware revision minor version
|
|
*/
|
|
|
|
cmd.Add(CMD_WRITE_INFO);
|
|
cmd.Add(WRITE_MDL_REV);
|
|
cmd.Add(mdlId);
|
|
cmd.Add(hwRevMaj);
|
|
cmd.Add(hwRevMin);
|
|
|
|
Lower.Send(cmd);
|
|
|
|
List<byte> rsp = Lower.Read(AP_TIMEOUT);
|
|
|
|
/*
|
|
* RSP: WRITE INFO
|
|
*
|
|
* [0] RSP_WRITE_INFO
|
|
*/
|
|
|
|
if (rsp.Count == 1)
|
|
{
|
|
if (rsp[0] != RSP_WRITE_INFO)
|
|
{
|
|
throw new Exception("invalid response opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response length");
|
|
}
|
|
}
|
|
|
|
public void EnterBslMode()
|
|
{
|
|
List<byte> cmd = new List<byte>();
|
|
|
|
/*
|
|
* CMD: ENTER BSL MODE
|
|
*
|
|
* [0] CMD_ENTER_BSL_MODE
|
|
*/
|
|
|
|
cmd.Add(CMD_ENTER_BSL_MODE);
|
|
|
|
Lower.Send(cmd);
|
|
|
|
List<byte> rsp = Lower.Read(AP_TIMEOUT);
|
|
|
|
/*
|
|
* RSP: ENTER BSL MODE
|
|
*
|
|
* [0] RSP_ENTER_BSL_MODE
|
|
*/
|
|
|
|
if (rsp.Count == 1)
|
|
{
|
|
if (rsp[0] != RSP_ENTER_BSL_MODE)
|
|
{
|
|
throw new Exception("invalid response opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response length");
|
|
}
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
List<byte> cmd = new List<byte>();
|
|
|
|
/*
|
|
* CMD: RESET
|
|
*
|
|
* [0] CMD_RESET
|
|
*/
|
|
|
|
cmd.Add(CMD_RESET);
|
|
|
|
Lower.Send(cmd);
|
|
|
|
List<byte> rsp = Lower.Read(AP_TIMEOUT);
|
|
|
|
/*
|
|
* RSP: RESET
|
|
*
|
|
* [0] RSP_RESET
|
|
*/
|
|
|
|
if (rsp.Count == 1)
|
|
{
|
|
if (rsp[0] != RSP_RESET)
|
|
{
|
|
throw new Exception("invalid response opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response length");
|
|
}
|
|
}
|
|
|
|
public byte SelfTest()
|
|
{
|
|
List<byte> cmd = new List<byte>();
|
|
|
|
/*
|
|
* CMD: SELF TEST
|
|
*
|
|
* [0] CMD_SELF_TEST
|
|
*/
|
|
|
|
cmd.Add(CMD_SELF_TEST);
|
|
|
|
Lower.Send(cmd);
|
|
|
|
List<byte> rsp = Lower.Read(AP_TIMEOUT);
|
|
|
|
/*
|
|
* RSP: SELF TEST
|
|
*
|
|
* [0] RSP_SELF_TEST
|
|
* [1] self test result
|
|
*/
|
|
|
|
if (rsp.Count == 2)
|
|
{
|
|
if (rsp[0] == RSP_SELF_TEST)
|
|
{
|
|
return rsp[1];
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response length");
|
|
}
|
|
}
|
|
|
|
public void SendKeySignature()
|
|
{
|
|
List<byte> cmd = new List<byte>();
|
|
|
|
/*
|
|
* CMD: SEND KEY SIGNATURE
|
|
*
|
|
* [0] CMD_SEND_KEY_SIG
|
|
* [1] reserved (set to 0x00)
|
|
*/
|
|
|
|
cmd.Add(CMD_SEND_KEY_SIG);
|
|
cmd.Add(0x00);
|
|
|
|
Lower.Send(cmd);
|
|
|
|
List<byte> rsp = Lower.Read(AP_TIMEOUT);
|
|
|
|
/*
|
|
* RSP: SEND KEY SIGNATURE
|
|
*
|
|
* [0] RSP_SEND_KEY_SIG
|
|
*/
|
|
|
|
if (rsp.Count == 1)
|
|
{
|
|
if (rsp[0] != RSP_SEND_KEY_SIG)
|
|
{
|
|
throw new Exception("invalid response opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response length");
|
|
}
|
|
}
|
|
|
|
public void SendByte(byte data)
|
|
{
|
|
List<byte> cmd = new List<byte>();
|
|
|
|
/*
|
|
* CMD: SEND BYTE
|
|
*
|
|
* [0] CMD_SEND_BYTE
|
|
* [1] reserved (set to 0x00)
|
|
* [2] byte to send
|
|
*/
|
|
|
|
cmd.Add(CMD_SEND_BYTE);
|
|
cmd.Add(0x00);
|
|
cmd.Add(data);
|
|
|
|
Lower.Send(cmd);
|
|
|
|
List<byte> rsp = Lower.Read(AP_TIMEOUT);
|
|
|
|
/*
|
|
* RSP: SEND BYTE
|
|
*
|
|
* [0] RSP_SEND_BYTE
|
|
*/
|
|
|
|
if (rsp.Count == 1)
|
|
{
|
|
if (rsp[0] != RSP_SEND_BYTE)
|
|
{
|
|
throw new Exception("invalid response opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid response length");
|
|
}
|
|
}
|
|
|
|
public void SendData(List<byte> data)
|
|
{
|
|
foreach (byte b in data)
|
|
{
|
|
SendByte(b);
|
|
}
|
|
}
|
|
|
|
public byte GetByte(int timeout)
|
|
{
|
|
List<byte> rsp = Lower.Read(timeout);
|
|
|
|
/*
|
|
* BCST: RECEIVE BYTE
|
|
*
|
|
* [0] BCST_RECEIVE_BYTE
|
|
* [1] reserved (set to 0x00)
|
|
* [2] byte received
|
|
*/
|
|
|
|
if (rsp.Count == 3)
|
|
{
|
|
if (rsp[0] == BCST_RECEIVE_BYTE)
|
|
{
|
|
return rsp[2];
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid broadcast opcode");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("invalid broadcast length");
|
|
}
|
|
}
|
|
|
|
public void Cancel()
|
|
{
|
|
Lower.Cancel();
|
|
}
|
|
}
|
|
}
|