/// <summary>
        /// Method of the thread to process asynchronous Message
        /// </summary>
        private void eventThreadProc()
        {
            try
            {
                while (!stop)
                {
                    SerialMessageType serialMessage = deviceChannel.waitNextAsyncEvent();
                    if (serialMessage != null)
                    {
                        switch ((PbMessageType)serialMessage.messageType)
                        {
                        case PbMessageType.ASYNC_MSG_FROM_PB:
                        {
                            AsyncEventMessage asyncEventMessage = (AsyncEventMessage)serialMessage;
                            eventDelegate(asyncEventMessage);
                            break;
                        }

                        default:
                        {
                            Debug.Assert(false, "Error in  eventThreadProc() : " +
                                         ((PbMessageType)serialMessage.messageType).ToString());
                            break;
                        }
                        }
                    }
                }
            }
            catch (Exception exp)
            {
                // MessageBox.Show(DateTime.Now.ToString() + " : " + exp.Source + " : " + exp.TargetSite + " : " + exp.Message);

                string   LogPath;
                string   mes      = DateTime.Now.ToString() + " : ERROR : " + exp.Source + " : " + exp.TargetSite + " : " + exp.Message;
                DateTime TCurrent = DateTime.Now;
                DateTime TRef     = new DateTime(TCurrent.Year,
                                                 TCurrent.Month,
                                                 TCurrent.Day,
                                                 12, 0, 0);

                int res = DateTime.Compare(TCurrent, TRef);
                if (res < 0)
                {
                    LogPath = @"c:\temp\RfidTracking\log\ReaderLog" + string.Format("[{0}]_{1}_AM.txt", deviceChannel.TheDeviceId, DateTime.Now.Date.ToString("dd_MM_yyyy"));
                }

                else
                {
                    LogPath = @"c:\temp\RfidTracking\log\ReaderLog" + string.Format("[{0}]_{1}_PM.txt", deviceChannel.TheDeviceId, DateTime.Now.Date.ToString("dd_MM_yyyy"));
                }
                WriteToLog(LogPath, mes, TCurrent);
                //throw new Exception();
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="asyncEventMessage"></param>
        public void handleAsyncEvent(AsyncEventMessage asyncEventMessage)
        {
            switch (asyncEventMessage.asyncEventType)
            {
            case AsyncEventType.PBET_DrawerOpened:
                Invoke((MethodInvoker) delegate { doorStateLabel.Text = "Door Open"; });

                break;

            case AsyncEventType.PBET_DrawerClosed:
                Invoke((MethodInvoker) delegate { doorStateLabel.Text = "Door Closed"; });
                break;
            }
        }
        /// <summary>
        /// Method for receive asynchronous message
        /// This method blocks until an inbound asynchronous event is received or cancelPendingOperations()
        ///is called.
        /// </summary>
        /// <returns>a message in a serialMessage type class</returns>
        public SerialMessageType waitNextAsyncEvent()
        {
            try
            {
                while (asyncEventQueue.Count == 0)
                {
                    // Wait for an asynchronous event.
                    asyncEventEvent.WaitOne(Timeout.Infinite, false);

                    // Asynchronous event is ready or operation was canceled.
                    if (cancelOps)
                    {
                        return(null);
                    }
                }

                // Asynchronous event has been received. Convert it into the expected format.
                byte[] messagePacket = null;

                lock (lockObj)
                {
                    messagePacket = asyncEventQueue.Dequeue();
                }

                if (messagePacket == null)
                {
                    return(null);
                }
                AsyncEventMessage asyncEventMessage = new AsyncEventMessage();
                asyncEventMessage.byteCount   = (byte)(SerialMessageType.LENGTH_SerialMessageHeader + messagePacket.Length); // Length of message.
                asyncEventMessage.messageType = (byte)PbMessageType.ASYNC_MSG_FROM_PB;
                asyncEventMessage.messageId   = 0;                                                                           // Unique ID identifying this transaction; responses use the same messageID.
                //  asyncEventMessage.deviceId = deviceId; // ID of  device, if applicable.
                asyncEventMessage.deviceId        = TheDeviceId;                                                             // ID of  device, if applicable.
                asyncEventMessage.timeoutMSecs    = 0;                                                                       // Maximum allowable device response time, if applicable.
                asyncEventMessage.errorCode       = 0;                                                                       // Return error code, if applicable.
                asyncEventMessage.deviceTypeMajor = (byte)deviceTypeMajor;                                                   // Device type major, if applicable.
                asyncEventMessage.deviceTypeMinor = (byte)deviceTypeMinor;                                                   // Device type minor, if applicable.
                asyncEventMessage.spare1          = 0;                                                                       // Extra data depending on message type.
                asyncEventMessage.serialMessage   = messagePacket;

                return(asyncEventMessage);
            }
            catch (Exception exp)
            {
                MessageBox.Show("exception async Message : " + exp.Message);
                return(null);
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="asyncEventMessage"></param>
        public void handleAsyncEvent(AsyncEventMessage asyncEventMessage)
        {
            switch (asyncEventMessage.asyncEventType)
            {
            //case AsyncEventType.PBET_TagAdded
            case AsyncEventType.PBET_TagAddedR8:
            {
                PBAE_RfidTagAdded tagAddedMessage = (PBAE_RfidTagAdded)Utilities.MarshalToStruct(
                    asyncEventMessage.serialMessage, typeof(PBAE_RfidTagAdded));
                Tag tag = findOrAddTag(SerialRFID.SerialNumber(tagAddedMessage.serialNumber), false);
                tag.inventorySequence = inventorySequence;
                tag.bTagAdded         = true;

                nbTagPerAxis[Axis]++;
                updateNbTagPerAxis();
                cptCount++;
                Invoke((MethodInvoker) delegate { labelCpt.Text = "Count: " + cptCount.ToString(); });
                checkKZout = 0;        // raz cpt  test sortie
                Invoke((MethodInvoker) delegate { labelKZ.Text = "KZ : " + checkKZout.ToString(); });
                break;
            }

            //case AsyncEventType.PBET_TagRemoved:
            case AsyncEventType.PBET_TagAddedSPCE2_RO:
            case AsyncEventType.PBET_TagAddedSPCE2_RW:
            {
                PBAE_RfidTagAdded tagAddedMessage = (PBAE_RfidTagAdded)Utilities.MarshalToStruct(
                    asyncEventMessage.serialMessage, typeof(PBAE_RfidTagAdded));
                Tag tag = findOrAddTag(SerialRFID.SerialNumber(tagAddedMessage.serialNumber), true);
                tag.inventorySequence = inventorySequence;
                tag.bTagAdded         = true;

                nbTagPerAxis[Axis]++;
                updateNbTagPerAxis();
                cptCount++;
                Invoke((MethodInvoker) delegate { labelCpt.Text = "Count: " + cptCount.ToString(); });
                checkKZout = 0;     // raz cpt  test sortie
                Invoke((MethodInvoker) delegate { labelKZ.Text = "KZ : " + checkKZout.ToString(); });
                break;
            }

            case AsyncEventType.PBET_BackDoorInfo:
            {
                PBAE_BackDoorInfo backDoorPacket = (PBAE_BackDoorInfo)Utilities.MarshalToStruct(
                    asyncEventMessage.serialMessage, typeof(PBAE_BackDoorInfo));
                if (backDoorPacket.backDoorEventType == (byte)BackDoorEventType.BDET_AxisChange)
                {
                    if ((backDoorPacket.value1 < 10) && (backDoorPacket.value2 > 20))
                    {
                        Axis = backDoorPacket.value1;
                        Invoke((MethodInvoker) delegate { labelaxis.Text = "Axis : " + backDoorPacket.value1.ToString(); });
                        Invoke((MethodInvoker) delegate { labelaxis.Refresh(); });
                        stopTime = DateTime.Now;
                        TimeSpan duration = stopTime - startTime;
                        string   time     = duration.ToString();
                        double   rate     = cptCount / duration.TotalSeconds;
                        if (time.Length > 12)
                        {
                            Invoke((MethodInvoker) delegate { labelTime.Text = "Time : " + time.Substring(0, 12) + " - Tags/s : " + String.Format("{0:0.00}", rate);; });
                        }
                    }
                }

                if ((backDoorPacket.value1 == 10) && (backDoorPacket.value2 == 1))
                {
                    checkKZout++;
                }
                Invoke((MethodInvoker) delegate { labelKZ.Text = "KZ : " + checkKZout.ToString(); });
                break;
            }

            case AsyncEventType.PBET_RfidScanStateChanged:
            {
                PBAE_RfidScanStateChanged scanStateChangedMessage = (PBAE_RfidScanStateChanged)Utilities.MarshalToStruct(
                    asyncEventMessage.serialMessage, typeof(PBAE_RfidScanStateChanged));

                // Switch on the new scan state.
                switch ((ScanStatusType)scanStateChangedMessage.scanStatus)
                {
                case ScanStatusType.SS_TagScanStarted:                                 // Cabinet scan has begun.
                {
                    //KB000: This could happen due to a Pyxibus bug where message with broken ACK is delivered twice.
                    // MyDebug.Assert(bScanActive);

                    nbTagPerAxis = new int[10];
                    updateNbTagPerAxis();
                    startTime  = DateTime.Now;
                    checkKZout = 1;
                    Invoke((MethodInvoker) delegate { labelKZ.Text = "KZ : " + checkKZout.ToString(); });
                    if (!bScanActive)
                    {
                        bScanRequested = false;
                        bScanActive    = true;

                        /* if(receiveTagsSynchronouslyDuringScanRadioButton.Checked)
                         * {
                         *       bool bFirstTag = true;
                         *       uint tagIndex;
                         *       uint tagCount;
                         *       UInt64 tagID;
                         *       while(device.getNextTag(bFirstTag, out tagID, out tagIndex, out tagCount))
                         *       {
                         *               bFirstTag = false;
                         *               Tag tag = findOrAddTag(tagID);
                         *       }
                         * }*/
                    }
                    break;
                }

                case ScanStatusType.SS_TagScanCanceledByHost:                                 // Cabinet scan canceled by host.
                    //KB000: This could happen due to a Pyxibus bug where message with broken ACK is delivered twice.
                    // MyDebug.Assert(bScanActive);
                    checkKZout = 255;
                    Invoke((MethodInvoker) delegate { labelKZ.Text = "KZ : " + checkKZout.ToString(); });
                    if (bScanActive)
                    {
                        bScanActive    = false;
                        bCancelLooping = true;
                        TagScanActive(false);
                    }
                    break;

                case ScanStatusType.SS_TagScanCanceledByDoorOpen:                                 // Cabinet scan canceled due to door opening.
                    //KB000: This could happen due to a Pyxibus bug where message with broken ACK is delivered twice.
                    // MyDebug.Assert(bScanActive);
                    if (bScanActive)
                    {
                        bScanActive    = false;
                        bCancelLooping = true;
                        MessageBox.Show("Tag scan canceled by opening door.");
                        TagScanActive(false);
                    }
                    break;

                case ScanStatusType.SS_TagScanFailedByUnrecoverableError:                                 // Cabinet scan failed due to unrecoverable error.
                    //KB000: This could happen due to a Pyxibus bug where message with broken ACK is delivered twice.
                    // MyDebug.Assert(bScanActive);
                    if (bScanActive)
                    {
                        bScanActive    = false;
                        bCancelLooping = true;
                        MessageBox.Show("Tag scan failed due to unrecoverable error: " +
                                        ((UnrecoverableErrorType)scanStateChangedMessage.info).ToString());
                        TagScanActive(false);
                    }
                    break;

                case ScanStatusType.SS_TagScanSendPourcent:
                    break;

                case ScanStatusType.SS_TagScanCompleted:                                 // Cabinet scan has completed
                {
                    //KB000: This could happen due to a Pyxibus bug where message with broken ACK is delivered twice.
                    // MyDebug.Assert(bScanActive);
                    stopTime = DateTime.Now;
                    TimeSpan duration = stopTime - startTime;
                    string   time     = duration.ToString();
                    double   rate     = cptCount / duration.TotalSeconds;
                    if (time.Length > 12)
                    {
                        Invoke((MethodInvoker) delegate { labelTime.Text = "Time : " + time.Substring(0, 12) + " - Tags/s : " + String.Format("{0:0.00}", rate);; });
                    }

                    if (bScanActive)
                    {
                        foreach (Tag tag in tagList.Values)
                        {
                            if (bKnownTagsCleared)
                            {
                                tag.bPresent = (tag.inventorySequence == inventorySequence);
                                Debug.Assert(!tag.bPresent || tag.bTagAdded);                                                         // When known tags are cleared, the only tag reports should be tag-added.
                            }
                            else if (tag.inventorySequence == inventorySequence)
                            {
                                // The tag reported a change in the presence state.
                                tag.bPresent = tag.bTagAdded;
                            }
                        }

                        uint presentTags = 0;
                        uint missingTags = 0;
                        foreach (Tag tag in tagList.Values)
                        {
                            if (tag.bPresent)
                            {
                                tag.missingCount = 0;
                                tag.presentCount++;
                                tag.presentTotal++;
                                presentTags++;
                            }
                            else
                            {
                                tag.missingCount++;
                                tag.missingTotal++;
                                tag.presentCount = 0;
                                missingTags++;
                            }

                            tag.row.Cells[1].Value = tag.presentCount.ToString();
                            tag.row.Cells[2].Value = tag.missingCount.ToString();
                            tag.row.Cells[3].Value = tag.presentTotal.ToString();
                            tag.row.Cells[4].Value = tag.missingTotal.ToString();

                            // Update the row color to give a visual indication of sequential present/missing state.
                            if (!tag.bPresent)
                            {
                                tag.row.DefaultCellStyle.BackColor = FadeColor(Color.Red, Color.Gray, tag.missingCount);
                            }
                            else if (tag.presentTotal == tag.presentCount)
                            {
                                tag.row.DefaultCellStyle.BackColor = Color.White;
                            }
                            else
                            {
                                tag.row.DefaultCellStyle.BackColor = FadeColor(Color.Green, Color.White, tag.presentCount);
                            }
                        }

                        Invoke((MethodInvoker) delegate { presentTagsLabel.Text = "Present: " + presentTags.ToString(); });
                        Invoke((MethodInvoker) delegate { missingTagsLabel.Text = "Missing: " + missingTags.ToString(); });



                        bScanActive = false;
                        // If too many tags were detected, show a warning.
                        if ((scanStateChangedMessage.info & (byte)TagScanCompleteInfoFlagsType.TSCF_TooManyTags) != 0)
                        {
                            bCancelLooping = true;
                            MessageBox.Show("Too many tags detected.");
                            TagScanActive(false);
                        }

                        // If looping, start again.
                        else if (loopCheckBox.Checked && !bCancelLooping)
                        {
                            if (bLoopTimerExpired)
                            {
                                doInventory();
                            }
                        }
                        else
                        {
                            TagScanActive(false);
                        }
                    }
                    break;
                }
                }

                break;
            }
            }
        }