585 lines
20 KiB
C#
585 lines
20 KiB
C#
using NA2WNFC;
|
|
using NfcC7_DLL.NfcHanler.Utils;
|
|
using Sensus;
|
|
using Sensus.Protocols.FlexNet.Serial;
|
|
using Sensus.Protocols.FlexNet.Serial.FNv2;
|
|
|
|
namespace NfcC7_DLL.NfcHanler
|
|
{
|
|
class NfcReader : ISerialConnection, IDisposable
|
|
{
|
|
public static string[] AvailableReaders { get { return NFCReader.GetAvailableReaders().ToArray(); } }
|
|
private NFCReader Reader;
|
|
private Thread InventoryThread;
|
|
private bool nfcTagDetected;
|
|
private byte[] rmaData;
|
|
private byte[] ndefData;
|
|
private NfcTargetDetails nfcTargetDetails;
|
|
|
|
public static string TimeFormatString = "yyyy-MM-dd HH:mm:ss.fffzz";
|
|
|
|
public int KeepAlive_S { set { if (value > delayResponseCountdown) { delayResponseCountdown = value; } } }
|
|
|
|
public bool NfcTagDetected
|
|
{
|
|
get
|
|
{
|
|
return nfcTagDetected;
|
|
}
|
|
set
|
|
{
|
|
if (value != nfcTagDetected)
|
|
{
|
|
nfcTagDetected = value;
|
|
OnTagEvent(new TagEventArgs() { Present = value });
|
|
}
|
|
}
|
|
}
|
|
|
|
public event EventHandler<TagEventArgs> TagEvent;
|
|
|
|
public byte[] NDEF { get { return ndefData; } }
|
|
|
|
public byte[] RMA { get { return rmaData; } }
|
|
|
|
public NfcTargetDetails NfcTargetDetails { get { return nfcTargetDetails; } }
|
|
|
|
protected virtual void OnTagEvent(TagEventArgs e)
|
|
{
|
|
EventHandler<TagEventArgs> handler = TagEvent;
|
|
handler?.Invoke(this, e);
|
|
}
|
|
|
|
public NfcReader(string name)
|
|
{
|
|
Reader = new NFCReader(name, 64, 128);
|
|
InitializeListener();
|
|
rmaData = new byte[0];
|
|
ndefData = new byte[0];
|
|
nfcTargetDetails = new NfcTargetDetails() { DeviceId = "", ProductType = "", ProductVersion = "" };
|
|
}
|
|
|
|
protected void InitializeListener()
|
|
{
|
|
receiveQueue = new BlockingQueue<ReceptionEventArgs<ISerialMessageFrame>>();
|
|
|
|
eventThread = ThreadHelpers.MakeThread("NFC RX", MessageReceivedLoop);
|
|
eventThread.IsBackground = true;
|
|
eventThread.Start();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Close();
|
|
|
|
Reader.ReleaseReader();
|
|
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
public void Open()
|
|
{
|
|
Reader.ConnectReader();
|
|
|
|
if (IsConnected)
|
|
{
|
|
lastActivity = DateTime.MinValue;
|
|
|
|
InventoryThread = ThreadHelpers.MakeThread("NFC Inventory", Inventory);
|
|
InventoryThread.IsBackground = true;
|
|
InventoryThread.Start();
|
|
}
|
|
}
|
|
|
|
public void Close()
|
|
{
|
|
nfcTargetDetails = new NfcTargetDetails() { DeviceId = "", ProductType = "", ProductVersion = "" };
|
|
|
|
if (IsConnected)
|
|
{
|
|
if (InventoryThread != null)
|
|
{
|
|
InventoryThread.Abort();
|
|
}
|
|
|
|
if (sendThread != null)
|
|
{
|
|
sendThread.Abort();
|
|
sendThread = null;
|
|
}
|
|
|
|
if (eventThread != null)
|
|
{
|
|
eventThread.Abort();
|
|
eventThread = null;
|
|
}
|
|
|
|
NfcTagDetected = false;
|
|
|
|
try
|
|
{
|
|
Reader.DisconnectReader();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
|
|
}
|
|
Reader.ReleaseReader();
|
|
}
|
|
}
|
|
|
|
public bool IsConnected
|
|
{
|
|
get { return Reader.IsConnected(); }
|
|
}
|
|
|
|
object objectLock = new Object();
|
|
|
|
public event EventHandler<ReceptionEventArgs<ISerialMessageFrame>> MessageReceived;
|
|
|
|
public event EventHandler<EventArgs> Disconnected;
|
|
|
|
public ClassicSerialMessageFrame SendFlexNetSerial(ISerialCommandFrame cmd, bool responseExpected, UInt32 timeoutMs)
|
|
{
|
|
ClassicSerialMessageFrame response = null;
|
|
|
|
return response;
|
|
}
|
|
|
|
public NA2WSerialFrame SendNa2wSerial(ISerialCommandFrame cmdFrame, bool responseExpected)
|
|
{
|
|
NA2WSerialFrame rxFrame = null;
|
|
|
|
if (String.IsNullOrEmpty(Reader.TagSerialNumber))
|
|
{
|
|
if (Reader.IsConnected())
|
|
{
|
|
lock (transactionInProgress)
|
|
{
|
|
// If no tag is found this is throwing system exception. Possiblity because
|
|
// in UI thread.
|
|
try
|
|
{
|
|
Reader.Inventory();
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!String.IsNullOrEmpty(Reader.TagSerialNumber))
|
|
{
|
|
byte[] response = null;
|
|
lock (transactionInProgress)
|
|
{
|
|
if (responseExpected)
|
|
{
|
|
response = Reader.SendMailboxMessage(cmdFrame.ToBytes(), TimeSpan.FromSeconds(6));
|
|
}
|
|
else
|
|
{
|
|
// Even though response not expected, sniff for 1 second
|
|
response = Reader.SendMailboxMessage(cmdFrame.ToBytes(), TimeSpan.FromSeconds(1));
|
|
}
|
|
}
|
|
|
|
lastActivity = DateTime.Now;
|
|
|
|
if (response != null)
|
|
{
|
|
try
|
|
{
|
|
rxFrame = NA2WSerialFrame.Parse(response);
|
|
ReceptionEventArgs<ISerialMessageFrame> eventFrame = new ReceptionEventArgs<ISerialMessageFrame>() { Frame = rxFrame };
|
|
MessageReceived(this, eventFrame);
|
|
}
|
|
catch
|
|
{
|
|
Utility.Log.Write(response.ToHexString());
|
|
}
|
|
|
|
// Response. Could be more. Extend polling for 2 seconds. Trigger read.
|
|
KeepAlive_S = 2;
|
|
InventoryThread.Interrupt();
|
|
}
|
|
else
|
|
{
|
|
// No response, poll for commulative 10 seconds
|
|
KeepAlive_S = (responseExpected ? 4 : 9);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Utility.Log.Write("No tag found." + System.Environment.NewLine);
|
|
}
|
|
|
|
return rxFrame;
|
|
}
|
|
|
|
public NA2WSerialFrame SendNa2wSerial(ISerialCommandFrame cmdFrame, bool responseExpected, UInt32 timeoutMs)
|
|
{
|
|
NA2WSerialFrame rxFrame = null;
|
|
|
|
if (String.IsNullOrEmpty(Reader.TagSerialNumber))
|
|
{
|
|
if (Reader.IsConnected())
|
|
{
|
|
lock (transactionInProgress)
|
|
{
|
|
// If no tag is found this is throwing system exception. Possiblity because
|
|
// in UI thread.
|
|
try
|
|
{
|
|
Reader.Inventory();
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!String.IsNullOrEmpty(Reader.TagSerialNumber))
|
|
{
|
|
byte[] response = null;
|
|
lock (transactionInProgress)
|
|
{
|
|
if (responseExpected)
|
|
{
|
|
response = Reader.SendMailboxMessage(cmdFrame.ToBytes(), TimeSpan.FromMilliseconds(timeoutMs));
|
|
}
|
|
else
|
|
{
|
|
// Even though response not expected, sniff for 1 second
|
|
response = Reader.SendMailboxMessage(cmdFrame.ToBytes(), TimeSpan.FromSeconds(1));
|
|
}
|
|
}
|
|
|
|
lastActivity = DateTime.Now;
|
|
|
|
if (response != null)
|
|
{
|
|
try
|
|
{
|
|
rxFrame = NA2WSerialFrame.Parse(response);
|
|
ReceptionEventArgs<ISerialMessageFrame> eventFrame = new ReceptionEventArgs<ISerialMessageFrame>() { Frame = rxFrame };
|
|
MessageReceived(this, eventFrame);
|
|
}
|
|
catch
|
|
{
|
|
Utility.Log.Write(response.ToHexString());
|
|
}
|
|
|
|
// Response. Could be more. Extend polling for 2 seconds. Trigger read.
|
|
KeepAlive_S = 2;
|
|
InventoryThread.Interrupt();
|
|
}
|
|
else
|
|
{
|
|
// No response, poll for commulative 10 seconds
|
|
KeepAlive_S = (responseExpected ? 4 : 9);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Utility.Log.Write("No tag found." + System.Environment.NewLine);
|
|
}
|
|
|
|
return rxFrame;
|
|
}
|
|
|
|
public NA2WSerialFrame SendNa2wSerial(ISerialCommandFrame cmdFrame, byte responseCommmandCode)
|
|
{
|
|
NA2WSerialFrame rxFrame = null;
|
|
|
|
if (String.IsNullOrEmpty(Reader.TagSerialNumber))
|
|
{
|
|
if (Reader.IsConnected())
|
|
{
|
|
lock (transactionInProgress)
|
|
{
|
|
// If no tag is found this is throwing system exception. Possiblity because
|
|
// in UI thread.
|
|
try
|
|
{
|
|
Reader.Inventory();
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!String.IsNullOrEmpty(Reader.TagSerialNumber))
|
|
{
|
|
byte[] response = null;
|
|
lock (transactionInProgress)
|
|
{
|
|
response = Reader.SendMailboxMessage(cmdFrame.ToBytes(), TimeSpan.FromSeconds(6));
|
|
}
|
|
|
|
lastActivity = DateTime.Now;
|
|
|
|
if (response != null)
|
|
{
|
|
try
|
|
{
|
|
rxFrame = NA2WSerialFrame.Parse(response);
|
|
if (rxFrame.CommandCode != responseCommmandCode)
|
|
{
|
|
ReceptionEventArgs<ISerialMessageFrame> eventFrame = new ReceptionEventArgs<ISerialMessageFrame>() { Frame = rxFrame };
|
|
MessageReceived(this, eventFrame);
|
|
rxFrame = null;
|
|
|
|
// Response. Could be more. Extend polling for 2 seconds. And read again
|
|
KeepAlive_S = 2;
|
|
InventoryThread.Interrupt();
|
|
}
|
|
else
|
|
{
|
|
// No response, poll for commulative 10 seconds
|
|
KeepAlive_S = 4;
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Utility.Log.Write("No tag found." + System.Environment.NewLine);
|
|
}
|
|
|
|
return rxFrame;
|
|
}
|
|
|
|
|
|
public void SerialMessageFound(object sender, ReceptionEventArgs<ISerialMessageFrame> e)
|
|
{
|
|
receiveQueue.Enqueue(e);
|
|
}
|
|
|
|
public List<NdefRecord> GetNdefRecords()
|
|
{
|
|
List<NdefRecord> records = new List<NdefRecord>();
|
|
if (Reader != null && Reader.IsConnected())
|
|
{
|
|
try
|
|
{
|
|
lock (transactionInProgress)
|
|
{
|
|
records = Reader.Read_Ndef_Records();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utility.Log.Write($"{ex.Message}\n{ex.StackTrace}\n");
|
|
}
|
|
}
|
|
return records;
|
|
}
|
|
public byte[] Get_Ndef_Data()
|
|
{
|
|
if (Reader != null && Reader.IsConnected())
|
|
{
|
|
try
|
|
{
|
|
lock (transactionInProgress)
|
|
{
|
|
ndefData = Reader.Read_Ndef_RawData();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utility.Log.Write($"{ex.Message}\n{ex.StackTrace}\n");
|
|
}
|
|
}
|
|
return ndefData;
|
|
}
|
|
|
|
public byte[] Get_RMA_Data()
|
|
{
|
|
if (Reader != null && Reader.IsConnected())
|
|
{
|
|
try
|
|
{
|
|
lock (transactionInProgress)
|
|
{
|
|
rmaData = Reader.Read_RMA_RawData(false, string.Empty);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utility.Log.Write($"{ex.Message}\n{ex.StackTrace}\n");
|
|
}
|
|
}
|
|
return rmaData;
|
|
}
|
|
|
|
private void MessageReceivedLoop()
|
|
{
|
|
while (true)
|
|
{
|
|
ReceptionEventArgs<ISerialMessageFrame> m = receiveQueue.Dequeue();
|
|
|
|
try
|
|
{
|
|
MessageReceived.Raise(this, m);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Utility.Log.Write(String.Format("FrameReceived event handler threw: {0}", e));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Inventory()
|
|
{
|
|
while (true)
|
|
{
|
|
if (delayResponseCountdown <= 0)
|
|
{
|
|
try
|
|
{
|
|
if (Reader.IsConnected())
|
|
{
|
|
if ((DateTime.Now - lastActivity).TotalSeconds > 4) // Timestamp based check
|
|
{
|
|
lock (transactionInProgress)
|
|
{
|
|
Reader.Inventory();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch { }
|
|
|
|
|
|
if (String.IsNullOrEmpty(Reader.TagSerialNumber) &&
|
|
NfcTagDetected == true)
|
|
{
|
|
Utility.Log.Write(DateTime.Now.ToString(TimeFormatString) + " : " + "Disconnected from tag.\n");
|
|
nfcTargetDetails = new NfcTargetDetails() { DeviceId = "", ProductType = "", ProductVersion = "" };
|
|
NfcTagDetected = false; // This uses nfcTargetDetails.
|
|
tagSerialNumber = "";
|
|
}
|
|
else if (!String.IsNullOrEmpty(Reader.TagSerialNumber) &&
|
|
!tagSerialNumber.Equals(Reader.TagSerialNumber))
|
|
{
|
|
// Transitioning from disconnected to connected or tag serial number has changed
|
|
tagSerialNumber = Reader.TagSerialNumber;
|
|
|
|
// Read NDEF record to logging.
|
|
String productType = "";
|
|
String productVersion = "";
|
|
String sfID = "";
|
|
try
|
|
{
|
|
lock (transactionInProgress)
|
|
{
|
|
productType = Reader.Read_Ndef_Product_Type();
|
|
productType = (!String.IsNullOrEmpty(productType) ? productType.Trim() : "No PT NDEF message");
|
|
productVersion = Reader.Read_Ndef_Product_Type_Version();
|
|
productVersion = (!String.IsNullOrEmpty(productVersion) ? (" " + productVersion.Trim()) : "");
|
|
sfID = Reader.Read_Ndef_ID1();
|
|
sfID = (!String.IsNullOrEmpty(sfID) ? (" " + sfID.Trim()) : "");
|
|
ndefData = Reader.Read_Ndef_RawData();
|
|
rmaData = Reader.Read_RMA_RawData(false, string.Empty);
|
|
}
|
|
}
|
|
catch { }
|
|
|
|
Utility.Log.Write(DateTime.Now.ToString(TimeFormatString) + " : " + String.Format("Connected to NFC tag, {0} ({1}{2}{3}).\n", Reader.TagSerialNumber, productType, productVersion, sfID));
|
|
try
|
|
{
|
|
nfcTargetDetails = new NfcTargetDetails()
|
|
{
|
|
DeviceId = sfID.Split(':')[1],
|
|
ProductType = productType.Split(':')[1],
|
|
ProductVersion = productVersion.Split(':')[1]
|
|
};
|
|
NfcTagDetected = true; // This uses nfcTargetDetails.
|
|
}
|
|
catch { }
|
|
|
|
}
|
|
|
|
try
|
|
{
|
|
Thread.Sleep(TimeSpan.FromSeconds(5));
|
|
}
|
|
catch
|
|
{
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
if (Reader.IsConnected())
|
|
{
|
|
delayResponseCountdown--;
|
|
|
|
byte[] response = null;
|
|
lock (transactionInProgress)
|
|
{
|
|
response = Reader.ReadMailboxMessage(TimeSpan.FromSeconds(0)); ;
|
|
}
|
|
|
|
lastActivity = DateTime.Now;
|
|
|
|
if (response != null)
|
|
{
|
|
try
|
|
{
|
|
NA2WSerialFrame rxFrame = NA2WSerialFrame.Parse(response);
|
|
ReceptionEventArgs<ISerialMessageFrame> eventFrame = new ReceptionEventArgs<ISerialMessageFrame>() { Frame = rxFrame };
|
|
SerialMessageFound(this, eventFrame);
|
|
}
|
|
catch { }
|
|
|
|
// Response. Could be more. Extend polling for 2 seconds.
|
|
KeepAlive_S = 2; ;
|
|
}
|
|
}
|
|
}
|
|
catch { }
|
|
|
|
try
|
|
{
|
|
Thread.Sleep(TimeSpan.FromSeconds(1));
|
|
}
|
|
catch
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private DateTime lastActivity;
|
|
private Thread sendThread;
|
|
private Thread eventThread;
|
|
private BlockingQueue<ReceptionEventArgs<ISerialMessageFrame>> receiveQueue;
|
|
private object transactionInProgress = new object();
|
|
private int delayResponseCountdown = 0;
|
|
private String tagSerialNumber = "";
|
|
}
|
|
|
|
public class TagEventArgs : EventArgs
|
|
{
|
|
public bool Present { get; set; }
|
|
}
|
|
|
|
public class NfcTargetDetails
|
|
{
|
|
public string TagId { get; set; }
|
|
public string ProductType { get; set; }
|
|
public string ProductVersion { get; set; }
|
|
public string DeviceId { get; set; }
|
|
}
|
|
}
|