C# RFID windows 服務 串口方式


話說RFID以前很火所以整理一下一年前自己處理的RFID程序,放源碼.

一開始覺得他是個很神奇的東西。 包含串口通訊和網絡通訊。 由於網絡通訊設備太貴,所以國內的設備基本上都是在外置一個比較便宜的模塊在里面。  

本案例應該適用於大多數的RFID模塊。

首先我們先放上RFID API:如下 

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace Rfid
{
    public class EPCSDKHelper
    {
        [DllImport("EPCSDK.dll")]
        public static extern IntPtr OpenComm(int portNo);

        [DllImport("EPCSDK.dll")]
        public static extern void CloseComm(IntPtr hCom);

        [DllImport("EPCSDK.dll")]
        public static extern bool ReadFirmwareVersion(IntPtr hCom, out int main, out int sub, byte ReaderAddr);

        [DllImport("EPCSDK.dll")]
        public static extern bool GetReaderParameters(IntPtr hCom, int addr, int paramNum, byte[] parms, byte ReaderAddr);
        
        [DllImport("EPCSDK.dll")]
        public static extern bool SetReaderParameters(IntPtr hCom, int addr, int paramNum, byte[] parms, byte ReaderAddr);

        [DllImport("EPCSDK.dll")]
        public static extern bool StopReading(IntPtr hCom, byte ReaderAddr);

        [DllImport("EPCSDK.dll")]
        public static extern bool ResumeReading(IntPtr hCom, byte ReaderAddr);

        [DllImport("EPCSDK.dll")]
        public static extern bool IdentifySingleTag(IntPtr hCom, byte[] tagId, byte[] antennaNo, byte ReaderAddr);

        [DllImport("EPCSDK.dll")]
        public static extern bool IdentifyUploadedSingleTag(IntPtr hCom, byte[] tagId, byte[] devNos, byte[] antennaNo);

        [DllImport("EPCSDK.dll")]
        public static extern bool IdentifyUploadedMultiTags(IntPtr hCom, out byte tagNum, byte[] tagIds, byte[] devNos, byte[] antennaNos);

        [DllImport("EPCSDK.dll")]
        public static extern bool ReadTag(IntPtr hCom, byte memBank, byte address, byte length, byte[] data, byte ReaderAddr);

        [DllImport("EPCSDK.dll")]
        public static extern bool WriteTagSingleWord(IntPtr hCom, byte memBank, byte address, byte data1, byte data2, byte ReaderAddr);

        [DllImport("EPCSDK.dll")]
        public static extern bool FastWriteTagID(IntPtr hCom, int bytesNum, byte[] bytes, byte ReaderAddr);

        [DllImport("EPCSDK.dll")]
        public static extern bool FastWriteTagID_Lock(IntPtr hCom, int bytesNum, byte[] bytes, byte ReaderAddr);

        [DllImport("EPCSDK.dll")]
        public static extern bool InitializeTag(IntPtr hCom, byte ReaderAddr);

        [DllImport("EPCSDK.dll")]
        public static extern bool LockPassWordTag(IntPtr hCom, byte passwd1, byte passwd2, byte passwd3, byte passwd4, byte lockType, byte ReaderAddr);

        [DllImport("EPCSDK.dll")]
        public static extern bool UnlockPassWordTag(IntPtr hCom, byte passwd1, byte passwd2, byte passwd3, byte passwd4, byte lockType, byte ReaderAddr);

        [DllImport("EPCSDK.dll")]
        public static extern bool KillTag(IntPtr hCom, byte passwd1, byte passwd2, byte passwd3, byte passwd4, byte ReaderAddr);
    }
}

  我們看到OpenComm他還是一串口方式打開的。

  我們要記錄每個設備的信息所以我們需要一個設備類

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using RfidService.Common;

namespace Rfid
{
    public class RfidDevice
    {
        /// <summary>
        /// 開啟監聽現成
        /// </summary>
        private Thread _mThread = null;

