tbf/NfcHandler/MCI_Protocol.cs
2024-07-25 12:14:58 +02:00

772 lines
31 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;
using System.IO.Ports;
using System.Timers;
using System.Runtime.CompilerServices;
//*****************************************************************************
// Copyright 2020 Sensus GmbH Ludwigshafen. All rights reserved.
// Author: Venkat, Rajeshwar
//*****************************************************************************
namespace Sensus.iPerl.NfcHandler
{
public class MCI_Protocol
{
private bool MCI_CycleResponseMsgTimeoutFlag = false;
private readonly byte STX = (byte) 0x02;
private readonly byte ETX = (byte) 0x03;
private readonly byte RX_ACK_RESPONSE_MSG_ID = (byte) 0xC9;
private readonly ushort[] MciPasswords = { 0x0000, 0x55AA, 0x1234, 0x97D1 };
public event DelNfc_MCI_MessageHandler MessageEvent;
public enum StructName
{
Calibration,
Configuration,
Status,
Power,
LCD,
unused1,
unused2,
Diagnostics,
ProductionInfo,
AckResponse,
RadioParams,
RadioInfo,
Command,
EEPROM_Metro,
ST25_Chip_Registers,
IndexReset,
NfcSecurity
}
public static readonly Dictionary<byte, string> StructName_id_to_str = new Dictionary<byte, string>
{
{0, "Calibration"},
{1, "Configuration"},
{2, "Status"},
{3, "Power"},
{4, "LCD"},
{5, "unused1"},
{6, "unused2"},
{7, "Diagnostics"},
{8, "ProductionInfo"},
{9, "AckResponse"},
{10, "RadioParams"},
{11, "RadioInfo"},
{12, "Command"},
{13, "EEPROM_Metro"},
{14, "ST25_Chip_Registers"},
{15, "IndexReset"},
{16, "NfcSecurity"}
};
private string StructToStr(StructName StName)
{
return StructName_id_to_str[Convert.ToByte(StName)];
}
private bool IsValidStruct(StructName StName)
{
return MCI_Protocol.StructName_id_to_str.ContainsKey(Convert.ToByte(StName));
}
public enum MCI_ErrorCodes
{
// these first 0..8 error codes are defined both in
// radio and metro. They can return these codes.
// higher codes will not be returned
Success_No_error = 0,
MCI_Error_MeterAns_Timeout = 1,
MCI_Error_MeterAns_Wrong_CRC = 2,
MCI_Error_MeterAns_Wrong_password = 3,
MCI_Error_MeterAns_Data_not_available = 4,
MCI_Error_MeterAns_Invalid_access = 5,
MCI_Error_MeterAns_Command_not_supported = 6,
MCI_Error_MeterAns_Command_not_executed = 7,
MCI_Error_MeterAns_Unidentified = 8,
// in case higher errors will be defined for the IMI in future
// we keep some distance with the errorcodes...
// host error codes from MCI_Read/Write start from 20:
MCI_Error_Host_Bad_MCI_ID = 20,
MCI_Error_Host_WriteReq_denied = 21,
MCI_Error_Host_WriteReq_bad_device_ans = 22,
MCI_Error_Host_ReadReq_denied = 23,
MCI_Error_Host_ReadReq_bad_device_ans = 24,
MCI_Error_Host_Bad_Payload_Len = 25,
MCI_Error_Host_MeterCRCDoesNotMatch = 26,
MCI_Error_Host_ReadReqBadResponseStructure = 27,
MCI_Error_Host_InvalidStructureID_CannotSendMsg = 28,
MCI_Error_Host_CommandNotInCmdCodeList = 29,
// host error codes from method MCI_TxRequest_RxResponse start from 40
MCI_Error_Host_MB_CTRL_Reg_Read1 = 40,
MCI_Error_Host_MB_disabled1 = 41,
MCI_Error_Host_MB_LEN_Reg_read1 = 42,
MCI_Error_Host_MB_msg_read1 = 43,
MCI_Error_Host_req_not_sent = 44,
MCI_Error_Host_req_not_read_by_iperl = 45,
MCI_Error_Host_MB_CTRL_Reg_Read2 = 46,
MCI_Error_Host_MB_disabled2 = 47,
MCI_Error_Host_MB_LEN_Reg_read2 = 48,
MCI_Error_Host_MB_msg_read2 = 49,
MCI_Error_Host_Timeout = 50,
MCI_Error_Host_msg_write = 51
}
public static string GetMCIErrorMessage(byte ErrorCode)
{
// this is called reflection. The variable names will be
// returned. No need of copys of variable names to string values.
return ((MCI_ErrorCodes) ErrorCode).ToString();
}
public static readonly Dictionary<byte, string> MCI_CmdCodes = new Dictionary<byte, string>
{
{0x00 , "Command: No Operation" },
{0x01 , "Command: Clear Alarms" },
{0x04 , "Command: Clear Diag" },
{0x05 , "Command: Clear Peak flowrate" },
{0x06 , "Command: Enter Active mode" },
{0x07 , "Command: Enter Test mode" },
{0x09 , "Command: Reset Accumulated Volume" },
{0x0A , "Command: Factory Default" },
{0x0B , "Command: Seal" },
{0x0C , "Command: Send radio address to radio FW" },
{0x0D , "Command: Adjust Field" },
{0x0E , "Command: LCD All segments ON" },
{0x0F , "Command: LCD All segments OFF" },
{0x10 , "Command: LCD Even segments ON" },
{0x11 , "Command: LCD Odd segments ON" },
{0x12 , "Command: LNA ON" },
{0x13 , "Command: LNA OFF" },
{0x14 , "Command: EPD ON" },
{0x15 , "Command: EPD OFF" },
{0x16 , "Command: Enter LPM4" },
{0x17 , "Command: Select drive coil connectivity" },
{0x1A , "Command: Enter VRTM" },
{0x1B , "Custom Package Mode ON" },
{0x1C , "Custom Package Mode OFF" },
{0x20 , "Command: Deinstall" },
{0x21 , "Command: Audit Mode" },
{0x22 , "Command: Diagnostic Refresh" },
{0x23 , "Command: NFC Security Reset Access Level" }
};
Dictionary<int, byte[]> MCI_Write_Info = new Dictionary<int, byte[]>();
Dictionary<int, byte[]> MCI_Read_Info = new Dictionary<int, byte[]>();
Dictionary<int, byte[]> MCI_ReadResponse_Info = new Dictionary<int, byte[]>();
private byte MB_Ctrl_Reg_Value;
private byte MB_LEN_Dyn_Register;
private ST25DV_Device _ST25DV_Device;
Tools.Crc16Ccitt Crc = new Tools.Crc16Ccitt(Tools.InitialCrcValue.NonZero1);
private System.Timers.Timer _ReqResCycleTimeoutTimer = new System.Timers.Timer();
public MCI_Protocol(ST25DV_Device ST25DVDevice)
{
_ST25DV_Device = ST25DVDevice;
Init_MCI_Info_MsgId_Password();
}
private void Init_MCI_Info_MsgId_Password()
{
//Write request
byte[] value1 = { 0x40, 0xD1, 0x97 };
MCI_Write_Info.Add(0, value1);//Calibration
byte [] value2 = { 0x41, 0xD1, 0x97 };
MCI_Write_Info.Add(1, value2); //Configuration
byte[] value3 = { 0x42, 0x34, 0x12 };
MCI_Write_Info.Add(2, value3); //Status
byte[] value4 = { 0x43, 0x34, 0x12 };
MCI_Write_Info.Add(3, value4);//Power
byte[] value5 = { 0x44, 0xAA, 0x55 };
MCI_Write_Info.Add(4, value5); //LCD
byte[] value6 = { 0x48, 0xD1, 0x97 };
MCI_Write_Info.Add(8, value6);//ProductionInfo
byte[] value7 = { 0x4E, 0xD1, 0x97 };
MCI_Write_Info.Add(10, value7);//RadioParams
byte[] value8 = { 0x4E, 0xD1, 0x97 };
MCI_Write_Info.Add(11, value8);//RadioInfo
byte[] value9 = { 0x4A, 0xD1, 0x97 };
MCI_Write_Info.Add(12, value9);//Command
byte[] valueIndexResetWrite = { 0x52, 0xD1, 0x97 };
MCI_Write_Info.Add(15, valueIndexResetWrite);//Index reset
byte[] valueNfcSecuritySignedWrite = { 0x54, 0xD1, 0x97 };
MCI_Write_Info.Add(16, valueNfcSecuritySignedWrite);//NFC Security signed message - while writing
//Read request
byte[] value10 = { 0x00, 0xD1, 0x97 };
MCI_Read_Info.Add(0, value10);//Calibration
byte[] value11 = { 0x01, 0xD1, 0x97 };
MCI_Read_Info.Add(1, value11); //Configuration
byte[] value12 = { 0x02, 0x34, 0x12 };
MCI_Read_Info.Add(2, value12); //Status
byte[] value13 = { 0x03, 0x34, 0x12 };
MCI_Read_Info.Add(3, value13);//Power
byte[] value14 = { 0x04, 0xAA, 0x55 };
MCI_Read_Info.Add(4, value14); //LCD
byte[] value15 = { 0x07, 0xAA, 0x55 };
MCI_Read_Info.Add(7, value15); //Diag
byte[] value16 = { 0x08, 0xD1, 0x97 };
MCI_Read_Info.Add(8, value16);//ProductionInfo
byte[] value17 = { 0x0E, 0xD1, 0x97 };
MCI_Read_Info.Add(10, value17);//RadioParams
byte[] value18 = { 0x0E, 0xD1, 0x97 };
MCI_Read_Info.Add(11, value18);//RadioInfo
byte[] valueIndexResetRead = { 0x12, 0xD1, 0x97 };
MCI_Read_Info.Add(15, valueIndexResetRead);//Index reset
byte[] valueNfcSecurityUnsignedRead = { 0x14, 0xD1, 0x97 };
MCI_Read_Info.Add(16, valueNfcSecurityUnsignedRead);//NFC Security non-signed message - while reading
//Read response
byte[] value19 = { 0xC0, 0xD1, 0x97 };
MCI_ReadResponse_Info.Add(0, value19);//Calibration
byte[] value20 = { 0xC1, 0xD1, 0x97 };
MCI_ReadResponse_Info.Add(1, value20); //Configuration
byte[] value21 = { 0xC2, 0x34, 0x12 };
MCI_ReadResponse_Info.Add(2, value21); //Status
byte[] value22 = { 0xC3, 0x34, 0x12 };
MCI_ReadResponse_Info.Add(3, value22);//Power
byte[] value23 = { 0xC4, 0xAA, 0x55 };
MCI_ReadResponse_Info.Add(4, value23); //LCD
byte[] value24 = { 0xC7, 0xAA, 0x55 };
MCI_ReadResponse_Info.Add(7, value24); //Diag
byte[] value25 = { 0xC8, 0xD1, 0x97 };
MCI_ReadResponse_Info.Add(8, value25);//ProductionInfo
byte[] value26 = { 0xC9, 0x00, 0x00 };
MCI_ReadResponse_Info.Add(9, value26);//Ack response
byte[] value27 = { 0xCE, 0xD1, 0x97 };
MCI_ReadResponse_Info.Add(10, value27);//RadioParams
byte[] value28 = { 0xCE, 0xD1, 0x97 };
MCI_ReadResponse_Info.Add(11, value28);//RadioInfo
byte[] valueIndexResetReadResponse = { 0xD2, 0xD1, 0x97 };
MCI_ReadResponse_Info.Add(15, valueIndexResetReadResponse);//Index reset
byte[] valueNfcSecurityUnsignedReadResponse = { 0xD4, 0xD1, 0x97 };
MCI_ReadResponse_Info.Add(16, valueNfcSecurityUnsignedReadResponse);//NFC Security non-signed message response - while reading
}
public bool MCI_Write(StructName StName, ushort offset, byte payloadlength, byte[] inBuffer, int timeoutMs,
out byte errorCode)
{
List<byte> RequestMessage = new List<byte>();
byte[] ResponseMessage = null;
byte[] crcValue = new byte[2];
errorCode = (byte) MCI_ErrorCodes.Success_No_error;
if (payloadlength != inBuffer.Length)
{
// Insufficient Payload length
errorCode = (byte)MCI_ErrorCodes.MCI_Error_Host_Bad_Payload_Len;
return false;
}
if (StName == StructName.Command)
{
if (! MCI_Protocol.MCI_CmdCodes.ContainsKey(inBuffer[0]))
{
// Command not supported
errorCode = (byte)MCI_ErrorCodes.MCI_Error_Host_CommandNotInCmdCodeList;
return false;
}
}
else // not a command => should be struct
{
if (!IsValidStruct(StName))
{
errorCode = (byte)MCI_ErrorCodes.MCI_Error_Host_InvalidStructureID_CannotSendMsg;
return false;
}
}
byte[] MsgId_Password = MCI_Write_Info[(int)StName];
RequestMessage.Add(STX);
RequestMessage.Add(Convert.ToByte(6 + payloadlength));
RequestMessage.Add(MsgId_Password[0]);
RequestMessage.Add((byte)(offset & 0x00FF));
RequestMessage.Add((byte)((offset & 0xFF00) >> 8));
RequestMessage.Add(payloadlength);
for (int i = 0; i < payloadlength; i++) // copy Buffer -> Request Payload
{
RequestMessage.Add(inBuffer[i]);
}
RequestMessage.Add(MsgId_Password[1]);
RequestMessage.Add(MsgId_Password[2]);
// calc CRC and add to request
crcValue = Crc.calcCRCfromMessage(RequestMessage.ToArray());
RequestMessage.Add(crcValue[0]);
RequestMessage.Add(crcValue[1]);
RequestMessage.Add(ETX);
OnMessageEvent("Write " + StructToStr(StName) + "Request: " + Tools.BytesToHex(RequestMessage.ToArray()));
errorCode = MCI_TxRequest_RxResponse(RequestMessage.ToArray(), out ResponseMessage, timeoutMs);
if (errorCode != (byte)MCI_ErrorCodes.Success_No_error)
{
return false;
}
//Response message received
byte[] RxCrcComputed = Crc.calcCRCfromMessage(ResponseMessage);
byte[] RxCrcMeter = new byte[2];
// CRC starts at length + STX(1) + lenbyte(1) = RespMsg[1] + 2.
Array.Copy(ResponseMessage, ResponseMessage[1] + 2, RxCrcMeter, 0, 2);
if (!Crc.crc_do_match(RxCrcMeter, RxCrcComputed))
{
OnMessageEvent(Crc.commentCRC(RxCrcMeter, RxCrcComputed));
errorCode = (byte) MCI_ErrorCodes.MCI_Error_Host_MeterCRCDoesNotMatch;
return false;
}
if ((ResponseMessage[0] == STX)
&& (ResponseMessage[1] == 0x07)
&& (ResponseMessage[2] == RX_ACK_RESPONSE_MSG_ID)
&& (ResponseMessage[11] == ETX))
{
errorCode = ResponseMessage[6]; // meter error. Must be between 0..8.
// Will be converted to errormessage string from the calling method.
if (errorCode != 0)
{
OnMessageEvent("Write " + StructToStr(StName) + " failed. Request Response: " + Tools.BytesToHex(ResponseMessage));
return false;
}
OnMessageEvent("Write : Success");
return true;
}
errorCode = (byte) MCI_ErrorCodes.MCI_Error_Host_WriteReq_bad_device_ans;
return false;
}
public bool MCI_Write_Read(StructName StName, ushort offset, byte payloadlength, byte[] inBuffer, out byte[] outBuffer, int timeoutMs,
out byte errorCode)
{
List<byte> RequestMessage = new List<byte>();
byte[] ResponseMessage = null;
byte[] crcValue = new byte[2];
byte RxMsgLength;
byte RxMsgId;
byte[] RxOffset = new byte[2];
byte RxPayloadlength;
byte[] RxCrcMeter = new byte[2];
outBuffer = null;
errorCode = (byte)MCI_ErrorCodes.Success_No_error;
if (payloadlength != inBuffer.Length)
{
// Insufficient Payload length
errorCode = (byte)MCI_ErrorCodes.MCI_Error_Host_Bad_Payload_Len;
return false;
}
if (StName == StructName.Command)
{
if (!MCI_Protocol.MCI_CmdCodes.ContainsKey(inBuffer[0]))
{
// Command not supported
errorCode = (byte)MCI_ErrorCodes.MCI_Error_Host_CommandNotInCmdCodeList;
return false;
}
}
else // not a command => should be struct
{
if (!IsValidStruct(StName))
{
errorCode = (byte)MCI_ErrorCodes.MCI_Error_Host_InvalidStructureID_CannotSendMsg;
return false;
}
}
byte[] MsgId_Password = MCI_Write_Info[(int)StName];
RequestMessage.Add(STX);
RequestMessage.Add(Convert.ToByte(6 + payloadlength));
RequestMessage.Add(MsgId_Password[0]);
RequestMessage.Add((byte)(offset & 0x00FF));
RequestMessage.Add((byte)((offset & 0xFF00) >> 8));
RequestMessage.Add(payloadlength);
for (int i = 0; i < payloadlength; i++) // copy Buffer -> Request Payload
{
RequestMessage.Add(inBuffer[i]);
}
RequestMessage.Add(MsgId_Password[1]);
RequestMessage.Add(MsgId_Password[2]);
// calc CRC and add to request
crcValue = Crc.calcCRCfromMessage(RequestMessage.ToArray());
RequestMessage.Add(crcValue[0]);
RequestMessage.Add(crcValue[1]);
RequestMessage.Add(ETX);
OnMessageEvent("Write " + StructToStr(StName) + "Request: " + Tools.BytesToHex(RequestMessage.ToArray()));
errorCode = MCI_TxRequest_RxResponse(RequestMessage.ToArray(), out ResponseMessage, timeoutMs);
if (errorCode != (byte)MCI_ErrorCodes.Success_No_error)
{
return false;
}
if ((ResponseMessage[0] == STX) && (ResponseMessage[11] == ETX)
&& (ResponseMessage[1] == 0x07)
&& (ResponseMessage[2] == RX_ACK_RESPONSE_MSG_ID))
{
//Ack message received, not served the read request
errorCode = ResponseMessage[6]; // forward error message from meter
OnMessageEvent("Read " + StructToStr(StName) + ": Failed with error "
+ Tools.ByteToHexString(errorCode));
return false;
}
//Response message received
RxMsgLength = ResponseMessage[1];
RxMsgId = ResponseMessage[2];
// RxOffset[0] = ResponseMessage[3];
// RxOffset[1] = ResponseMessage[4];
RxPayloadlength = ResponseMessage[5];
// RxPassword[0] = ResponseMessage[6 + RxPayloadlength];
// RxPassword[1] = ResponseMessage[7 + RxPayloadlength];
RxCrcMeter[0] = ResponseMessage[8 + RxPayloadlength];
RxCrcMeter[1] = ResponseMessage[9 + RxPayloadlength];
byte[] RxCrcComputed = Crc.calcCRCfromMessage(ResponseMessage);
// OnMessageEvent(Crc.commentCRC(RxCrcMeter, RxCrcComputed));
if (!Crc.crc_do_match(RxCrcMeter, RxCrcComputed))
{
errorCode = (byte)MCI_ErrorCodes.MCI_Error_Host_MeterCRCDoesNotMatch;
return false;
}
//TODO, verify received password matches with expected password or not?
if (!((ResponseMessage[0] == STX) && (ResponseMessage[10 + RxPayloadlength] == ETX)
&& ((ResponseMessage[2] & 0x3F) == (MsgId_Password[0] & 0x3F))))
{
errorCode = (byte)MCI_ErrorCodes.MCI_Error_Host_ReadReqBadResponseStructure;
return false;
}
outBuffer = new byte[RxPayloadlength];
for (int i = 0; i < RxPayloadlength; i++)
{
outBuffer[i] = (ResponseMessage[6 + i]);
}
if (IsValidStruct(StName))
{
OnMessageEvent("Read " + StructToStr(StName) + ": " + Tools.BytesToHex(outBuffer)
+ " Success");
}
else
{
OnMessageEvent("Read Failed! Unknown MCI ID: " + Convert.ToByte(StName));
errorCode = (byte)MCI_ErrorCodes.MCI_Error_Host_Bad_MCI_ID;
return false;
}
errorCode = (byte)0x00; //Success, No error
return true;
}
public bool MCI_Read(StructName StName, ushort offset, byte payloadlength, int timeoutMs,
out byte[] outBuffer, out byte errorCode)
{
List<byte> RequestMessage = new List<byte>();
byte[] ResponseMessage = null;
byte RxMsgLength;
byte RxMsgId;
byte [] RxOffset = new byte[2];
byte RxPayloadlength;
byte[] RxCrcMeter = new byte[2];
byte[] RxPassword = new byte[2];
byte[] MsgId_Password = MCI_Read_Info[(byte)StName];
byte[] crcValue;
outBuffer = null;
errorCode = (byte)0x00; //Success, No error
if (! IsValidStruct(StName))
{
errorCode = (byte)MCI_ErrorCodes.MCI_Error_Host_InvalidStructureID_CannotSendMsg;
OnMessageEvent("Read request:" + MCI_Protocol.GetMCIErrorMessage(errorCode));
return false;
}
RequestMessage.Add(STX);
RequestMessage.Add(0x06);
RequestMessage.Add(MsgId_Password[0]);
RequestMessage.Add((byte)(offset & 0x00FF));
RequestMessage.Add((byte)((offset & 0xFF00) >> 8));
RequestMessage.Add(payloadlength);
RequestMessage.Add(MsgId_Password[1]);
RequestMessage.Add(MsgId_Password[2]);
crcValue = Crc.calcCRCfromMessage(RequestMessage.ToArray());
RequestMessage.AddRange(crcValue);
RequestMessage.Add(ETX);
OnMessageEvent("Read Request: " + Tools.BytesToHex(RequestMessage.ToArray()));
errorCode = MCI_TxRequest_RxResponse(RequestMessage.ToArray(), out ResponseMessage, timeoutMs);
if (errorCode != (byte) MCI_ErrorCodes.Success_No_error)
{
return false;
}
if ((ResponseMessage[0] == STX) && (ResponseMessage[11] == ETX)
&& (ResponseMessage[1] == 0x07)
&& (ResponseMessage[2] == RX_ACK_RESPONSE_MSG_ID))
{
//Ack message received, not served the read request
errorCode = ResponseMessage[6]; // forward error message from meter
OnMessageEvent("Read " + StructToStr(StName) + ": Failed with error "
+ Tools.ByteToHexString(errorCode));
return false;
}
//Response message received
RxMsgLength = ResponseMessage[1];
RxMsgId = ResponseMessage[2];
// RxOffset[0] = ResponseMessage[3];
// RxOffset[1] = ResponseMessage[4];
RxPayloadlength = ResponseMessage[5];
// RxPassword[0] = ResponseMessage[6 + RxPayloadlength];
// RxPassword[1] = ResponseMessage[7 + RxPayloadlength];
RxCrcMeter[0] = ResponseMessage[8 + RxPayloadlength];
RxCrcMeter[1] = ResponseMessage[9 + RxPayloadlength];
byte[] RxCrcComputed = Crc.calcCRCfromMessage(ResponseMessage);
// OnMessageEvent(Crc.commentCRC(RxCrcMeter, RxCrcComputed));
if (!Crc.crc_do_match(RxCrcMeter, RxCrcComputed))
{
errorCode = (byte) MCI_ErrorCodes.MCI_Error_Host_MeterCRCDoesNotMatch;
return false;
}
//TODO, verify received password matches with expected password or not?
if (!((ResponseMessage[0] == STX) && (ResponseMessage[10 + RxPayloadlength] == ETX)
&& ((ResponseMessage[2] & 0x3F) == (MsgId_Password[0] & 0x3F))))
{
errorCode = (byte)MCI_ErrorCodes.MCI_Error_Host_ReadReqBadResponseStructure;
return false;
}
outBuffer = new byte[RxPayloadlength];
for (int i = 0; i < RxPayloadlength; i++)
{
outBuffer[i] = (ResponseMessage[6 + i]);
}
if (IsValidStruct(StName))
{
OnMessageEvent("Read " + StructToStr(StName) + ": " + Tools.BytesToHex(outBuffer)
+ " Success");
}
else
{
OnMessageEvent("Read Failed! Unknown MCI ID: " + Convert.ToByte(StName));
errorCode = (byte)MCI_ErrorCodes.MCI_Error_Host_Bad_MCI_ID;
return false;
}
errorCode = (byte)0x00; //Success, No error
return true;
}
private byte MCI_TxRequest_RxResponse(byte[] InBuffer, out byte[] OutBuffer, int timeout)
{
// return message is the errorcode, 0 means no error.
byte[] responseMsg = null;
OutBuffer = null;
MCI_CycleResponseMsgTimeoutFlag = false;
StartReqResCycleTimeoutTimer(timeout);
if (!_ST25DV_Device.ST25DV_ReadMailboxControlReg(out MB_Ctrl_Reg_Value))
{
MCI_CycleResponseMsgTimeoutFlag = false;
stopReqResCycleTimeoutTimer();
return (byte) MCI_ErrorCodes.MCI_Error_Host_MB_CTRL_Reg_Read1;
}
//Mailbox enable/disable check, proceed further only if enabled
if ((MB_Ctrl_Reg_Value & 0x01) == 0x00)
{
MCI_CycleResponseMsgTimeoutFlag = false;
stopReqResCycleTimeoutTimer();
OnMessageEvent(">> REMARK: Check if Metorlogy firmware-version is at least: 5.1.24 <<");
return (byte)MCI_ErrorCodes.MCI_Error_Host_MB_disabled1;
}
//Checking iPERL previous message is in mailbox or not, if present then read it and return failure
if ((MB_Ctrl_Reg_Value & 0x02) == 0x02)
{
byte returnError;
OnMessageEvent("NFC DLL Error: Previous message not read, reading now !");
if (!_ST25DV_Device.ST25DV_ReadMailboxMessageLength(out MB_LEN_Dyn_Register))
{
returnError = (byte)MCI_ErrorCodes.MCI_Error_Host_MB_LEN_Reg_read1;
}
else
{
OnMessageEvent("NFC DLL Error: Previous message length " + MB_LEN_Dyn_Register);
if (!_ST25DV_Device.ST25DV_ReadMessage(MB_LEN_Dyn_Register, out responseMsg))
{
returnError = (byte)MCI_ErrorCodes.MCI_Error_Host_MB_msg_read1;
}
else
{
OnMessageEvent("NFC DLL Error: Previous message read as " + Tools.BytesToHex(responseMsg));
OnMessageEvent("NFC DLL Error: Present request not sent, retry again !");
returnError = (byte)MCI_ErrorCodes.MCI_Error_Host_req_not_sent;
}
}
MCI_CycleResponseMsgTimeoutFlag = false;
stopReqResCycleTimeoutTimer();
return returnError;
}
//Checking previous app message is in mailbox or not, if present then return failure !
if ((MB_Ctrl_Reg_Value & 0x04) == 0x04)
{
// Previous sent request is not read by iPERL
MCI_CycleResponseMsgTimeoutFlag = false;
stopReqResCycleTimeoutTimer();
return (byte)MCI_ErrorCodes.MCI_Error_Host_req_not_read_by_iperl;
}
//Mailbox free, so sending request message
if (_ST25DV_Device.ST25DV_WriteMessage(InBuffer))
{
while (true)
{
if (!_ST25DV_Device.ST25DV_ReadMailboxControlReg(out MB_Ctrl_Reg_Value))
{
MCI_CycleResponseMsgTimeoutFlag = false;
stopReqResCycleTimeoutTimer();
return (byte)MCI_ErrorCodes.MCI_Error_Host_MB_CTRL_Reg_Read2;
}
//Mailbox enable/disable check, proceed further only if enabled
if ((MB_Ctrl_Reg_Value & 0x01) == 0x00)
{
MCI_CycleResponseMsgTimeoutFlag = false;
stopReqResCycleTimeoutTimer();
return (byte)MCI_ErrorCodes.MCI_Error_Host_MB_disabled2;
}
//Proceed further only if host replied response message, otherwise wait in this loop
if ((MB_Ctrl_Reg_Value & 0x02) == 0x02)
{
if (!_ST25DV_Device.ST25DV_ReadMailboxMessageLength(out MB_LEN_Dyn_Register))
{
MCI_CycleResponseMsgTimeoutFlag = false;
stopReqResCycleTimeoutTimer();
return (byte)MCI_ErrorCodes.MCI_Error_Host_MB_LEN_Reg_read2;
}
else
{
if (!_ST25DV_Device.ST25DV_ReadMessage(MB_LEN_Dyn_Register, out responseMsg))
{
MCI_CycleResponseMsgTimeoutFlag = false;
stopReqResCycleTimeoutTimer();
return (byte)MCI_ErrorCodes.MCI_Error_Host_MB_msg_read2;
}
else
{
OutBuffer = new byte[responseMsg.Length];
OutBuffer = responseMsg;
MCI_CycleResponseMsgTimeoutFlag = false;
stopReqResCycleTimeoutTimer();
return (byte)MCI_ErrorCodes.Success_No_error;
}
}
}
//Checking timeout occured or not
if(MCI_CycleResponseMsgTimeoutFlag)
{
MCI_CycleResponseMsgTimeoutFlag = false;
stopReqResCycleTimeoutTimer();
return (byte)MCI_ErrorCodes.MCI_Error_Host_Timeout;
}
}
}
else
{
MCI_CycleResponseMsgTimeoutFlag = false;
stopReqResCycleTimeoutTimer();
return (byte)MCI_ErrorCodes.MCI_Error_Host_msg_write;
}
}
#region Message Event
private void OnMessageEvent(string message)
{
NfcMessageEventArgs e = new NfcMessageEventArgs();
e.Message = message;
if (MessageEvent != null)
{
MessageEvent(this, e);
}
e = null;
}
#endregion
private void StartReqResCycleTimeoutTimer(int timeoutMilliSec)
{
_ReqResCycleTimeoutTimer.Elapsed += new ElapsedEventHandler(ReqResCycleTimeoutEvent);
_ReqResCycleTimeoutTimer.Interval = timeoutMilliSec;
_ReqResCycleTimeoutTimer.Enabled = true;
_ReqResCycleTimeoutTimer.Stop();
_ReqResCycleTimeoutTimer.Start();
}
private void stopReqResCycleTimeoutTimer()
{
_ReqResCycleTimeoutTimer.Stop();
}
#region Timer Event
private void ReqResCycleTimeoutEvent(object sender, ElapsedEventArgs e)
{
MCI_CycleResponseMsgTimeoutFlag = true;
}
#endregion
}
}