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 cmd = new List(); /* * CMD: READ AP VERSION * * [0] CMD_READ * [1] READ_AP_VER */ cmd.Add(CMD_READ); cmd.Add(READ_AP_VER); Lower.Send(cmd); List 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 cmd = new List(); /* * CMD: READ FW VERSION * * [0] CMD_READ * [1] READ_FW_VER */ cmd.Add(CMD_READ); cmd.Add(READ_FW_VER); Lower.Send(cmd); List 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 cmd = new List(); /* * CMD: READ UNIQUE ID * * [0] CMD_READ * [1] READ_UNIQUE_ID */ cmd.Add(CMD_READ); cmd.Add(READ_UNIQUE_ID); Lower.Send(cmd); List 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 cmd = new List(); /* * CMD: READ MODEL ID * * [0] CMD_READ * [1] READ_MODEL_ID */ cmd.Add(CMD_READ); cmd.Add(READ_MODEL_ID); Lower.Send(cmd); List 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 cmd = new List(); /* * CMD: READ HARDWARE REVISION * * [0] CMD_READ * [1] READ_HW_REV */ cmd.Add(CMD_READ); cmd.Add(READ_HW_REV); Lower.Send(cmd); List 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 cmd = new List(); /* * CMD: READ SERIAL NUMBER * * [0] CMD_READ * [1] READ_SER_NUM */ cmd.Add(CMD_READ); cmd.Add(READ_SER_NUM); Lower.Send(cmd); List 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 cmd = new List(); /* * 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 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 cmd = new List(); /* * CMD: ENTER BSL MODE * * [0] CMD_ENTER_BSL_MODE */ cmd.Add(CMD_ENTER_BSL_MODE); Lower.Send(cmd); List 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 cmd = new List(); /* * CMD: RESET * * [0] CMD_RESET */ cmd.Add(CMD_RESET); Lower.Send(cmd); List 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 cmd = new List(); /* * CMD: SELF TEST * * [0] CMD_SELF_TEST */ cmd.Add(CMD_SELF_TEST); Lower.Send(cmd); List 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 cmd = new List(); /* * 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 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 cmd = new List(); /* * 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 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 data) { foreach (byte b in data) { SendByte(b); } } public byte GetByte(int timeout) { List 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(); } } }