package com.youchain.rfid;

import com.uhf.api.cls.*;
import com.uhf.api.cls.Reader.*;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Vector;

public class LongTermAsyncRead extends JFrame{
	Vector<String> vt=new Vector<String>();
	JButton jbt1;
	JButton jbt2;
	JList jlist;
	ReaderExceptionChecker rechecker = new ReaderExceptionChecker(3, 60);

	public  LongTermAsyncRead(int h,int w)
	{ super();

		Container coter=this.getContentPane();
		this.setLayout(null);

		jbt1=new JButton("开始盘存");
		jbt1.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent arg0) {
				vt.clear();
				// TODO Auto-generated method stub
				if (StartReadTags()!= READER_ERR.MT_OK_ERR)
				{
					MessageBox("开始盘存失败");
					return;
				}
			}

		});

		jbt2=new JButton("停止盘存");
		jbt2.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent e) {
				System.out.println("盘存打印:"+vt);
				// TODO Auto-generated method stub
				if (rdr.StopReading() != READER_ERR.MT_OK_ERR)
				{
					MessageBox("停止盘存失败");
					return;
				}
			}

		});

		jlist=new JList();

		coter.add(jbt1);
		coter.add(jbt2);

		coter.add(jlist);

		int stx=50,sty=20,ey=20,bx=100,by=25;
		jbt1.setBounds(stx, sty, bx, by);
		jbt2.setBounds(stx, sty+ey+by, bx, by);

		jlist.setBounds(jbt1.location().x+jbt1.size().width+50, jbt1.location().y,
				400, 200);

		// this.setContentPane(coter);

		this.setBounds(0, 0, w, h);
		this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		this.setVisible(true);

		if(OpenReader()!=READER_ERR.MT_OK_ERR)
		{   MessageBox("初始化读写器失败,请检查设备地址以及类型，重新打开");
			return;
		}

		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				if(rdr!=null)
				{
					rdr.StopReading();
					rdr.CloseReader();
				}
				System.exit(0);
			}
		});
	}

	void MessageBox(String mes)
	{
		JOptionPane.showMessageDialog(null, mes, "消息提示", JOptionPane.INFORMATION_MESSAGE);

	}

	ReadListener RL=new ReadListener()
	{

		@Override
		public void tagRead(Reader r, final TAGINFO[] tag) {
			// TODO Auto-generated method stub
			//可以对读到的标签做进一步的读,写,锁和GPIO等操作******************************
		/*
		//以下示例写入两个块的数据到盘存到的标签的USER区中。
	    //注：只有在非高速盘存模式下才可以进行其它的标签操作，高速盘存模式下禁
	    //止再进行其它标签操作，否则盘存操作将被终止，其它的标签操作也不会成功。
		//但GPIO的操作是例外，不论哪种盘存模式都可以在此处操作GPIO
		TagFilter_ST oldfilter=rdr.new TagFilter_ST();
		byte[] wdata=new byte[4];
		wdata[0] = 0x12;
		wdata[1] = 0x34;
		wdata[2] = 0x56;
		wdata[3] = 0x78;
		READER_ERR er = READER_ERR.MT_OK_ERR;
		//先将盘存的过滤条件保存，因为对标签进行写操作的时候也需要设置过滤条件，
		//此过滤条件可能和盘存的过滤条件不同，在完成写操作后还需要将盘存的过滤
		//条件恢复。不用检查返回值，不会失败

		er=rdr.ParamGet(Mtr_Param.MTR_PARAM_TAG_FILTER, oldfilter);

		TagFilter_ST newfilter=rdr.new TagFilter_ST();
		newfilter.bank=1;
		newfilter.fdata=tag[0].EpcId;
		newfilter.flen=tag[0].Epclen*8;
		newfilter.isInvert=0;
		newfilter.startaddr=32;

		//设置写标签操作时的过滤条件（以标签的EPC码为过滤条件）
		er=rdr.ParamSet(Mtr_Param.MTR_PARAM_TAG_FILTER, newfilter);
		//一般使用标签被盘存到时的天线编号作为进一步操作的天线
		er = rdr.WriteTagData(tag[0].AntennaID, (char)3, 0, wdata, 4, null, (short)1000);
		if (er != READER_ERR.MT_OK_ERR)
		{
			//操作有可能失败（很多原因可能造成操作失败，常见的比如标签速度过快，
			//已经不在天线场内）
		}
		if (oldfilter.flen == 0) //表示盘存时没有设置过滤条件
			rdr.ParamSet(Mtr_Param.MTR_PARAM_TAG_FILTER, null);
		else //恢复盘存时的过滤条件
			rdr.ParamSet(Mtr_Param.MTR_PARAM_TAG_FILTER, oldfilter);

		//设置GPO1为1
		//*
		if (rdr.SetGPO(1, 1) != READER_ERR.MT_OK_ERR)
		{
			//操作有可能失败,比如由于断网
		}
		//*/
			SwingUtilities.invokeLater(new Runnable(){
				@Override
				public void run() {
					//System.out.println("update ui ...");
					for(int i=0;i<tag.length;i++)
					{
						if(tag[i].EmbededDatalen==0)
							vt.add(Reader.bytes_Hexstr(tag[i].EpcId));
						else
							vt.add(Reader.bytes_Hexstr(tag[i].EpcId)+" "+Reader.bytes_Hexstr(tag[i].EmbededData));
					}
					// 去重
					HashSet set = new HashSet(vt);
					vt= new Vector(set);

					jlist.setListData(vt);
				}
			});
			//*/
		}

	};
	ReadExceptionListener REL=new ReadExceptionListener()
	{

		@Override
		public void tagReadException(Reader r, final READER_ERR re) {

			//如果需要可在此处记录异常日志
			System.out.println(r.GetReaderAddress() + "--异常信息:" + re.toString());
			//判断是否异常发生过于频繁
			if (rechecker.IsTrigger())
			{
				// TODO Auto-generated method stub
				SwingUtilities.invokeLater(new Runnable(){
					@Override
					public void run() {
						MessageBox("读写器异常太过频繁,错误信息:"+re.toString());
					}
				});

				return;
			}
			else
				rechecker.AddErr();

			//尝试重新连接读写器并启动盘存操作，如果5次均失败则弹出提示
			//尝试重新连接读写器并启动盘存操作，如果5次均失败则弹出提示
			READER_ERR resume_err = READER_ERR.MT_OK_ERR;
			for (int i = 0; i < 5; ++i)
			{
				resume_err = OpenReader();
				if (resume_err == READER_ERR.MT_OK_ERR)
				{
					resume_err = StartReadTags();
					if (resume_err == READER_ERR.MT_OK_ERR)
						break;
				}
				try {
					Thread.sleep(4000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

			if (resume_err != READER_ERR.MT_OK_ERR)
			{
				//如果需要可在此处记录异常日志

				SwingUtilities.invokeLater(new Runnable(){
					@Override
					public void run() {
						MessageBox("重连读写器失败");
					}
				});
			}
		}

	};

	GpiTriggerListener GTL=new GpiTriggerListener()
	{

		@Override
		public void GpiTrigger(Reader r, GpiInfo_ST gist,int id) {
			// TODO Auto-generated method stub
			System.out.println(r.GetReaderAddress());

			for (int i = 0; i < gist.gpiCount; ++i)
			{
				System.out.println(gist.gpiStats[i].GpiId+" "+gist.gpiStats[i].State+" "+id);
			}
		}

	};

	GpiTriggerBoundaryListener GTBL=new GpiTriggerBoundaryListener()
	{

		@Override
		public void GpiTriggerBoundary(Reader r, GpiTriggerBoundaryType btype,
									   GpiTriggerBoundaryReasonType reason) {
			// TODO Auto-generated method stub
			System.out.println(r.GetReaderAddress());

			System.out.println(btype+" "+reason);
		}

	};

	Reader rdr = null;
	READER_ERR OpenReader()
	{
		READER_ERR err = READER_ERR.MT_OK_ERR;
		if (rdr != null)
		{
			rdr.CloseReader();
			rdr=null;
		}
		//初始化读写器实例************************************************************
		//当使用设备的串口进行连接的时候，InitReader_Notype函数的第一个参数也可
		//能是串口号（例如com1）当设备仅有一个天线端口时（例如一体机或者发卡器），
		//InitReader_Notype函数的第二个参数也可能为1
		//读写器出厂默认IP为192.168.1.100   com4
		int portnum = 4;  //注意是读写器天线端口数，不是已连接数量
		rdr=new Reader();
		err = rdr.InitReader_Notype("192.168.0.224",4);
		err = rdr.ParamSet(Reader.Mtr_Param.MTR_PARAM_RF_MAXPOWER, new int[]{0});

		System.out.println("connect:"+err.toString());
		if (err != READER_ERR.MT_OK_ERR)
			return err;
		//****************************************************************************

		//以下为必须要设置的参数和事件回调处理函数************************************
		//设置读写器发射功率,本例设置为最大发射功率，可根据实际情况调整,
		//一般来说，功率越大则识别距离越远

		//获取读写器最大发射功率
		int[] maxpower=new int[1];
		err=rdr.ParamGet(Mtr_Param.MTR_PARAM_RF_MAXPOWER, maxpower);
		//*
		if (err != READER_ERR.MT_OK_ERR)
			return err;

		AntPowerConf apcf=rdr.new AntPowerConf();
		apcf.antcnt=portnum;
		for(int i=0;i<apcf.antcnt;i++)
		{
			AntPower jaap=rdr.new AntPower();
			jaap.antid=i+1;
			jaap.readPower=(short)maxpower[0];
			jaap.writePower=(short)maxpower[0];
			apcf.Powers[i]=jaap;
		}
		err=rdr.ParamSet( Mtr_Param.MTR_PARAM_RF_ANTPOWER, apcf);
		//*
		if (err != READER_ERR.MT_OK_ERR)
			return err;

		//设置读写器执行GEN2空中接口协议
		Inv_Potls_ST ipst=rdr.new Inv_Potls_ST();
		ipst.potlcnt=1;
		ipst.potls=new Inv_Potl[1];
		for(int i=0;i<ipst.potlcnt;i++)
		{
			Inv_Potl ipl=rdr.new Inv_Potl();
			ipl.weight=30;
			ipl.potl=SL_TagProtocol.SL_TAG_PROTOCOL_GEN2;
			ipst.potls[0]=ipl;
		}
		//不用检查返回值，不会失败
		err= rdr.ParamSet(Mtr_Param.MTR_PARAM_TAG_INVPOTL, ipst);


		//设置盘存到标签时的回调处理函数
		rdr.addReadListener(RL);
		//*
		//设置读写器发生错误时的回调处理函数
		rdr.addReadExceptionListener(REL);
		//****************************************************************************

		//以下为根据应用需求可能要设置的参数******************************************
		//*
		//标签数量比较大，且移动速度缓慢或静止不动,设置为Session1可取得更
		//好效果,反之标签数量较少移动速度较快应设置为Session0,读写器默认
		//为Session0

		int[] gen2session=new int[]{1};
		err =rdr.ParamSet(Mtr_Param.MTR_PARAM_POTL_GEN2_SESSION, gen2session);
		if (err != READER_ERR.MT_OK_ERR)
			return err;
		//*/

     /*
     //对于某些应用可能需要读写器只盘存符合某些数据特征的标签，可以通
 	//过设置过滤条件来实现，这样对于不符合特征的标签就不会被采集，以
 	//下代码实现只盘存EPC码以0011010011（二进制）开头的标签
 	byte[] filterbytes=new byte[2];
 	filterbytes[0] = 0x34;
 	filterbytes[1] = (byte) 0xC0;

 	TagFilter_ST filter=rdr.new TagFilter_ST();
 	filter.bank=1;
 	filter.fdata=filterbytes;
 	filter.flen=4;
 	filter.isInvert=0;
 	filter.startaddr=32;

 	//不用检查返回值，不会失败
    rdr.ParamSet(Mtr_Param.MTR_PARAM_TAG_FILTER, filter);//*/


 	/*
     //有些应用除了快速盘存标签的EPC码外还想同时抓取某一个bank内的数据，
 	//可以通过设置此参数实现（目前只有slr11xx和slr12xx系列读写器才支
 	//持），以下代码实现抓取tid区从0块开始的12个字节的数据,需要注意的
 	//是抓取的字节数必须是2的倍数,如果成功获得其它bank的数据则TAGINFO
 	//结构的成员EmbededData则为获得的数据，如果失败的话则TAGINFO结构
 	//的成员EmbededDatalen为0

 	EmbededData_ST edst = rdr.new EmbededData_ST();
	edst.startaddr=0;
	edst.bank=2;
	//bytecnt=0 取消嵌入数据
	edst.bytecnt=12;
	edst.accesspwd=null;
	//不用检查返回值，不会失败
	rdr.ParamSet(Mtr_Param.MTR_PARAM_TAG_EMBEDEDDATA, edst);//*/
		return READER_ERR.MT_OK_ERR;
	}

	READER_ERR StartReadTags()
	{
		//初始化结BackReadOption
		BackReadOption m_BROption=new BackReadOption();
		//本例只使用天线1进行盘存，如果要使用多个天线则只需要将使用的天线编
		//号赋值到数组ants中，例如同时使用天线1和2，则代码应该改为ants[0] = 1;
		//ants[1] = 2;antcnt = 2;
		int antcnt=1;
		int[] ants=new int[antcnt];
		for(int i=0;i<antcnt;i++)
			ants[i]=i+1;
		/*是否采用高速模式（目前只有slr11xx和slr12xx系列读写器才支持）,对于
		 *一般标签数量不大，速度不快的应用没有必要使用高速模式,本例没有设置
		 *使用高速模式
		 * */
		m_BROption.IsFastRead = true;//采用非高速模式盘存标签


		///非高速盘存模式下必须要设置的参数*******************************************
		//盘存周期,单位为ms，可根据实际使用的天线个数按照每个天线需要200ms
		//的方式计算得出,如果启用高速模式则此选项没有任何意义，可以设置为
		//任意值，或者干脆不设置
		m_BROption.ReadDuration = (short)(200 * antcnt);
		//盘存周期间的设备不工作时间,单位为ms,一般可设置为0，增加设备不工作
		//时间有利于节电和减少设备发热（针对某些使用电池供电或空间结构不利
		//于散热的情况会有帮助）
		m_BROption.ReadInterval = 0;
		//****************************************************************************


		//高速盘存模式参数设置********************************************************
		//以下为选择使用高速模式才起作用的选项参,照如下设置即可,如果使能高速
		//模式，即把IsFastRead设置为true则,只需取消以下被注释的代码即可
		//*
		//高速模式下为取得最佳效果设置为0即可
		m_BROption.FastReadDutyRation = 0;
		//标签信息是否携带识别天线的编号
		m_BROption.TMFlags.IsAntennaID = true;
		//标签信息是否携带标签识别次数
		m_BROption.TMFlags.IsReadCnt = false;
		//标签信息是否携带识别标签时的信号强度
		m_BROption.TMFlags.IsRSSI = false;
		//标签信息是否携带时间戳
		m_BROption.TMFlags.IsTimestamp = false;
		//标签信息是否携带识别标签时的工作频点
		m_BROption.TMFlags.IsFrequency = false;
		//标签信息是否携带识别标签时同时读取的其它bank数据信息,如果要获取在
		//盘存时同时读取其它bank的信息还必须设置MTR_PARAM_TAG_EMBEDEDDATA参数,
		//（目前只有slr11xx和slr12xx系列读写器才支持）
		m_BROption.TMFlags.IsEmdData = false;
		//保留字段，可始终设置为0
		m_BROption.TMFlags.IsRFU = false;
		//*/
		//****************************************************************************


		//使用GPI输入信号触发读写器工作***********************************************
		//*
		//共有三种触发模式：
		//1  预定义两种GPI状态，一种作为触发读写器启动盘存的条件，另一种
		//   作为停止盘存的条件
		//2  预定义一种GPI状态，触发读写器启动盘存，指定一段时间(必须大于
		//   5秒)后自动停止盘存标签
		//3  预定义两种GPI状态，满足任何一种GPI状态都触发读写器启动盘存，
		//   指定一段时间(必须大于5秒)后自动停止盘存标签
		//详见"读写器GPI触发工作模式.pdf"
		//以下示例为模式1，Trigger1State为启动工作时的GPI状态，且可以指
		//定多个GPI的状态，此例指定当GPI1为0时读写器开始盘存,当GPI2为0时
		//读写器停止盘存
		//m_BROption.IsGPITrigger = true;
		//设置读写器发生GPI时的回调处理函数
		// rdr.addGpiTriggerListener(GTL);
		// rdr.addGpiTriggerBoundaryListener(GTBL);

		//第一种触发模式
 	/*
 	 m_BROption.GpiTrigger.TriggerType = GpiTrigger_Type.GPITRIGGER_TRI1START_TRI2STOP;
 	m_BROption.GpiTrigger.GpiTrigger1States.gpiCount = 1;
 	m_BROption.GpiTrigger.GpiTrigger1States.gpiStats[0].GpiId = 1;
 	m_BROption.GpiTrigger.GpiTrigger1States.gpiStats[0].State = 0;
 	m_BROption.GpiTrigger.GpiTrigger2States.gpiCount = 1;
 	m_BROption.GpiTrigger.GpiTrigger2States.gpiStats[0].GpiId = 2;
 	m_BROption.GpiTrigger.GpiTrigger2States.gpiStats[0].State = 0;
 	*/
		//第二种触发模式
 	  /*m_BROption.GpiTrigger.TriggerType = GpiTrigger_Type.GPITRIGGER_TRI1ORTRI2START_TIMEOUTSTOP;
	 	m_BROption.GpiTrigger.GpiTrigger1States.gpiCount = 1;
	 	m_BROption.GpiTrigger.GpiTrigger1States.gpiStats[0].GpiId = 1;
	 	m_BROption.GpiTrigger.GpiTrigger1States.gpiStats[0].State = 0;
	 	m_BROption.GpiTrigger.GpiTrigger2States.gpiCount = 1;
	 	m_BROption.GpiTrigger.GpiTrigger2States.gpiStats[0].GpiId = 2;
	 	m_BROption.GpiTrigger.GpiTrigger2States.gpiStats[0].State = 0;
	 	m_BROption.GpiTrigger.StopTriggerTimeout=5000;
	 	*/

		//第三种触发模式
 	    /*
 	    m_BROption.GpiTrigger.TriggerType = GpiTrigger_Type.GPITRIGGER_TRI1START_TIMEOUTSTOP;
	 	m_BROption.GpiTrigger.GpiTrigger1States.gpiCount = 1;
	 	m_BROption.GpiTrigger.GpiTrigger1States.gpiStats[0].GpiId = 3;
	 	m_BROption.GpiTrigger.GpiTrigger1States.gpiStats[0].State = 0;
	 	m_BROption.GpiTrigger.StopTriggerTimeout=5000;
	 	 */

		//在GPI触发工作时，当触发条件发生时的处理函数，可通过此事件获取触
		//发时刻的GPI状态，如果不关心触发时刻的GPI状态以及时序关系，可以
		//不设置此事件，详见文档"读写器GPI触发工作模式.pdf"

		return rdr.StartReading(ants, antcnt, m_BROption);
	}
	//*
	public static void main(String[] args)
	{
		System.out.println(System.getProperty("java.library.path"));
		try {
			if(!System.getProperty("os.arch").contains("64"))
			{
				//32位系统需要这个支持库
				System.loadLibrary("ACE");

			}
			System.loadLibrary("PCOMM");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println("hello into the longtermasyncread of samples for java");
		LongTermAsyncRead fm=new LongTermAsyncRead(300,650);

	}
	//*/
}
