KFDtool/sw/control/KFDtool.P25/ThreeWire/ThreeWireProtocol.cs

237 lines
7.9 KiB
C#
Raw Normal View History

2019-07-29 15:24:10 -06:00
using KFDtool.Adapter.Protocol.Adapter;
2019-08-25 17:08:08 -06:00
using KFDtool.Shared;
2019-07-29 15:24:10 -06:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace KFDtool.P25.ThreeWire
{
public class ThreeWireProtocol
{
2019-08-25 17:08:08 -06:00
private static NLog.Logger Log = NLog.LogManager.GetCurrentClassLogger();
2019-07-29 15:24:10 -06:00
private const int TWI_TIMEOUT = 5000; // 5 second
private const byte READY_REQ_OPCODE = 0xC0;
private const byte READY_GENERAL_MODE_OPCODE = 0xD0;
private const byte TRANSFER_DONE_OPCODE = 0xC1;
private const byte KMM_OPCODE = 0xC2;
private const byte DISCONNECT_ACK_OPCODE = 0x90;
private const byte DISCONNECT_OPCODE = 0x92;
private AdapterProtocol Protocol;
public ThreeWireProtocol(AdapterProtocol ap)
{
Protocol = ap;
}
public void SendKeySignature()
{
2019-08-25 17:08:08 -06:00
Log.Debug("kfd: key signature");
2019-07-29 15:24:10 -06:00
Protocol.SendKeySignature();
}
public void InitSession()
{
// send ready req opcode
List<byte> cmd = new List<byte>();
cmd.Add(READY_REQ_OPCODE);
2019-08-25 17:08:08 -06:00
Log.Debug("kfd: ready req");
Log.Debug("kfd -> mr: {0}", Utility.DataFormat(cmd));
2019-07-29 15:24:10 -06:00
Protocol.SendData(cmd);
// receive ready general mode opcode
2019-08-25 17:08:08 -06:00
Log.Debug("mr: ready general mode");
2019-07-29 15:24:10 -06:00
byte rsp = Protocol.GetByte(TWI_TIMEOUT);
2019-08-25 17:08:08 -06:00
Log.Debug("kfd -> mr: {0}", Utility.DataFormat(rsp));
2019-07-29 15:24:10 -06:00
if (rsp != READY_GENERAL_MODE_OPCODE)
{
throw new Exception("mr: unexpected opcode");
}
}
private List<byte> CreateKmmFrame(List<byte> kmm)
{
// create body
List<byte> body = new List<byte>();
body.Add(0x00); // control
body.Add(0xFF); // destination RSI high byte
body.Add(0xFF); // destination RSI mid byte
body.Add(0xFF); // destination RSI low byte
body.AddRange(kmm); // kmm
// calculate crc
byte[] crc = CRC16.CalculateCrc(body.ToArray());
// create frame
List<byte> frame = new List<byte>();
int length = body.Count + 2; // control + dest rsi + kmm + crc
frame.Add(KMM_OPCODE); // kmm opcode
frame.Add((byte)((length >> 8) & 0xFF)); // length high byte
frame.Add((byte)(length & 0xFF)); // length low byte
frame.AddRange(body); // kmm body
frame.Add(crc[0]); // crc high byte
frame.Add(crc[1]); // crc low byte
return frame;
}
private List<byte> ParseKmmFrame()
{
byte temp;
// receive kmm opcode
2019-08-25 17:08:08 -06:00
Log.Debug("mr: kmm opcode");
2019-07-29 15:24:10 -06:00
temp = Protocol.GetByte(TWI_TIMEOUT);
2019-08-25 17:08:08 -06:00
Log.Debug("mr -> kfd: {0}", Utility.DataFormat(temp));
2019-07-29 15:24:10 -06:00
if (temp != KMM_OPCODE)
{
throw new Exception(string.Format("mr: unexpected opcode, expected: 0x{0:X2}, got: 0x{1:X2}", KMM_OPCODE, temp));
}
int length = 0;
// receive length high byte
2019-08-25 17:08:08 -06:00
Log.Debug("mr: length high byte");
2019-07-29 15:24:10 -06:00
temp = Protocol.GetByte(TWI_TIMEOUT);
2019-08-25 17:08:08 -06:00
Log.Debug("mr -> kfd: 0x{0:X2}", temp);
2019-07-29 15:24:10 -06:00
length |= (temp & 0xFF) << 8;
// receive length low byte
2019-08-25 17:08:08 -06:00
Log.Debug("mr: length low byte");
2019-07-29 15:24:10 -06:00
temp = Protocol.GetByte(TWI_TIMEOUT);
2019-08-25 17:08:08 -06:00
Log.Debug("mr -> kfd: {0}", Utility.DataFormat(temp));
2019-07-29 15:24:10 -06:00
length |= temp & 0xFF;
2019-08-25 17:08:08 -06:00
Log.Debug("length: {0}", length);
2019-07-29 15:24:10 -06:00
List<byte> toCrc = new List<byte>();
// receive control
2019-08-25 17:08:08 -06:00
Log.Debug("mr: control");
2019-07-29 15:24:10 -06:00
temp = Protocol.GetByte(TWI_TIMEOUT);
2019-08-25 17:08:08 -06:00
Log.Debug("mr -> kfd: {0}", Utility.DataFormat(temp));
2019-07-29 15:24:10 -06:00
toCrc.Add(temp);
// receive dest rsi high byte
2019-08-25 17:08:08 -06:00
Log.Debug("mr: dest rsi high byte");
2019-07-29 15:24:10 -06:00
temp = Protocol.GetByte(TWI_TIMEOUT);
2019-08-25 17:08:08 -06:00
Log.Debug("mr -> kfd: {0}", Utility.DataFormat(temp));
2019-07-29 15:24:10 -06:00
toCrc.Add(temp);
// receive dest rsi mid byte
2019-08-25 17:08:08 -06:00
Log.Debug("mr: dest rsi mid byte");
2019-07-29 15:24:10 -06:00
temp = Protocol.GetByte(TWI_TIMEOUT);
2019-08-25 17:08:08 -06:00
Log.Debug("mr -> kfd: {0}", Utility.DataFormat(temp));
2019-07-29 15:24:10 -06:00
toCrc.Add(temp);
// receive dest rsi low byte
2019-08-25 17:08:08 -06:00
Log.Debug("mr: dest rsi low byte");
2019-07-29 15:24:10 -06:00
temp = Protocol.GetByte(TWI_TIMEOUT);
2019-08-25 17:08:08 -06:00
Log.Debug("mr -> kfd: {0}", Utility.DataFormat(temp));
2019-07-29 15:24:10 -06:00
toCrc.Add(temp);
int bodyLength = length - 6;
List<byte> kmm = new List<byte>();
for (int i = 0; i < bodyLength; i++)
{
2019-08-25 17:08:08 -06:00
Log.Debug("mr: kmm byte {0} of {1}", i + 1, bodyLength);
2019-07-29 15:24:10 -06:00
temp = Protocol.GetByte(TWI_TIMEOUT);
2019-08-25 17:08:08 -06:00
Log.Debug("mr -> kfd: {0}", Utility.DataFormat(temp));
2019-07-29 15:24:10 -06:00
kmm.Add(temp);
}
toCrc.AddRange(kmm);
2019-08-25 17:08:08 -06:00
// calculate crc
byte[] expectedCrc = CRC16.CalculateCrc(toCrc.ToArray());
Log.Debug("expected crc - high: 0x{0:X2}, low: 0x{1:X2}", expectedCrc[0], expectedCrc[1]);
2019-07-29 15:24:10 -06:00
byte[] crc = new byte[2];
// receive crc high byte
2019-08-25 17:08:08 -06:00
Log.Debug("mr: crc high byte");
2019-07-29 15:24:10 -06:00
crc[0] = Protocol.GetByte(TWI_TIMEOUT);
2019-08-25 17:08:08 -06:00
Log.Debug("mr -> kfd: {0}", Utility.DataFormat(crc[0]));
2019-07-29 15:24:10 -06:00
// receive crc low byte
2019-08-25 17:08:08 -06:00
Log.Debug("mr: crc low byte");
2019-07-29 15:24:10 -06:00
crc[1] = Protocol.GetByte(TWI_TIMEOUT);
2019-08-25 17:08:08 -06:00
Log.Debug("mr -> kfd: {0}", Utility.DataFormat(crc[1]));
2019-07-29 15:24:10 -06:00
if (expectedCrc[0] != crc[0])
{
throw new Exception(string.Format("mr: crc high byte mismatch, expected: 0x{0:X2}, got: 0x{1:X2}", expectedCrc[0], crc[0]));
}
if (expectedCrc[1] != crc[1])
{
throw new Exception(string.Format("mr: crc low byte mismatch, expected: 0x{0:X2}, got: 0x{1:X2}", expectedCrc[1], crc[1]));
}
return kmm;
}
public void EndSession()
{
// send transfer done opcode
List<byte> cmd1 = new List<byte>();
cmd1.Add(TRANSFER_DONE_OPCODE);
2019-08-25 17:08:08 -06:00
Log.Debug("kfd: transfer done");
Log.Debug("kfd -> mr: {0}", Utility.DataFormat(cmd1));
2019-07-29 15:24:10 -06:00
Protocol.SendData(cmd1);
// receive transfer done opcode
2019-08-25 17:08:08 -06:00
Log.Debug("mr: transfer done");
2019-07-29 15:24:10 -06:00
byte rsp1 = Protocol.GetByte(TWI_TIMEOUT);
2019-08-25 17:08:08 -06:00
Log.Debug("mr -> kfd: {0}", Utility.DataFormat(rsp1));
2019-07-29 15:24:10 -06:00
if (rsp1 != TRANSFER_DONE_OPCODE)
{
throw new Exception("mr: unexpected opcode");
}
// send disconnect opcode
List<byte> cmd2 = new List<byte>();
cmd2.Add(DISCONNECT_OPCODE);
2019-08-25 17:08:08 -06:00
Log.Debug("kfd: disconnect");
Log.Debug("kfd -> mr: {0}", Utility.DataFormat(cmd2));
2019-07-29 15:24:10 -06:00
Protocol.SendData(cmd2);
// receive disconnect ack opcode
2019-08-25 17:08:08 -06:00
Log.Debug("mr: disconnect ack");
2019-07-29 15:24:10 -06:00
byte rsp2 = Protocol.GetByte(TWI_TIMEOUT);
2019-08-25 17:08:08 -06:00
Log.Debug("mr -> kfd: {0}", Utility.DataFormat(rsp2));
2019-07-29 15:24:10 -06:00
if (rsp2 != DISCONNECT_ACK_OPCODE)
{
throw new Exception("mr: unexpected opcode");
}
}
public byte[] PerformKmmTransfer(byte[] inKmm)
{
2019-08-25 17:08:08 -06:00
List<byte> txFrame = CreateKmmFrame(inKmm.ToList());
Log.Debug("kfd -> mr: {0}", Utility.DataFormat(txFrame));
Protocol.SendData(txFrame);
2019-07-29 15:24:10 -06:00
2019-08-25 17:08:08 -06:00
List<byte> rxFrame = ParseKmmFrame();
2019-07-29 15:24:10 -06:00
2019-08-25 17:08:08 -06:00
return rxFrame.ToArray();
2019-07-29 15:24:10 -06:00
}
}
}