话说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的处理还是很简单的。 跟处理串口没什么却别。发送数据-> 读取接收的数据->解析->处理业务入库。 

  

  分享是种美德,要提倡!