        /// <summary>
        /// 暫停事件
        /// </summary>
        private readonly ManualResetEvent _mManualReset = null;

        /// <summary>
        /// 串口號
        /// </summary>
        private readonly int _comNo = 0;

        /// <summary>
        /// 時間間隔
        /// </summary>
        private readonly int _timeTick = 0;

        /// <summary>
        /// 是否多卡讀取
        /// </summary>
        private bool _multiFlag = false;

        /// <summary>
        /// RFID數據
        /// </summary>
        private readonly List<byte[]> _data = new List<byte[]>();

        /// <summary>
        /// 數據鎖
        /// </summary>
        private readonly object _dataLock = new object();

        /// <summary>
        /// 錯誤數量
        /// </summary>
        private int _errorCount = 0;

        /// <summary>
        /// 只讀 串口號
        /// </summary>
        public int ComNo 
        { 
            get 
            { 
                return _comNo; 
            } 
        }

        /// <summary>
        /// 串口句柄
        /// </summary>
        public IntPtr ComHadle { set; get; }

        /// <summary>
        /// 只讀 時間間隔 毫秒級 
        /// </summary>
        public int TimeTick 
        {
            get 
            {
                return _timeTick;
            }
        }

        /// <summary>
        /// 是否多卡標志
        /// </summary>
        public bool MultiFlag { set { _multiFlag = value; } get { return _multiFlag; } }

        /// <summary>
        /// 暫停讀取標志
        /// </summary>
        public bool StopReadFlag { set; get; }

        /// <summary>
        /// 出入串口
        /// </summary>
        public PassCom PassCom { set; get; }

        /// <summary>
        /// 構造函數
        /// </summary>
        /// <param name="comNo"></param>
        /// <param name="sleepTime"></param>
        public RfidDevice(int comNo,int sleepTime)
        {
            _comNo = comNo;
            _timeTick = sleepTime;
            _mManualReset = new ManualResetEvent(true);
            ComHadle = EPCSDKHelper.OpenComm(_comNo);
            if (ComHadle == new IntPtr())
            {
                //輸出系統日志
                //throw new Exception("打開串口失敗!");

                LogInfo.Error("打開串口:" + comNo + "失敗!" );
            }
        }

        /// <summary>
        /// 構造函數
        /// </summary>
        /// <param name="comNo"></param>
        /// <param name="sleepTime"></param>
        /// <param name="multiFlag"></param>
        public RfidDevice(int comNo, int sleepTime,bool multiFlag)
        {
            _comNo = comNo;
            _timeTick = sleepTime;
            MultiFlag = multiFlag;
            _mManualReset = new ManualResetEvent(true);
            ComHadle = EPCSDKHelper.OpenComm(_comNo);
            if (ComHadle == new IntPtr())
            {
                //輸出系統日志
                //throw new Exception("打開串口失敗!");
                LogInfo.Error("打開串口:" + comNo + "失敗!");
            }
        }

        /// <summary>
        /// 構造函數
        /// </summary>
        /// <param name="comNo"></param>
        /// <param name="sleepTime"></param>
        /// <param name="multiFlag"></param>
        /// <param name="passCom"></param>
        public RfidDevice(int comNo, int sleepTime, bool multiFlag,PassCom passCom)
        {
            _comNo = comNo;
            _timeTick = sleepTime;
            _multiFlag = multiFlag;
            MultiFlag = multiFlag;
            _mManualReset = new ManualResetEvent(true);
            this.PassCom = passCom;
            ComHadle = EPCSDKHelper.OpenComm(_comNo);
#if DEBUG
            Console.WriteLine("串口號:" + this.ComNo.ToString() + " - " + ComHadle.ToString());
#endif
            if (ComHadle == new IntPtr())
            {
                //輸出系統日志
                //throw new Exception("打開串口失敗!");
                LogInfo.Error("打開串口:" + comNo + "失敗!");
            }
        }

        /// <summary>
        /// 關閉串口
        /// </summary>
        public void CloseComm()
        {
            EPCSDKHelper.CloseComm(this.ComHadle);
            LogInfo.Info("關閉串口:" + this.ComNo );
        }
        
