Files
tbf/NfcC7_DLL/NfcHanler/NfcReader.cs
T

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; }
}
}