KFDtool/sw/control/KFDtool.Adapter/Protocol/Adapter/AdapterProtocol.cs

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();
}
}
}