        /// <summary>
        /// 開始讀取
        /// </summary>
        public void Start()
        {
            if (_mThread != null) return;
            _mThread = new Thread(GetRfidTag) {IsBackground = true};
            _mThread.Start();
        }

        /// <summary>
        /// 暫停
        /// </summary>
        public void ReStart()
        {
            _mManualReset.Set();
        }

        /// <summary>
        /// 繼續
        /// </summary>
        public void Stop()
        {
            _mManualReset.Reset();
        }

        /// <summary>
        /// 獲取RFID標簽現成
        /// </summary>
        private void GetRfidTag()
        {
            while(true)
            {
                GcCollect();
                try
                {
                    Monitor.Enter(this._dataLock);
                    _mManualReset.WaitOne();
                    byte[] ids;
                    byte[] devNos;
                    byte[] antennaNos;
                    if (this._multiFlag)
                    {
                        ids = new byte[12 * 200];
                        devNos = new byte[200];
                        antennaNos = new byte[200];
                        //處理多卡讀取模式
                        byte idNum = 0;
                        if (EPCSDKHelper.IdentifyUploadedMultiTags(this.ComHadle, out idNum, ids, devNos, antennaNos))
                        {
                            _errorCount = 0;
                            var tmpids = new byte[idNum * 12];
                            Array.Copy(ids, 0, tmpids, 0, tmpids.Length);
                            this._data.Add(tmpids);
#if DEBUG
                            Console.WriteLine("串口號:"+this.ComNo.ToString() + " - " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.yyy") + " - 02 - " + TextEncoder.ByteArrayToHexString(ids));
                            LogInfo.Info("串口號:" + this.ComNo.ToString() + " - " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.yyy") + " - 02 - " + TextEncoder.ByteArrayToHexString(ids));
#endif
                        }
                    }
                    else
                    {
                        ids = new byte[12];
                        devNos = new byte[1];
                        antennaNos = new byte[1];
                        //處理單卡讀取模式
                        if (EPCSDKHelper.IdentifyUploadedSingleTag(this.ComHadle, ids, devNos, antennaNos))
                        {
                            _errorCount = 0;
                            this._data.Add(ids);
#if DEBUG
                            Console.WriteLine("串口號:" + this.ComNo.ToString() + " - " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.yyy") + " - 01 - " + TextEncoder.ByteArrayToHexString(ids));
                            LogInfo.Info("串口號:" + this.ComNo.ToString() + " - " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.yyy") + " - 01 - " + TextEncoder.ByteArrayToHexString(ids));
#endif
                        }
                    }
                }
                catch (Exception er)
                {
#if DEBUG
                    Console.WriteLine("串口號:" + this.ComNo.ToString() + " - " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.yyy") + " Error: " + er.Message);
                    LogInfo.Error("串口號:" + this.ComNo.ToString() + " - " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.yyy") + " Error: " + er.Message);
#endif
                    _errorCount++;
                    if (_errorCount > 10)
                    {
                        //設備復位
                    }
                }
                finally
                {
                    Monitor.Exit(this._dataLock);
                }
                Thread.Sleep(this._timeTick);
            }
        }

        /// <summary>
        /// 獲取RFID數據標簽
        /// </summary>
        /// <returns></returns>
        public IList<byte[]> GetData()
        {
            try
            {
                Monitor.Enter(this._dataLock);
                GC.WaitForPendingFinalizers();
                GC.Collect();
                GC.WaitForPendingFinalizers();
                var tmpData = new List<byte[]>();
                tmpData.AddRange(_data);
                _data.Clear();
#if DEBUG
                Console.WriteLine("串口號:" + this.ComNo.ToString() + " - " + "_tmpData:" + tmpData.Count + "  _data:" + _data.Count);
                LogInfo.Info("串口號:" + this.ComNo.ToString() + " - " + "_tmpData:" + tmpData.Count + "  _data:" + _data.Count);
#endif
                return tmpData;
            }
            finally
            {
                Monitor.Exit(this._dataLock);
            }
        }

        /// <summary>
        /// 數據回收
        /// </summary>
        private static void GcCollect()
        {
            GC.WaitForFullGCComplete();
            GC.Collect();
            GC.WaitForFullGCComplete();
        }

    }
}

  當然我們還需要一個設備管理類作為設備的監管。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RfidService;
using System.Diagnostics;
using System.Threading;
using RfidService.Common;

namespace Rfid
{
    public class RfidDevices : IDisposable
    {
        /// <summary>
        /// RFID設備集合
        /// </summary>
        private IList<RfidDevice> _lstRfidDevice = new List<RfidDevice>();
        private readonly RfidDataContext _oRfidDataContext = new RfidDataContext();
        /// <summary>
        /// 添加RFID設備
        /// </summary>
        /// <param name="rfidDevice"></param>
        public void Add(RfidDevice rfidDevice)
        {
            this._lstRfidDevice.Add(rfidDevice);
        }

        /// <summary>
        /// 移除RFID設備
        /// </summary>
        /// <param name="rfidDevice"></param>
        public void Remove(RfidDevice rfidDevice)
        {
            foreach (var o in _lstRfidDevice.Where(o => o.ComHadle == rfidDevice.ComHadle &&
                                                        o.ComNo == rfidDevice.ComNo))
            {
                _lstRfidDevice.Remove(o);
                break;
            }
        }

        public void DeviceClose()
        {
            foreach (var o in _lstRfidDevice)
            {
                try
                {
                    o.CloseComm();
                }
                catch(Exception er)
                {
                    LogInfo.Error("設備監聽關閉失敗:" + o.ComNo);
                    LogInfo.Error("設備監聽關閉失敗:" + er.Message);
                }
            }
        }

        public IList<RfidDevice> GetDevices()
        {
            return _lstRfidDevice;
        }

        readonly object _oLock = new object();
        /// <summary>
        /// 獲取所有設備數據
        /// </summary>
        /// <returns></returns>
        public void GetData()
        {
            try
            {
                Monitor.Enter(_oLock);
                var sw = new Stopwatch();
                sw.Start();
                var lstByteArray = new List<byte[]>();
                var serviceDateTime = DateTime.Now;
                foreach (var o in _lstRfidDevice)
                {
                    try
                    {
                        var lstByt = o.GetData(); 
                        foreach (var byt in lstByt)
                        {
                            for (var i = 0; i < byt.Length; i = i + 12)
                            {
                                var buffer = new byte[4]; 
                                GcCollect();
                                Array.Copy(byt, i + 8, buffer, 0, 4);
                                var id = ((buffer[0]) + (buffer[1] << 8) + (buffer[2] << 16) + (buffer[3] << 32)).ToString();
								//處理自己的業務把
                            }
                        }
  
                    }
                    catch (Exception er)
                    {
                        Console.WriteLine(er.Message + "\t\n" + er.StackTrace.ToString());
                        LogInfo.Info(er.Message);
                        LogInfo.Info(er.StackTrace.ToString());
                    }
                }
                sw.Stop();
                Console.WriteLine("操作數據庫執行時間:" + sw.ElapsedMilliseconds.ToString());
                LogInfo.Info("操作數據庫執行時間:"  + sw.ElapsedMilliseconds.ToString());
            }
            finally
            {
                Monitor.Exit(_oLock);
            }
        }

        public void Dispose()
        {
            _lstRfidDevice.Clear();
            _lstRfidDevice = null;
            GcCollect();
        }

        public void GcCollect()
        {
            GC.WaitForPendingFinalizers();
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }
}

  通過以上幾個類我們可以對設備的記錄讀寫了。 在設備處理方法中你可以自行處理自己的業務邏輯。

  其實從整體上看RFID的處理還是很簡單的。 跟處理串口沒什么卻別。發送數據-> 讀取接收的數據->解析->處理業務入庫。 

  

  分享是種美德,要提倡!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM