using System;
using System.Windows.Forms;
using ModuleTech;
using ModuleTech.Gen2;
using ModuleLibrary;

namespace InitTag_cs
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        Reader rdr = null;
        void OpenReader()
        {
            /*
             * When using the network port of the device for initialization, the 
             * first parameter of the Create method may also be the IP address of 
             * the device. When the device has only one antenna port (such as 
             * integreted reader or desktop reader), the third parameter of the 
             * Create method is 1, determine the value of the third parameter 
             * based on the actual number of antenna ports on the device.
             */
            int antnum = int.Parse(antcnt.Text);
            rdr = Reader.Create(port.Text, ModuleTech.Region.EU3, antnum);

            // Parameters that must be set

            // Set the transmit power of the reader
            // Set the reader's transmit power to 20dbm and 24dbm. It is not appropriate 
            // to set the transmit power too much for the initial tag type application. 
            // Generally speaking, the larger the transmit power, the farther the 
            // read/write distance is.
            AntPower[] pwrs = new AntPower[antnum];
            for (int i = 0; i < antnum; ++i)
            {
                pwrs[i].AntId = (byte)(i + 1);
                pwrs[i].ReadPower = (ushort)1900; 
                pwrs[i].WritePower = (ushort)1900; 
            }
            rdr.ParamSet("AntPowerConf", pwrs);

            // Set the antenna used for inventory
            int usedant = int.Parse(selant.Text, System.Globalization.NumberStyles.Integer);
            int[] useants = new int[] { usedant };
            SimpleReadPlan readPlan = new SimpleReadPlan(TagProtocol.GEN2, useants);
            rdr.ParamSet("ReadPlan", readPlan);

            // Set the antenna used for tag operations such as read, write, and lock
            rdr.ParamSet("TagopAntenna", usedant);
        }

        // Used to detect if there is only one tag in the antenna field before the specific tag operation
        private TagReadData PreTagOp()
        {
            if (rdr == null)
            {
                MessageBox.Show("Reader not initialized");
                return null;
            }
            
            try
            {
                TagReadData[] tags = rdr.Read(250);
                if (tags.Length != 1)
                {
                    MessageBox.Show("Please ensure that there is only one tag in the antenna field");
                    return null;
                }
                return tags[0];
            }
            catch (System.IO.IOException e)
            {
                MessageBox.Show("IO Error: " +  e.ToString());
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("Detection tag failed :" + ex.ToString());
            }
            return null;
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        /*
         * Write the EPC code.
         * Please note that both the WriteTag and WriteTagMemWords methods can modify the EPC area 
         * data of the label. Several bits in the PC section of the EPC area are used 
         * to indicate the length of the EPC code, that is, the length of the returned 
         * EPC code can be less than or equal to The actual EPC area capacity, 
         * WriteTag method will write data from the block address 2 to the EPC area, 
         * and set the bit of the PC segment indicating the length of the EPC code 
         * to the length of the write data, that is, the data written by the 
         * WriteTag method will be the same as the data obtained by the Read method. 
         * The WriteTagMemWords method can modify any writable storage area in the EPC 
         * area.
         */
        private void btnwriteepc_Click(object sender, EventArgs e)
        {
            TagReadData target = PreTagOp();
            if (target == null)
                return;
            Gen2TagFilter filter = new Gen2TagFilter(target.EPC.Length * 8, target.EPC, MemBank.EPC, 32, false);
            try
            {
                // The access password settings are divided into two cases:
                // 1. When the operating area is locked, you must set the access 
                //    password operation consistent with the label to succeed.
                // 2. When the operating area is not locked, you can set the access 
                //    password to 0, or do not set the access password.
                // The reader uses 0 as the access password by default.
                uint accesspwd = uint.Parse(accpwd.Text, System.Globalization.NumberStyles.HexNumber);
                rdr.ParamSet("AccessPassword", accesspwd);
                rdr.WriteTag(filter, new TagData(ByteFormat.FromHex(epc.Text)));
                MessageBox.Show("Operation success");
            }
            catch (ModuleException mex)
            {
                MessageBox.Show("Operation failed:" + mex.ToString());
                return;
            }
        }

        /*
         * Write data to the tag storage area. This example writes two blocks of 
         * data to the USER area.
         * */
        private void btnwritebank_Click(object sender, EventArgs e)
        {
            TagReadData target = PreTagOp();
            if (target == null)
                return;
            Gen2TagFilter filter = new Gen2TagFilter(target.EPC.Length * 8, target.EPC, MemBank.EPC, 32, false);
            try
            {
                // The access password settings are divided into two cases:
                // 1. When the operating area is locked, you must set the access 
                //    password operation consistent with the label to succeed.
                // 2. When the operating area is not locked, you can set the access 
                //    password to 0, or do not set the access password.
                // The reader uses 0 as the access password by default.
                uint accesspwd = uint.Parse(accpwd.Text, System.Globalization.NumberStyles.HexNumber);
                rdr.ParamSet("AccessPassword", accesspwd);
                byte[] datab = ByteFormat.FromHex(data.Text);
                ushort[] wdata = new ushort[2];
                wdata[0] = BitConverter.ToUInt16(datab, 0);
                wdata[1] = BitConverter.ToUInt16(datab, 2);
                rdr.WriteTagMemWords(filter, MemBank.USER, 0, wdata);
                MessageBox.Show("Operation success");
            }
            catch (ModuleException mex)
            {
                MessageBox.Show("Operation failed:" + mex.ToString());
                return;
            }
        }

        /*
         * Read the data in the tag storage area.
         */
        private void btnreadbank_Click(object sender, EventArgs e)
        {
            TagReadData target = PreTagOp();
            if (target == null)
                return;
            Gen2TagFilter filter = new Gen2TagFilter(target.EPC.Length * 8, target.EPC, MemBank.EPC, 32, false);
            try
            {
                // The access password settings are divided into two cases:
                // 1. When the operating area is locked, you must set the access 
                //    password operation consistent with the label to succeed.
                // 2. When the operating area is not locked, you can set the access 
                //    password to 0, or do not set the access password.
                // The reader uses 0 as the access password by default.
                uint accesspwd = uint.Parse(accpwd.Text, System.Globalization.NumberStyles.HexNumber);
                rdr.ParamSet("AccessPassword", accesspwd);

                MemBank membank;
                switch (writebank.SelectedItem)
                {
                    case "RESERVED":
                        membank = MemBank.RESERVED;
                        break;
                    case "EPC":
                        membank = MemBank.EPC;
                        break;
                    case "TID":
                        membank = MemBank.TID;
                        break;
                    case "USER":
                        membank = MemBank.USER;
                        break;
                    default:
                        membank = MemBank.USER;
                        break;
                }

                ushort[] rdata = rdr.ReadTagMemWords(filter, membank, int.Parse(dataaddr.Text), 2);
                MessageBox.Show("Operation success");
                String msg = rdata[0].ToString("X2") + rdata[1].ToString("X2");
                MessageBox.Show(msg);
            }
            catch (ModuleException mex)
            {
                MessageBox.Show("Operation failed:" + mex.ToString());
                return;
            }
        }

        /*
         * Lock the storage area of the tag. In this example, temporarily lock the EPC 
         * area of the tag.It should be noted that the access password of the tag 
         * must be initialized to non-zero before locking the tag storage area. Be sure to 
         * set the AccessPassword parameter before calling the LockTag method to 
         * lock the storage area. Otherwise, the operation will be failure. The access 
         * password for the initialization tag can be manipulated by the 
         * WriteTagMemWords method. After completing the LockTag, please set the 
         * AccessPassword to 0, because the AccessPassword parameter will remain 
         * valid once it is set, until the next time it is set. Generally, the default 
         * access password for the tags that have just been purchased is 0.
         */
        private void btnlocktag_Click(object sender, EventArgs e)
        {
            TagReadData target = PreTagOp();
            if (target == null)
                return;
            Gen2TagFilter filter = new Gen2TagFilter(target.EPC.Length * 8, target.EPC, MemBank.EPC, 32, false);
            try
            {
                Gen2LockAct[] act = new Gen2LockAct[1];
                act[0] = Gen2LockAct.EPC_LOCK;
                uint accesspwd = uint.Parse(accpwd.Text, System.Globalization.NumberStyles.HexNumber);
                rdr.ParamSet("AccessPassword", accesspwd);
                rdr.LockTag(filter, new Gen2LockAction(act));
                accesspwd = (uint)0;
                rdr.ParamSet("AccessPassword", accesspwd);
                MessageBox.Show("Operation success");
            }
            catch (ModuleException mex)
            {
                MessageBox.Show("Operation failed:" + mex.ToString());
                return;
            }
        }

        /*
         * Kill the tag, the tag can no longer be used after it is killed. It should 
         * be noted that the tag can only perform the kill operation if the non-zero 
         * kill password is initialized.
         * */
        private void btnkilltag_Click(object sender, EventArgs e)
        {
            TagReadData target = PreTagOp();
            if (target == null)
                return;
            Gen2TagFilter filter = new Gen2TagFilter(target.EPC.Length * 8, target.EPC, MemBank.EPC, 32, false);
            try
            {
                uint kpwd = uint.Parse(killpwd.Text, System.Globalization.NumberStyles.HexNumber);
                rdr.KillTag(filter, kpwd);
                MessageBox.Show("Operation success");
            }
            catch (ModuleException mex)
            {
                MessageBox.Show("Operation failed:" + mex.ToString());
                return;
            }
        }

        /*
         * Complete the access password, kill password, EPC code and 
         * lock the access password, kill password and EPC area of the tag.
         * Note: In the actual application scenario, after initializing the EPC area or 
         * USER area of the tag, it may be necessary to lock these storage areas to 
         * prevent unauthorized rewriting. If it is such an application, the access 
         * password of the tag must be initialized to be non-zero to lock the other 
         * storage area of the tag. If it is considered that the tag may need to 
         * be killed in the future, the tag's kill password must also be initialized. 
         * Access password and kill password also need to be locked, and these 
         * passwords cannot be read and rewritten without authorization.
         */
        private void btninittag_Click(object sender, EventArgs e)
        {
            TagReadData target = PreTagOp();
            if (target == null)
                return;
            Gen2TagFilter filter = new Gen2TagFilter(target.EPC.Length * 8, target.EPC, MemBank.EPC, 32, false);
            try
            {
                // The access password is usually 0 when the tag is shipped 
                // from the factory.
                uint accesspwd = (uint)0;
                rdr.ParamSet("AccessPassword", accesspwd);

                byte[] wepc = ByteFormat.FromHex(epc.Text);
                rdr.WriteTag(filter, new TagData(wepc));

                byte[] kpwdb = ByteFormat.FromHex(killpwd.Text);
                ushort[] kpwd = new ushort[2];
                kpwd[0] = BitConverter.ToUInt16(kpwdb, 0);
                kpwd[1] = BitConverter.ToUInt16(kpwdb, 2);
                rdr.WriteTagMemWords(filter, MemBank.RESERVED, 0, kpwd);

                byte[] w_accpwdb = ByteFormat.FromHex(accpwd.Text);
                ushort[] w_accesspwd = new ushort[2];
                w_accesspwd[0] = BitConverter.ToUInt16(w_accpwdb, 0);
                w_accesspwd[1] = BitConverter.ToUInt16(w_accpwdb, 2);
                rdr.WriteTagMemWords(filter, MemBank.RESERVED, 2, w_accesspwd);

                Gen2LockAct[] act = new Gen2LockAct[3];
                act[0] = Gen2LockAct.ACCESS_LOCK;
                act[1] = Gen2LockAct.KILL_LOCK;
                act[2] = Gen2LockAct.EPC_LOCK;
                accesspwd = uint.Parse(accpwd.Text, System.Globalization.NumberStyles.HexNumber);
                rdr.ParamSet("AccessPassword", accesspwd);
                Gen2TagFilter filter2 = new Gen2TagFilter(wepc.Length * 8, wepc, MemBank.EPC, 32, false);
                rdr.LockTag(filter2, new Gen2LockAction(act));
                // Change the access password to 0 to avoid affecting the next tag 
                // operation.
                accesspwd = (uint)0;
                rdr.ParamSet("AccessPassword", accesspwd);
                MessageBox.Show("Operation success");
            }
            catch (ModuleException mex)
            {
                MessageBox.Show("Operation failed:" + mex.ToString());
                return;
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (rdr != null)
                rdr.Disconnect();
        }

        private void btnconnect_Click(object sender, EventArgs e)
        {
            if (rdr != null)
                rdr.Disconnect();
            try
            {
                OpenReader();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Connection to the reader failed:" + ex.ToString());
                Close();
                return;
            }
        }
    }
}
