diff --git a/Doc/NFCS5_DLL_API_Documentation.pdf b/Doc/NFCS5_DLL_API_Documentation.pdf new file mode 100644 index 000000000..a07934a00 Binary files /dev/null and b/Doc/NFCS5_DLL_API_Documentation.pdf differ diff --git a/Doc/iPERL_Android_Mobile_Communication.docx b/Doc/iPERL_Android_Mobile_Communication.docx new file mode 100644 index 000000000..18a81cb77 Binary files /dev/null and b/Doc/iPERL_Android_Mobile_Communication.docx differ diff --git a/Doc/scheme.png b/Doc/scheme.png new file mode 100644 index 000000000..9c1e7a06f Binary files /dev/null and b/Doc/scheme.png differ diff --git a/NfcHandler/CR95HF_Reader.cs b/NfcHandler/CR95HF_Reader.cs index e7e71ac47..1257ca1ca 100644 --- a/NfcHandler/CR95HF_Reader.cs +++ b/NfcHandler/CR95HF_Reader.cs @@ -1,249 +1,249 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Timers; -using System.IO.Ports; - -//***************************************************************************** -// Copyright 2020 Sensus GmbH Ludwigshafen. All rights reserved. -// Author: Venkat, Rajeshwar -//***************************************************************************** - -namespace Sensus.iPerl.NfcHandler -{ - public class CR95HF_Reader - { - - private readonly byte [] CR95HF_CMD_ECHO = { 0x55 }; - private readonly byte[] CR95HF_CMD_IDN = { 0x01, 0x00 }; //CommandCode(0x01), Length(0x00) - private readonly byte[] CR95HF_CMD_PROTOCOL_SELECT_ON = { 0x02, 0x02, 0x01, 0x0D }; //CommandCode(0x02), Length(0x02), ISO/IEC 15693(0x01), 26 Kbps H, Wait for SOF, 10% modulation, Single subcarrier S, CRC appended (0x0D) - private readonly byte[] CR95HF_CMD_PROTOCOL_SELECT_OFF = { 0x02, 0x02, 0x00, 0x00 }; //CommandCode(0x02), Length(0x02), Protocol off (0x00), Protocol off (0x00) - private List CR95HF_CMD_SEND_RECEIVE = new List(); // Command code (0x04), Length (this is number of bytes after this length byte), REQUEST_FLAGS(0x02) and payload (this varies based on device command) - - private readonly byte REQUEST_FLAGS = 0x02; // Single subcarrier freq, High data rate, No Inventory/ProtExtn/Select/Address/Option flags - - private SERIAL_Driver _SERIAL_Driver; - public event DelNfc_CR95HF_MessageHandler MessageEvent; - - private static readonly Dictionary CR95HF_ErrorCodes = new Dictionary - { - { 0x00 , "Success, No error" }, - { 0x80 , "Success, No error" }, - { 0xA0 , "Success, No error" }, - { 0xC0 , "Success, No error" }, - { 0x82 , "Invalid command length" }, - { 0x83 , "Invalid protocol"}, - { 0x63 , "EEmdSOFerror23, SOF error in high part(duration 2 to 3 etu) in ISO/IEC 14443B"}, - { 0x65 , "EEmdSOFerror10, SOF error in low part(duration 10 to 11 etu) in ISO/IEC 14443B"}, - { 0x66 , "EEmdEgt error, Extended Guard Time error in ISO/IEC 14443B"}, - { 0x67 , "ETr1 Too Big Too long, TR1 send by the card, reception stopped in ISO/IEC 14443BT"}, - { 0x68 , "ETr1Too small Too small, TR1 send by the card in ISO/IEC 14443B"}, - { 0x71 , "EinternalError, Wrong frame format decoded"}, - { 0x85 , "EUserStop, Stopped by user(used only in Card mode)"}, - { 0x86 , "ECommError, Hardware communication error"}, - { 0x87 , "EFrameWaitTOut,Frame wait time out (no valid reception)"}, - { 0x88 , "EInvalidSof,Invalid SOF" }, - { 0x89 , "EBufOverflow,Too many bytes received and data still arriving" }, - { 0x8A , "EFramingError,if start bit = 1 or stop bit = 0"}, - { 0x8B , "EEgtError,EGT time out" }, - { 0x8C , "EInvalidLen,Valid for ISO/IEC 18092, if Length<3" }, - { 0x8D , "ECrcError,CRC error, Valid only for ISO/IEC 18092" }, - { 0x8E , "ERecvLost,CRC error,When reception is lost without EOF received(or subcarrier was lost)"}, - { 0x8F , "ENoField,CRC error,When Listen command detects the absence of external field)"}, - { 0x90 , "EUnintByte,Residual bits in last byte. Useful for ACK/NAK reception of ISO/IEC 14443 Type A"}, - { 0xFF , "Invalid COM port, request Failed" }, - }; - - public CR95HF_Reader(SERIAL_Driver serialdriver) - { - _SERIAL_Driver = serialdriver; - } - - #region Message Event - private void OnMessageEvent(string message) - { - NfcMessageEventArgs e = new NfcMessageEventArgs(); - e.Message = message; - - if (MessageEvent != null) - { - MessageEvent(this, e); - } - e = null; - } - #endregion - - public bool OpenConnection(string comport, int baudrate, int databits, Parity parity, StopBits stopbits) - { - return _SERIAL_Driver.OpenConnection(comport, baudrate, databits, parity, stopbits);//Port Intialization and Port Open; - } - - public bool CR95HF_Connect() - { - byte[] bytesReceived; - - if (_SERIAL_Driver.isOpen()) - { - //OnMessageEvent("Tx- " + Tools.ByteArrayToHexString(CR95HF_CMD_IDN)); - _SERIAL_Driver.SendMessage(CR95HF_CMD_IDN, CR95HF_CMD_IDN.Length); - if (_SERIAL_Driver.GetRawData().Length == 0) return false; - bytesReceived = _SERIAL_Driver.GetRawData(); - //OnMessageEvent("Rx- " + Tools.ByteArrayToHexString(bytesReceived)); - if (bytesReceived.Length == 17 && (bytesReceived[0] == 0x00 || bytesReceived[0] == 0x80)) - { - string strReader = System.Text.Encoding.ASCII.GetString(bytesReceived); - strReader = strReader.Substring(2, 12); - OnMessageEvent("CombiHead '" + strReader + "'"); - } - else - { - if (CR95HF_ErrorCodes.ContainsKey(bytesReceived[0])) - OnMessageEvent("NFC CR95HF error: " + CR95HF_ErrorCodes[bytesReceived[0]]); - else - OnMessageEvent("NFC CR95HF error: Unidentified"); - return false; - } - - //OnMessageEvent("Tx- " + Tools.ByteArrayToHexString(CR95HF_CMD_PROTOCOL_SELECT_ON)); - _SERIAL_Driver.SendMessage(CR95HF_CMD_PROTOCOL_SELECT_ON, CR95HF_CMD_PROTOCOL_SELECT_ON.Length); - if (_SERIAL_Driver.GetRawData().Length == 0) return false; - bytesReceived = _SERIAL_Driver.GetRawData(); - //OnMessageEvent("Rx- " + Tools.ByteArrayToHexString(bytesReceived)); - if ((bytesReceived[0] != 0x00) && (bytesReceived[0] != 0x80)) - { - if (CR95HF_ErrorCodes.ContainsKey(bytesReceived[0])) - OnMessageEvent("NFC CR95HF error: " + CR95HF_ErrorCodes[bytesReceived[0]]); - else - OnMessageEvent("NFC CR95HF error: Unidentified"); - return false; - } - } - else - { - OnMessageEvent(_SERIAL_Driver.ErrorMessage); - return false; - } - OnMessageEvent("NFC CR95HF: Protocol ON"); - return true; - } - - public bool CR95HF_RFProtocolOn() - { - byte[] bytesReceived; - - if (_SERIAL_Driver.isOpen()) - { - //OnMessageEvent("Tx- " + Tools.ByteArrayToHexString(CR95HF_CMD_PROTOCOL_SELECT_ON)); - _SERIAL_Driver.SendMessage(CR95HF_CMD_PROTOCOL_SELECT_ON, CR95HF_CMD_PROTOCOL_SELECT_ON.Length); - if (_SERIAL_Driver.GetRawData().Length == 0) return false; - bytesReceived = _SERIAL_Driver.GetRawData(); - //OnMessageEvent("Rx- " + Tools.ByteArrayToHexString(bytesReceived)); - if ((bytesReceived[0] != 0x00) && (bytesReceived[0] != 0x80)) - { - if (CR95HF_ErrorCodes.ContainsKey(bytesReceived[0])) - OnMessageEvent("NFC CR95HF error: " + CR95HF_ErrorCodes[bytesReceived[0]]); - else - OnMessageEvent("NFC CR95HF error: Unidentified"); - return false; - } - } - else - { - OnMessageEvent(_SERIAL_Driver.ErrorMessage); - return false; - } - return true; - } - - public bool CR95HF_RFProtocolOff() - { - byte[] bytesReceived; - - if (_SERIAL_Driver.isOpen()) - { - //OnMessageEvent("Tx- " + Tools.ByteArrayToHexString(CR95HF_CMD_PROTOCOL_SELECT_OFF)); - _SERIAL_Driver.SendMessage(CR95HF_CMD_PROTOCOL_SELECT_OFF, CR95HF_CMD_PROTOCOL_SELECT_OFF.Length); - if (_SERIAL_Driver.GetRawData().Length == 0) return false; - bytesReceived = _SERIAL_Driver.GetRawData(); - //OnMessageEvent("Rx- " + Tools.ByteArrayToHexString(bytesReceived)); - if ((bytesReceived[0] != 0x00) && (bytesReceived[0] != 0x80)) - { - if (CR95HF_ErrorCodes.ContainsKey(bytesReceived[0])) - OnMessageEvent("NFC CR95HF error: " + CR95HF_ErrorCodes[bytesReceived[0]]); - else - OnMessageEvent("NFC CR95HF error: Unidentified"); - return false; - } - } - else - { - OnMessageEvent(_SERIAL_Driver.ErrorMessage); - return false; - } - return true; - } - - public bool CR95HF_SendRecv(byte[] fromDevice, out byte[] toDevice) - { - CR95HF_CMD_SEND_RECEIVE = new List(); - toDevice = null; - - if (_SERIAL_Driver.isOpen()) - { - CR95HF_CMD_SEND_RECEIVE.Add(0x04);//Command Code - CR95HF_CMD_SEND_RECEIVE.Add((byte)(1 + fromDevice.Length)); // This is bytes from device + 1 (because request flags byte added here) - CR95HF_CMD_SEND_RECEIVE.Add(REQUEST_FLAGS); - CR95HF_CMD_SEND_RECEIVE.AddRange(fromDevice); - - //OnMessageEvent("Tx- " + Tools.ByteArrayToHexString(CR95HF_CMD_SEND_RECEIVE.ToArray())); - _SERIAL_Driver.SendMessage(CR95HF_CMD_SEND_RECEIVE.ToArray(), (3 + fromDevice.Length)); // This is bytes from device + 3 (because request flags + length + reader command) - if (_SERIAL_Driver.GetRawData().Length == 0) return false; - byte[] bytesReceived = _SERIAL_Driver.GetRawData(); - //OnMessageEvent("Rx- " + Tools.ByteArrayToHexString(bytesReceived)); - if ((bytesReceived[0] == 0x00) || (bytesReceived[0] == 0x80) || (bytesReceived[0] == 0xA0) || (bytesReceived[0] == 0xC0)) - { - toDevice = new byte[bytesReceived[1]]; - for (int i = 0; i < Convert.ToInt32(bytesReceived[1]); i++) - { - toDevice[i] = bytesReceived[2 + i]; - } - } - else - { - if (CR95HF_ErrorCodes.ContainsKey(bytesReceived[0])) - OnMessageEvent("NFC CR95HF error: " + CR95HF_ErrorCodes[bytesReceived[0]]); - else - OnMessageEvent("NFC CR95HF error: Unidentified"); - return false; - } - } - else - { - OnMessageEvent(_SERIAL_Driver.ErrorMessage); - return false; - } - return true; - } - public bool CR95HF_Echo() - { - if (_SERIAL_Driver.isOpen()) - { - if (_SERIAL_Driver.SendMessage(CR95HF_CMD_ECHO, 1)) - { - if (_SERIAL_Driver.GetRawData().Length == 0) return false; - byte[] bytesReceived = _SERIAL_Driver.GetRawData(); - if ((bytesReceived.Length == 1) && (bytesReceived[0] == CR95HF_CMD_ECHO[0])) - return true; - } - } - else - { - OnMessageEvent(_SERIAL_Driver.ErrorMessage); - return false; - } - return false; - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Timers; +using System.IO.Ports; + +//***************************************************************************** +// Copyright 2020 Sensus GmbH Ludwigshafen. All rights reserved. +// Author: Venkat, Rajeshwar +//***************************************************************************** + +namespace Sensus.iPerl.NfcHandler +{ + public class CR95HF_Reader + { + + private readonly byte [] CR95HF_CMD_ECHO = { 0x55 }; + private readonly byte[] CR95HF_CMD_IDN = { 0x01, 0x00 }; //CommandCode(0x01), Length(0x00) + private readonly byte[] CR95HF_CMD_PROTOCOL_SELECT_ON = { 0x02, 0x02, 0x01, 0x0D }; //CommandCode(0x02), Length(0x02), ISO/IEC 15693(0x01), 26 Kbps H, Wait for SOF, 10% modulation, Single subcarrier S, CRC appended (0x0D) + private readonly byte[] CR95HF_CMD_PROTOCOL_SELECT_OFF = { 0x02, 0x02, 0x00, 0x00 }; //CommandCode(0x02), Length(0x02), Protocol off (0x00), Protocol off (0x00) + private List CR95HF_CMD_SEND_RECEIVE = new List(); // Command code (0x04), Length (this is number of bytes after this length byte), REQUEST_FLAGS(0x02) and payload (this varies based on device command) + + private readonly byte REQUEST_FLAGS = 0x02; // Single subcarrier freq, High data rate, No Inventory/ProtExtn/Select/Address/Option flags + + private SERIAL_Driver _SERIAL_Driver; + public event DelNfc_CR95HF_MessageHandler MessageEvent; + + private static readonly Dictionary CR95HF_ErrorCodes = new Dictionary + { + { 0x00 , "Success, No error" }, + { 0x80 , "Success, No error" }, + { 0xA0 , "Success, No error" }, + { 0xC0 , "Success, No error" }, + { 0x82 , "Invalid command length" }, + { 0x83 , "Invalid protocol"}, + { 0x63 , "EEmdSOFerror23, SOF error in high part(duration 2 to 3 etu) in ISO/IEC 14443B"}, + { 0x65 , "EEmdSOFerror10, SOF error in low part(duration 10 to 11 etu) in ISO/IEC 14443B"}, + { 0x66 , "EEmdEgt error, Extended Guard Time error in ISO/IEC 14443B"}, + { 0x67 , "ETr1 Too Big Too long, TR1 send by the card, reception stopped in ISO/IEC 14443BT"}, + { 0x68 , "ETr1Too small Too small, TR1 send by the card in ISO/IEC 14443B"}, + { 0x71 , "EinternalError, Wrong frame format decoded"}, + { 0x85 , "EUserStop, Stopped by user(used only in Card mode)"}, + { 0x86 , "ECommError, Hardware communication error"}, + { 0x87 , "EFrameWaitTOut,Frame wait time out (no valid reception)"}, + { 0x88 , "EInvalidSof,Invalid SOF" }, + { 0x89 , "EBufOverflow,Too many bytes received and data still arriving" }, + { 0x8A , "EFramingError,if start bit = 1 or stop bit = 0"}, + { 0x8B , "EEgtError,EGT time out" }, + { 0x8C , "EInvalidLen,Valid for ISO/IEC 18092, if Length<3" }, + { 0x8D , "ECrcError,CRC error, Valid only for ISO/IEC 18092" }, + { 0x8E , "ERecvLost,CRC error,When reception is lost without EOF received(or subcarrier was lost)"}, + { 0x8F , "ENoField,CRC error,When Listen command detects the absence of external field)"}, + { 0x90 , "EUnintByte,Residual bits in last byte. Useful for ACK/NAK reception of ISO/IEC 14443 Type A"}, + { 0xFF , "Invalid COM port, request Failed" }, + }; + + public CR95HF_Reader(SERIAL_Driver serialdriver) + { + _SERIAL_Driver = serialdriver; + } + + #region Message Event + private void OnMessageEvent(string message) + { + NfcMessageEventArgs e = new NfcMessageEventArgs(); + e.Message = message; + + if (MessageEvent != null) + { + MessageEvent(this, e); + } + e = null; + } + #endregion + + public bool OpenConnection(string comport, int baudrate, int databits, Parity parity, StopBits stopbits) + { + return _SERIAL_Driver.OpenConnection(comport, baudrate, databits, parity, stopbits);//Port Intialization and Port Open; + } + + public bool CR95HF_Connect() + { + byte[] bytesReceived; + + if (_SERIAL_Driver.isOpen()) + { + //OnMessageEvent("Tx- " + Tools.ByteArrayToHexString(CR95HF_CMD_IDN)); + _SERIAL_Driver.SendMessage(CR95HF_CMD_IDN, CR95HF_CMD_IDN.Length); + if (_SERIAL_Driver.GetRawData().Length == 0) return false; + bytesReceived = _SERIAL_Driver.GetRawData(); + //OnMessageEvent("Rx- " + Tools.ByteArrayToHexString(bytesReceived)); + if (bytesReceived.Length == 17 && (bytesReceived[0] == 0x00 || bytesReceived[0] == 0x80)) + { + string strReader = System.Text.Encoding.ASCII.GetString(bytesReceived); + strReader = strReader.Substring(2, 12); + OnMessageEvent("CombiHead '" + strReader + "'"); + } + else + { + if (CR95HF_ErrorCodes.ContainsKey(bytesReceived[0])) + OnMessageEvent("NFC CR95HF error: " + CR95HF_ErrorCodes[bytesReceived[0]]); + else + OnMessageEvent("NFC CR95HF error: Unidentified"); + return false; + } + + //OnMessageEvent("Tx- " + Tools.ByteArrayToHexString(CR95HF_CMD_PROTOCOL_SELECT_ON)); + _SERIAL_Driver.SendMessage(CR95HF_CMD_PROTOCOL_SELECT_ON, CR95HF_CMD_PROTOCOL_SELECT_ON.Length); + if (_SERIAL_Driver.GetRawData().Length == 0) return false; + bytesReceived = _SERIAL_Driver.GetRawData(); + //OnMessageEvent("Rx- " + Tools.ByteArrayToHexString(bytesReceived)); + if ((bytesReceived[0] != 0x00) && (bytesReceived[0] != 0x80)) + { + if (CR95HF_ErrorCodes.ContainsKey(bytesReceived[0])) + OnMessageEvent("NFC CR95HF error: " + CR95HF_ErrorCodes[bytesReceived[0]]); + else + OnMessageEvent("NFC CR95HF error: Unidentified"); + return false; + } + } + else + { + OnMessageEvent(_SERIAL_Driver.ErrorMessage); + return false; + } + OnMessageEvent("NFC CR95HF: Protocol ON"); + return true; + } + + public bool CR95HF_RFProtocolOn() + { + byte[] bytesReceived; + + if (_SERIAL_Driver.isOpen()) + { + //OnMessageEvent("Tx- " + Tools.ByteArrayToHexString(CR95HF_CMD_PROTOCOL_SELECT_ON)); + _SERIAL_Driver.SendMessage(CR95HF_CMD_PROTOCOL_SELECT_ON, CR95HF_CMD_PROTOCOL_SELECT_ON.Length); + if (_SERIAL_Driver.GetRawData().Length == 0) return false; + bytesReceived = _SERIAL_Driver.GetRawData(); + //OnMessageEvent("Rx- " + Tools.ByteArrayToHexString(bytesReceived)); + if ((bytesReceived[0] != 0x00) && (bytesReceived[0] != 0x80)) + { + if (CR95HF_ErrorCodes.ContainsKey(bytesReceived[0])) + OnMessageEvent("NFC CR95HF error: " + CR95HF_ErrorCodes[bytesReceived[0]]); + else + OnMessageEvent("NFC CR95HF error: Unidentified"); + return false; + } + } + else + { + OnMessageEvent(_SERIAL_Driver.ErrorMessage); + return false; + } + return true; + } + + public bool CR95HF_RFProtocolOff() + { + byte[] bytesReceived; + + if (_SERIAL_Driver.isOpen()) + { + //OnMessageEvent("Tx- " + Tools.ByteArrayToHexString(CR95HF_CMD_PROTOCOL_SELECT_OFF)); + _SERIAL_Driver.SendMessage(CR95HF_CMD_PROTOCOL_SELECT_OFF, CR95HF_CMD_PROTOCOL_SELECT_OFF.Length); + if (_SERIAL_Driver.GetRawData().Length == 0) return false; + bytesReceived = _SERIAL_Driver.GetRawData(); + //OnMessageEvent("Rx- " + Tools.ByteArrayToHexString(bytesReceived)); + if ((bytesReceived[0] != 0x00) && (bytesReceived[0] != 0x80)) + { + if (CR95HF_ErrorCodes.ContainsKey(bytesReceived[0])) + OnMessageEvent("NFC CR95HF error: " + CR95HF_ErrorCodes[bytesReceived[0]]); + else + OnMessageEvent("NFC CR95HF error: Unidentified"); + return false; + } + } + else + { + OnMessageEvent(_SERIAL_Driver.ErrorMessage); + return false; + } + return true; + } + + public bool CR95HF_SendRecv(byte[] fromDevice, out byte[] toDevice) + { + CR95HF_CMD_SEND_RECEIVE = new List(); + toDevice = null; + + if (_SERIAL_Driver.isOpen()) + { + CR95HF_CMD_SEND_RECEIVE.Add(0x04);//Command Code + CR95HF_CMD_SEND_RECEIVE.Add((byte)(1 + fromDevice.Length)); // This is bytes from device + 1 (because request flags byte added here) + CR95HF_CMD_SEND_RECEIVE.Add(REQUEST_FLAGS); + CR95HF_CMD_SEND_RECEIVE.AddRange(fromDevice); + + //OnMessageEvent("Tx- " + Tools.ByteArrayToHexString(CR95HF_CMD_SEND_RECEIVE.ToArray())); + _SERIAL_Driver.SendMessage(CR95HF_CMD_SEND_RECEIVE.ToArray(), CR95HF_CMD_SEND_RECEIVE.Count); + if (_SERIAL_Driver.GetRawData().Length == 0) return false; + byte[] bytesReceived = _SERIAL_Driver.GetRawData(); + //OnMessageEvent("Rx- " + Tools.ByteArrayToHexString(bytesReceived)); + if ((bytesReceived[0] == 0x00) || (bytesReceived[0] == 0x80) || (bytesReceived[0] == 0xA0) || (bytesReceived[0] == 0xC0)) + { + toDevice = new byte[bytesReceived[1]]; + for (int i = 0; i < Convert.ToInt32(bytesReceived[1]); i++) + { + toDevice[i] = bytesReceived[2 + i]; + } + } + else + { + if (CR95HF_ErrorCodes.ContainsKey(bytesReceived[0])) + OnMessageEvent("NFC CR95HF error: " + CR95HF_ErrorCodes[bytesReceived[0]]); + else + OnMessageEvent("NFC CR95HF error: Unidentified"); + return false; + } + } + else + { + OnMessageEvent(_SERIAL_Driver.ErrorMessage); + return false; + } + return true; + } + public bool CR95HF_Echo() + { + if (_SERIAL_Driver.isOpen()) + { + if (_SERIAL_Driver.SendMessage(CR95HF_CMD_ECHO, 1)) + { + if (_SERIAL_Driver.GetRawData().Length == 0) return false; + byte[] bytesReceived = _SERIAL_Driver.GetRawData(); + if ((bytesReceived.Length == 1) && (bytesReceived[0] == CR95HF_CMD_ECHO[0])) + return true; + } + } + else + { + OnMessageEvent(_SERIAL_Driver.ErrorMessage); + return false; + } + return false; + } + } } \ No newline at end of file diff --git a/NfcHandler/MCI_Protocol.cs b/NfcHandler/MCI_Protocol.cs index 067848f8a..df2e71196 100644 --- a/NfcHandler/MCI_Protocol.cs +++ b/NfcHandler/MCI_Protocol.cs @@ -7,6 +7,7 @@ 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. @@ -22,7 +23,6 @@ namespace Sensus.iPerl.NfcHandler private readonly byte STX = (byte) 0x02; private readonly byte ETX = (byte) 0x03; private readonly byte RX_ACK_RESPONSE_MSG_ID = (byte) 0xC9; - private readonly byte RX_ACK_PASSTHROUGH_MSG_ID = (byte)0xCE; private readonly ushort[] MciPasswords = { 0x0000, 0x55AA, 0x1234, 0x97D1 }; public event DelNfc_MCI_MessageHandler MessageEvent; @@ -286,6 +286,7 @@ namespace Sensus.iPerl.NfcHandler 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) { @@ -296,33 +297,27 @@ namespace Sensus.iPerl.NfcHandler errorCode = (byte) MCI_ErrorCodes.Success_No_error; if (payloadlength != inBuffer.Length) - { - OnMessageEvent("Insufficient Payload !, Payload length given as: " + 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])) + if (! MCI_Protocol.MCI_CmdCodes.ContainsKey(inBuffer[0])) { - OnMessageEvent("Write " + MCI_Protocol.MCI_CmdCodes[inBuffer[0]]); - } - else - { - OnMessageEvent("Command: Not supported"); + // Command not supported errorCode = (byte)MCI_ErrorCodes.MCI_Error_Host_CommandNotInCmdCodeList; return false; } } - else + else // not a command => should be struct { if (!IsValidStruct(StName)) { errorCode = (byte)MCI_ErrorCodes.MCI_Error_Host_InvalidStructureID_CannotSendMsg; - OnMessageEvent("Write request:" + MCI_Protocol.GetMCIErrorMessage(errorCode)); return false; } - OnMessageEvent("Write " + StructToStr(StName) + ": " + Tools.BytesToHex(inBuffer)); } byte[] MsgId_Password = MCI_Write_Info[(int)StName]; @@ -347,12 +342,10 @@ namespace Sensus.iPerl.NfcHandler RequestMessage.Add(crcValue[1]); RequestMessage.Add(ETX); - OnMessageEvent("Write Request: " + Tools.BytesToHex(RequestMessage.ToArray())); + 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) { - OnMessageEvent("WriteReq denied"); - errorCode = (byte)MCI_ErrorCodes.MCI_Error_Host_WriteReq_denied; return false; } //Response message received @@ -360,33 +353,159 @@ namespace Sensus.iPerl.NfcHandler 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); - OnMessageEvent(Crc.commentCRC(RxCrcMeter, RxCrcComputed)); if (!Crc.crc_do_match(RxCrcMeter, RxCrcComputed)) { - OnMessageEvent("CRC from Meter and PC do not match!"); + 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_PASSTHROUGH_MSG_ID || ResponseMessage[2] == RX_ACK_RESPONSE_MSG_ID) + 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 - OnMessageEvent("Write " + StructToStr(StName) + "Request Response: " + Tools.BytesToHex(ResponseMessage)); + 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 Calibration: Failed with error " + Tools.ByteToHexString(errorCode)); + OnMessageEvent("Write " + StructToStr(StName) + " failed. Request Response: " + Tools.BytesToHex(ResponseMessage)); return false; } OnMessageEvent("Write : Success"); return true; } - OnMessageEvent("WriteReq bad device ans"); 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 RequestMessage = new List(); + 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) { @@ -409,9 +528,8 @@ namespace Sensus.iPerl.NfcHandler { errorCode = (byte)MCI_ErrorCodes.MCI_Error_Host_InvalidStructureID_CannotSendMsg; OnMessageEvent("Read request:" + MCI_Protocol.GetMCIErrorMessage(errorCode)); - return false; + return false; } - OnMessageEvent("Read " + StructToStr(StName)); RequestMessage.Add(STX); RequestMessage.Add(0x06); @@ -430,12 +548,11 @@ namespace Sensus.iPerl.NfcHandler errorCode = MCI_TxRequest_RxResponse(RequestMessage.ToArray(), out ResponseMessage, timeoutMs); if (errorCode != (byte) MCI_ErrorCodes.Success_No_error) { - OnMessageEvent("Read Request:" + MCI_Protocol.GetMCIErrorMessage(errorCode)); return false; } if ((ResponseMessage[0] == STX) && (ResponseMessage[11] == ETX) && (ResponseMessage[1] == 0x07) - && (ResponseMessage[2] == RX_ACK_PASSTHROUGH_MSG_ID || ResponseMessage[2] == RX_ACK_RESPONSE_MSG_ID) ) + && (ResponseMessage[2] == RX_ACK_RESPONSE_MSG_ID)) { //Ack message received, not served the read request errorCode = ResponseMessage[6]; // forward error message from meter @@ -456,7 +573,7 @@ namespace Sensus.iPerl.NfcHandler byte[] RxCrcComputed = Crc.calcCRCfromMessage(ResponseMessage); - OnMessageEvent(Crc.commentCRC(RxCrcMeter, RxCrcComputed)); + // OnMessageEvent(Crc.commentCRC(RxCrcMeter, RxCrcComputed)); if (!Crc.crc_do_match(RxCrcMeter, RxCrcComputed)) { errorCode = (byte) MCI_ErrorCodes.MCI_Error_Host_MeterCRCDoesNotMatch; @@ -476,7 +593,6 @@ namespace Sensus.iPerl.NfcHandler { outBuffer[i] = (ResponseMessage[6 + i]); } - OnMessageEvent("Read Request Response: " + Tools.BytesToHex(ResponseMessage)); if (IsValidStruct(StName)) @@ -505,7 +621,6 @@ namespace Sensus.iPerl.NfcHandler if (!_ST25DV_Device.ST25DV_ReadMailboxControlReg(out MB_Ctrl_Reg_Value)) { - OnMessageEvent("NFC DLL Error: MB CTRL Reg read (1) failed"); MCI_CycleResponseMsgTimeoutFlag = false; stopReqResCycleTimeoutTimer(); return (byte) MCI_ErrorCodes.MCI_Error_Host_MB_CTRL_Reg_Read1; @@ -513,10 +628,10 @@ namespace Sensus.iPerl.NfcHandler //Mailbox enable/disable check, proceed further only if enabled if ((MB_Ctrl_Reg_Value & 0x01) == 0x00) { - OnMessageEvent("NFC DLL Error: MB feature (1) disabled"); MCI_CycleResponseMsgTimeoutFlag = false; - stopReqResCycleTimeoutTimer(); - return (byte)MCI_ErrorCodes.MCI_Error_Host_MB_disabled1; + 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) @@ -525,7 +640,6 @@ namespace Sensus.iPerl.NfcHandler OnMessageEvent("NFC DLL Error: Previous message not read, reading now !"); if (!_ST25DV_Device.ST25DV_ReadMailboxMessageLength(out MB_LEN_Dyn_Register)) { - OnMessageEvent("NFC DLL Error: MB LEN Reg read (1) failed"); returnError = (byte)MCI_ErrorCodes.MCI_Error_Host_MB_LEN_Reg_read1; } else @@ -533,7 +647,6 @@ namespace Sensus.iPerl.NfcHandler OnMessageEvent("NFC DLL Error: Previous message length " + MB_LEN_Dyn_Register); if (!_ST25DV_Device.ST25DV_ReadMessage(MB_LEN_Dyn_Register, out responseMsg)) { - OnMessageEvent("NFC DLL Error: MB message read (1) failed"); returnError = (byte)MCI_ErrorCodes.MCI_Error_Host_MB_msg_read1; } else @@ -551,7 +664,7 @@ namespace Sensus.iPerl.NfcHandler //Checking previous app message is in mailbox or not, if present then return failure ! if ((MB_Ctrl_Reg_Value & 0x04) == 0x04) { - OnMessageEvent("NFC DLL Error: Previous sent request is not read by iPERL. So, present request will not be sent, retry again !"); + // Previous sent request is not read by iPERL MCI_CycleResponseMsgTimeoutFlag = false; stopReqResCycleTimeoutTimer(); return (byte)MCI_ErrorCodes.MCI_Error_Host_req_not_read_by_iperl; @@ -563,7 +676,6 @@ namespace Sensus.iPerl.NfcHandler { if (!_ST25DV_Device.ST25DV_ReadMailboxControlReg(out MB_Ctrl_Reg_Value)) { - OnMessageEvent("NFC DLL Error: MB CTRL Reg read (2) failed"); MCI_CycleResponseMsgTimeoutFlag = false; stopReqResCycleTimeoutTimer(); return (byte)MCI_ErrorCodes.MCI_Error_Host_MB_CTRL_Reg_Read2; @@ -571,7 +683,6 @@ namespace Sensus.iPerl.NfcHandler //Mailbox enable/disable check, proceed further only if enabled if ((MB_Ctrl_Reg_Value & 0x01) == 0x00) { - OnMessageEvent("NFC DLL Error: MB feature (2) disabled"); MCI_CycleResponseMsgTimeoutFlag = false; stopReqResCycleTimeoutTimer(); return (byte)MCI_ErrorCodes.MCI_Error_Host_MB_disabled2; @@ -582,7 +693,6 @@ namespace Sensus.iPerl.NfcHandler { if (!_ST25DV_Device.ST25DV_ReadMailboxMessageLength(out MB_LEN_Dyn_Register)) { - OnMessageEvent("NFC DLL Error: MB LEN Reg read (2) failed"); MCI_CycleResponseMsgTimeoutFlag = false; stopReqResCycleTimeoutTimer(); return (byte)MCI_ErrorCodes.MCI_Error_Host_MB_LEN_Reg_read2; @@ -591,7 +701,6 @@ namespace Sensus.iPerl.NfcHandler { if (!_ST25DV_Device.ST25DV_ReadMessage(MB_LEN_Dyn_Register, out responseMsg)) { - OnMessageEvent("NFC DLL Error: MB message read (2) failed"); MCI_CycleResponseMsgTimeoutFlag = false; stopReqResCycleTimeoutTimer(); return (byte)MCI_ErrorCodes.MCI_Error_Host_MB_msg_read2; @@ -609,7 +718,6 @@ namespace Sensus.iPerl.NfcHandler //Checking timeout occured or not if(MCI_CycleResponseMsgTimeoutFlag) { - OnMessageEvent("NFC DLL Error: Timeout"); MCI_CycleResponseMsgTimeoutFlag = false; stopReqResCycleTimeoutTimer(); return (byte)MCI_ErrorCodes.MCI_Error_Host_Timeout; @@ -618,7 +726,6 @@ namespace Sensus.iPerl.NfcHandler } else { - OnMessageEvent("NFC DLL Error: MB Msg write failed"); MCI_CycleResponseMsgTimeoutFlag = false; stopReqResCycleTimeoutTimer(); return (byte)MCI_ErrorCodes.MCI_Error_Host_msg_write; diff --git a/NfcHandler/NfcDataHandler.cs b/NfcHandler/NfcDataHandler.cs index 537ecb8a9..2b8306305 100644 --- a/NfcHandler/NfcDataHandler.cs +++ b/NfcHandler/NfcDataHandler.cs @@ -1,7 +1,8 @@ using System; using System.IO.Ports; -using System.Diagnostics; +using System.Text; +using System.Threading; //***************************************************************************** // Copyright 2020 Sensus GmbH Ludwigshafen. All rights reserved. @@ -12,6 +13,8 @@ namespace Sensus.iPerl.NfcHandler { public sealed class NfcDataHandler { + private string _ComPort = ""; + private readonly byte[] readCommand = { 0x80, 0x08, 0x00, 0x03, 0x00, 0x00 }; public SERIAL_Driver _SERIAL_Driver; public SERIAL_Driver _SERIAL_Driver_Head_Config; @@ -27,8 +30,6 @@ namespace Sensus.iPerl.NfcHandler public event DelNfcMessageHandler MessageEvent; - private string _ComPort = ""; - public NfcDataHandler() { _SERIAL_Driver = new SERIAL_Driver(); @@ -37,14 +38,14 @@ namespace Sensus.iPerl.NfcHandler _ST25DV_Device = new ST25DV_Device(_CR95HF_Reader); _MCI_Protocol = new MCI_Protocol(_ST25DV_Device); _NFCHead_Config = new NFCHeadConfig(_SERIAL_Driver_Head_Config); - LastErrorCode = 0; + LastErrorCode = 0; } public bool OpenConnection(string comport, int baudrate, int databits, Parity parity, StopBits stopbits) { _ComPort = comport; bool isopen = _SERIAL_Driver.OpenConnection(comport, baudrate, databits, parity, stopbits); - if(!isopen)OnMessageEvent(_SERIAL_Driver.ErrorMessage); + if (!isopen) OnMessageEvent(_SERIAL_Driver.ErrorMessage); return isopen; } @@ -75,7 +76,7 @@ namespace Sensus.iPerl.NfcHandler OnMessageEvent(comport + "......... Already in use "); return false; } - + bool isopen = _SERIAL_Driver_Head_Config.OpenConnection(comport, 9600, 8, Parity.None, StopBits.Two); OnMessageEvent(_SERIAL_Driver_Head_Config.ErrorMessage); return isopen; @@ -140,7 +141,7 @@ namespace Sensus.iPerl.NfcHandler public bool ConnectDevice() { byte[] responseData; - + if (_CR95HF_Reader.CR95HF_RFProtocolOn()) { if (GetSystemInfo()) @@ -188,7 +189,7 @@ namespace Sensus.iPerl.NfcHandler OnMessageEvent(ex.Message); } return false; - } + } public bool ST25DV_ReadSingleBlock(byte blockNumber, out byte[] outBuffer) { @@ -256,18 +257,17 @@ namespace Sensus.iPerl.NfcHandler if (!worked) { SetLastErrorMesage(); - ST25DV_MailboxCommStop(); return false; } - return ST25DV_MailboxCommStop(); + return true; } return false; } - // This function-header is needed for calls to the DLL without need for using enums. - // In python 3.11 the module pythonnet (v3.x) does not support casting 'int' to 'enum' aynmore, - // so this workaround is needed. - public bool MCI_Write_pythonwrapper_enum(int STIndex, ushort offset, byte payloadlength, byte[] payload, int timeoutMs) + // This function-header is needed for calls to the DLL without need for using enums. + // In python 3.11 the module pythonnet (v3.x) does not support casting 'int' to 'enum' aynmore, + // so this workaround is needed. + public bool MCI_Write_pythonwrapper_enum(int STIndex, ushort offset, byte payloadlength, byte[] payload, int timeoutMs) { return MCI_Write((MCI_Protocol.StructName)STIndex, offset, payloadlength, payload, timeoutMs); } @@ -284,140 +284,74 @@ namespace Sensus.iPerl.NfcHandler if (!ans) { SetLastErrorMesage(); - ST25DV_MailboxCommStop(); return false; } - return ST25DV_MailboxCommStop(); + return true; } return false; } - public bool MCI_Read(byte msgId, ushort offset, byte payloadlength, int timeoutMs) + public bool MCI_Write_Read(MCI_Protocol.StructName StName, ushort offset, byte payloadlength, byte[] payload, int timeoutMs) { LastErrorMessage = string.Empty; + LastData = null; byte[] response; + byte errorCode = 0; if (ST25DV_MailboxCommStart()) { - bool ans = _MCI_Protocol.MCI_Read((MCI_Protocol.StructName) msgId, offset, payloadlength, timeoutMs, - out response, out errorCode); + bool ans = _MCI_Protocol.MCI_Write_Read(StName, offset, payloadlength, payload, out response, timeoutMs, out errorCode); LastErrorCode = errorCode; LastData = response; if (!ans) { SetLastErrorMesage(); - ST25DV_MailboxCommStop(); return false; } - return ST25DV_MailboxCommStop(); - } - return false; - } - - public bool MCI_Write(byte msgId, ushort offset, byte payloadlength, byte[] payload, int timeoutMs) - { - LastErrorMessage = string.Empty; - LastData = null; - byte errorCode = 0; - if (ST25DV_MailboxCommStart()) - { - bool ans = _MCI_Protocol.MCI_Write((MCI_Protocol.StructName) msgId, offset, payloadlength, payload, - timeoutMs, out errorCode); - LastErrorCode = errorCode; - if (!ans) - { - SetLastErrorMesage(); - ST25DV_MailboxCommStop(); - return false; - } - return ST25DV_MailboxCommStop(); + return true; } return false; } private bool ST25DV_MailboxCommStart() { - bool success = false; - byte[] EepromBlockRead = { 0, 0, 0, 0 }; - byte[] EepromBlockWrite = { 0, 0, 0, 0 }; - - //Byte-2 in block-2 represent the EEPROM I2C interface status -> - //0xA5-EEPROM I2C Interface Idle, 0x5A-EEPROM I2C Interface Active - success = _ST25DV_Device.ST25DV_ReadSingleBlock(2, out EepromBlockRead, false); - if (success) + // wake up the ST25DV by setting the GPO pin to output a pulse -> INT on Metro (set highest bit to one -> causes a pulse on GPO) + if (_ST25DV_Device.ST25DV_WriteGPOManageCommand(_ST25DV_Device.GPO_MANAGE_SET_PULSE, false)) { - if (EepromBlockRead[1] == 0xA5) //0xA5-EEPROM I2C Interface Idle - { - //Byte-1 in block-64 represent the Mailbox RF interface status -> - //0xA5-Mailbox RF Interface Idle, 0x5A-Mailbox RF Interface Active - EepromBlockWrite[0] = 0x5A; //Raising Mailbox RF interface Active flag to avoid collisions with host interface - success = _ST25DV_Device.ST25DV_WriteSingleBlock(64, EepromBlockWrite, false); - if (success) - { - //Sets 0x01 (MB_EN) in the register (MB_CTRL_Dyn) with address 0x0D - if (_ST25DV_Device.ST25DV_WriteDynamicConfiguration(0x0D, 0x01, false)) - { - return true; //With this we proceed for mailbox communication with ST25 - } - else - { - LastErrorCode = 0x08; //MCI Error: Unidentified - LastErrorMessage = "MB_CTRL_Dyn writing failed(ST25DV_MailboxCommStart), try again"; - return false; - } - } - else - { - LastErrorCode = 0x08; //MCI Error: Unidentified - LastErrorMessage = "Mailbox RF interface status writing failed(ST25DV_MailboxCommStart), try again"; - return false; - } - } - else - { - LastErrorCode = 0x08; //MCI Error: Unidentified - LastErrorMessage = "EEPROM interface busy(ST25DV_MailboxCommStart), try again"; - return false; - } + Thread.Sleep(10); // wait 10ms to give metro some time + byte MB_Ctrl_Reg_Value = 0x00; + for (int i = 0; i < 20; i++) // do 20 retries max (20 times 100ms = 2sec, which should be more than enough) + { + if (_ST25DV_Device.ST25DV_ReadMailboxControlReg(out MB_Ctrl_Reg_Value)) + { + if ((MB_Ctrl_Reg_Value & 0x01) == 0x01) + { + return true; //With this we proceed for mailbox communication with ST25 + } + else + { + Thread.Sleep(100); // wait 100ms, then try again + LastErrorMessage = "Mailbox was not activated by Firmware (ST25DV_MailboxCommStart), try again"; + } + } + else + { + Thread.Sleep(100); // wait 100ms, then try again + LastErrorMessage = "Mailbox state could not be read (ST25DV_MailboxCommStart), try again"; + } + } + LastErrorCode = 0x08; //MCI Error: Unidentified + OnMessageEvent(">> REMARK: Check if Metorlogy firmware-version is at least: 5.1.24 <<"); + return false; } else { LastErrorCode = 0x08; //MCI Error: Unidentified - LastErrorMessage = "EEPROM interface status reading failed(ST25DV_MailboxCommStart), try again"; + LastErrorMessage = "GPO config writing failed(ST25DV_MailboxCommStart), try again"; return false; } } - private bool ST25DV_MailboxCommStop() - { - bool success = false; - byte[] EepromBlockWrite = { 0, 0, 0, 0 }; - - //Sets 0x00 (MB_EN) in the register (MB_CTRL_Dyn) with address 0x0D - if (_ST25DV_Device.ST25DV_WriteDynamicConfiguration(0x0D, 0x00, false)) - { - //Byte-1 in block-64 represent the Mailbox RF interface status -> - //0xA5-Mailbox RF Interface Idle, 0x5A-Mailbox RF Interface Active - EepromBlockWrite[0] = 0xA5; //Raising Mailbox RF interface Idle flag to avoid collisions with host interface - success = _ST25DV_Device.ST25DV_WriteSingleBlock(64, EepromBlockWrite, false); - if (success) - { - return true; //With this we proceed for interpreting the communication happened with ST25 - } - else - { - LastErrorCode = 0x08; //MCI Error: Unidentified - LastErrorMessage = "Mailbox RF interface status writing failed(ST25DV_MailboxCommStop), try again"; - return false; - } - } - else - { - LastErrorCode = 0x08; //MCI Error: Unidentified - LastErrorMessage = "MB_CTRL_Dyn writing failed(ST25DV_MailboxCommStop), try again"; - return false; - } - } private void SetLastErrorMesage() { @@ -430,7 +364,7 @@ namespace Sensus.iPerl.NfcHandler LastErrorMessage = "MCI Error: The Errorcode '" + LastErrorCode as string + "' couldn't be converted to string with the enum MCI_ErrorCodes!"; } - + } public bool NFCHeadConfig_PulseLedOutputEnable() @@ -480,7 +414,7 @@ namespace Sensus.iPerl.NfcHandler try { - if ( (!MCI_Write(MCI_Protocol.StructName.NfcSecurity, offset, payloadLength, payload, timeoutMs)) || (LastErrorCode != 0x00)) + if ((!MCI_Write(MCI_Protocol.StructName.NfcSecurity, offset, payloadLength, payload, timeoutMs)) || (LastErrorCode != 0x00)) { return false; } @@ -492,11 +426,68 @@ namespace Sensus.iPerl.NfcHandler return true; // true - success, false - failed } + public string NFCSecurity_Read_EndpointId(int timeoutMs) + { + string result = string.Empty; + byte[] payload = readCommand; + byte payloadLength = Convert.ToByte(payload.Length); + ushort offset = 0; + + try + { + if ((!MCI_Write_Read(MCI_Protocol.StructName.NfcSecurity, offset, payloadLength, payload, timeoutMs)) || (LastErrorCode != 0x00)) + { + return string.Empty; + } + } + catch (Exception ex) + { + OnMessageEvent(ex.Message); + return string.Empty; + } + + //Check response header + if (LastData[0] != 0x05 || LastData[1] != 0x00) + { + LastErrorMessage = "Wrong response header"; + return string.Empty; + } + + //Check length byte + if (LastData[2] == 0x00) + { + LastErrorMessage = "Response length is 0"; + return string.Empty; + } + + //Check length of message + int lengthMessage = LastData[2] + 3; // two header bytes and one length byte + if (LastData.Length != lengthMessage) + { + LastErrorMessage = "Response length is wrong"; + return string.Empty; + } + + //Check identifier for information + if (LastData[3] != 0x00 || LastData[4] != 0x00) + { + LastErrorMessage = "Wrong identifier"; + return string.Empty; + } + + int lengthEndpointId = LastData[2] - 2; //Identifier bytes + byte[] id = new byte[lengthEndpointId]; + Array.Copy(LastData, 5, id, 0, lengthEndpointId); + result = Encoding.ASCII.GetString(id); + + return result; + } + public byte NFCSecurity_ReadPrivilegeLevel(int timeoutMs) { ushort offset = 0; byte payloadLength = 1; - byte payload = 4; + byte payload = 4; try { if ((!MCI_Read(MCI_Protocol.StructName.NfcSecurity, offset, payloadLength, timeoutMs)) || (LastErrorCode != 0x00)) @@ -520,7 +511,7 @@ namespace Sensus.iPerl.NfcHandler { ushort offset = 0; byte payloadLength = 1; - byte [] payload = { 0x23 }; // 0x23 - Command code for 'NFC Security reset access level' + byte[] payload = { 0x23 }; // 0x23 - Command code for 'NFC Security reset access level' try { @@ -536,13 +527,11 @@ namespace Sensus.iPerl.NfcHandler return true; // true - success, false - failed } - public string GetDllVersion() - { - System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); - FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location); - string str = "NfcS5 DLL v" + fvi.FileVersion; - return str.Remove(str.Length - 2); // only show x.y.z version, hide 4th number - } + public string GetDllVersion() + { + Version dll_version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; + return "NfcS5 DLL v" + String.Format("{0}.{1}.{2}", dll_version.Major, dll_version.Minor, dll_version.Build); //, dll_version.MajorRevision); + } #region Message Event private void OnMessageEvent(string message) diff --git a/NfcHandler/ST25DV_Device.cs b/NfcHandler/ST25DV_Device.cs index 0bb1d8be1..8d2ac661d 100644 --- a/NfcHandler/ST25DV_Device.cs +++ b/NfcHandler/ST25DV_Device.cs @@ -22,8 +22,10 @@ namespace Sensus.iPerl.NfcHandler private byte[] ST25DV_CMD_WRITE_DYNAMIC_CONFIG = { 0xAE, 0x02, 0x00, 0x00 }; //Command code, IC Mfg Code, Register address, register value to be written private readonly byte[] ST25DV_CMD_READ_MAILBOX_CONTROL_REG = { 0xAD, 0x02, 0x0D }; //Command code, IC Mfg Code, MB_CTRL_Dyn Register address private readonly byte[] ST25DV_CMD_READ_MAILBOX_MESSAGE_LENGTH = { 0xAB, 0x02 }; //Command code, IC Mfg Code - private byte[] ST25DV_CMD_READ_MESSAGE = { 0xAC, 0x02, 0x00, 0x00 }; //Command code, IC Mfg Code, Mailbox pointer(mostly this is 0), NumberofBytesToRead (this will be received from caller) - + private byte[] ST25DV_CMD_READ_MESSAGE = { 0xAC, 0x02, 0x00, 0x00 }; //Command code, IC Mfg Code, Mailbox pointer(mostly this is 0), NumberofBytesToRead (this will be received from caller) + private byte[] ST25DV_CMD_MANAGE_GPO = { 0xA9, 0x02, 0x00 }; //Command code, IC Mfg Code, GPO value + public readonly byte GPO_MANAGE_SET_PULSE = 0x80; // Command code to set a pulse on the GPO pin (if enabled by FW in the Meter) + private CR95HF_Reader _CR95HF_Reader; private System.Timers.Timer _CycleTimeoutTimer = new System.Timers.Timer(); @@ -42,8 +44,8 @@ namespace Sensus.iPerl.NfcHandler {0x15 , "The specified block is protected in read" } }; - public event DelNfc_ST25DV_MessageHandler MessageEvent; - + public event DelNfc_ST25DV_MessageHandler MessageEvent; + public ST25DV_Device(CR95HF_Reader CR95HFReader) { _CR95HF_Reader = CR95HFReader; @@ -265,12 +267,39 @@ namespace Sensus.iPerl.NfcHandler return false; } + public bool ST25DV_WriteGPOManageCommand(byte regValue, bool logEnabled) + { + byte[] response = null; + ST25DV_CMD_MANAGE_GPO[2] = regValue; + + if (_CR95HF_Reader.CR95HF_SendRecv(ST25DV_CMD_MANAGE_GPO, out response)) + { + //Success - ResponseFlags = 0x00, success + //Error - ResponseFlags = 0x01, 1 byte error code + if (response[0] == 0x00) + { + if (logEnabled) + { + OnMessageEvent("Write GPO Manage: Success"); + } + return true; + } + else + { + if ((response[0] == 0x01) && (ST25DV_ErrorCodes.ContainsKey(response[1]))) + OnMessageEvent("Write GPO Manage: Failed with ST25DV error - " + ST25DV_ErrorCodes[response[1]]); + } + } + OnMessageEvent("Write GPO Manage: Failed with ST25DV Unidentified error"); + return false; + } + public bool ST25DV_WriteDynamicConfiguration(byte regAddress, byte regValue, bool logEnabled) { - byte[] response = null; + byte[] response = null; ST25DV_CMD_WRITE_DYNAMIC_CONFIG[2] = regAddress; - ST25DV_CMD_WRITE_DYNAMIC_CONFIG[3] = regValue; - + ST25DV_CMD_WRITE_DYNAMIC_CONFIG[3] = regValue; + if (_CR95HF_Reader.CR95HF_SendRecv(ST25DV_CMD_WRITE_DYNAMIC_CONFIG, out response)) { //Success - ResponseFlags = 0x00, success @@ -365,14 +394,11 @@ namespace Sensus.iPerl.NfcHandler { outBuffer[i] = response[1 + i]; } - //OnMessageEvent("Read Message: " + Tools.ByteArrayToHexString(outBuffer)); + OnMessageEvent("Read Message: " + Tools.BytesToHex(outBuffer)); return true; } - else - { - if ((response[0] == 0x01) && (ST25DV_ErrorCodes.ContainsKey(response[1]))) - OnMessageEvent("Read Message Failed: With ST25DV error - " + ST25DV_ErrorCodes[response[1]]); - } + if ((response[0] == 0x01) && ST25DV_ErrorCodes.ContainsKey(response[1])) + OnMessageEvent("Read Message Failed: With ST25DV error - " + ST25DV_ErrorCodes[response[1]]); } OnMessageEvent("Read Message Failed: With ST25DV Unidentified error"); return false; @@ -397,11 +423,8 @@ namespace Sensus.iPerl.NfcHandler //OnMessageEvent("Write Message: " + Tools.ByteArrayToHexString(inBuffer)); return true; } - else - { - if ((response[0] == 0x01) && (ST25DV_ErrorCodes.ContainsKey(response[1]))) - OnMessageEvent("Write Message Failed: With ST25DV error - " + ST25DV_ErrorCodes[response[1]]); - } + if ((response[0] == 0x01) && ST25DV_ErrorCodes.ContainsKey(response[1])) + OnMessageEvent("Write Message Failed: With ST25DV error - " + ST25DV_ErrorCodes[response[1]]); } OnMessageEvent("Write Message Failed: With ST25DV Unidentified error"); return false; diff --git a/NfcS5_DLL.csproj b/NfcS5_DLL.csproj index 3a96ef8b4..4bfc97b55 100644 --- a/NfcS5_DLL.csproj +++ b/NfcS5_DLL.csproj @@ -11,6 +11,7 @@ NfcS5_DLL v4.7.2 512 + true diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index d01464cea..7aec111dc 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("NfcS5_DLL")] -[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyCopyright("Copyright © 2024")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.14.0.0")] -[assembly: AssemblyFileVersion("1.14.0.0")] +[assembly: AssemblyVersion("1.18.0.0")] +[assembly: AssemblyFileVersion("1.18.0.0")]