/// <summary>
        /// The secondary thread used to get data from USB/RS232 COM port
        /// </summary>
        private void ReceiveThreadfunc()
        {
            //this is the object used to keep current configuration data
            RFEConfiguration objCurrentConfiguration = null;
            RFESweepData objSweepTracking = null;
            m_bThreadTrackingEnabled = false;
            int nTrackingStepRetry = 0;

            while (m_bRunReceiveThread)
            {
                string strReceived = "";
#if SUPPORT_EXPERIMENTAL
                while (m_bPortConnected && !m_bModeAPI)
#else
                while (m_bPortConnected && m_bRunReceiveThread)
#endif
                {
                    string sNewText = "";

                    try
                    {
                        Monitor.Enter(m_serialPortObj);
                        if (m_serialPortObj.IsOpen && m_serialPortObj.BytesToRead > 0)
                        {
                            sNewText = m_serialPortObj.ReadExisting();
                        }
                    }
                    catch (IOException) { }
                    catch (TimeoutException) { }
                    catch (Exception obExeption)
                    {
                        Monitor.Enter(m_arrReceivedData);
                        m_arrReceivedData.Enqueue(obExeption);
                        Monitor.Exit(m_arrReceivedData);
                    }
                    finally { Monitor.Exit(m_serialPortObj); }

                    if (sNewText.Length > 0)
                    {
                        if (m_bDebugTraces)
                        {
                            //Debug only, do not enable this in production
                            m_ReceivedBytesMutex.WaitOne();
                            m_sAllReceivedBytes += sNewText;
                            m_ReceivedBytesMutex.ReleaseMutex();
                        }
                        strReceived += sNewText;
                        sNewText = "";
                    }
                    if (strReceived.Length > 25240)
                    {
                        //Safety code, some error prevented the string from being processed in several loop cycles. Reset it.
                        if (m_bDebugTraces)
                        {
                            Monitor.Enter(m_arrReceivedData);
                            m_arrReceivedData.Enqueue("Received string truncated (" + strReceived.Length + ")");
                            Monitor.Exit(m_arrReceivedData);
                        }
                        strReceived = "";
                    }
                    if (strReceived.Length > 0)
                    {
                        if (strReceived[0] == '#')
                        {
                            int nEndPos = strReceived.IndexOf("\r\n");
                            if (nEndPos >= 0)
                            {
                                string sNewLine = strReceived.Substring(0, nEndPos);
                                string sLeftOver = strReceived.Substring(nEndPos + 2);
                                strReceived = sLeftOver;

                                RFEConfiguration objNewConfiguration = null;
                                if ((sNewLine.Length > 2) && (sNewLine.Substring(0, 3) == "#K1"))
                                {
                                    if (m_bThreadTrackingEnabled==false)
                                    {
                                        //if we are starting tracking here, send the request for first step right away
                                        m_objRFEGen.SendCommand_TrackingStep(0);
                                        SendCommand_TrackingStep(0); 
                                    }
                                    m_bThreadTrackingEnabled=true;
                                    nTrackingStepRetry = 0;

                                    Monitor.Enter(m_arrReceivedData);
                                    m_arrReceivedData.Enqueue(sNewLine);
                                    Monitor.Exit(m_arrReceivedData);
                                }
                                if ((sNewLine.Length > 2) && (sNewLine.Substring(0, 3) == "#K0"))
                                {
                                    m_bThreadTrackingEnabled = false;

                                    Monitor.Enter(m_arrReceivedData);
                                    m_arrReceivedData.Enqueue(sNewLine);
                                    Monitor.Exit(m_arrReceivedData);
                                }
                                else if ((sNewLine.Length > 5) && ((sNewLine.Substring(0, 6) == "#C2-F:") || (sNewLine.Substring(0, 6) == "#C3-G:")))
                                {
                                    m_bThreadTrackingEnabled=false;

                                    if (m_bDebugTraces)
                                    {
                                        Monitor.Enter(m_arrReceivedData);
                                        m_arrReceivedData.Enqueue("Received Config:" + strReceived.Length.ToString("D5"));
                                        Monitor.Exit(m_arrReceivedData);
                                    }

                                    //Standard configuration expected
                                    objNewConfiguration = new RFEConfiguration();
                                    if (objNewConfiguration.ProcessReceivedString(sNewLine))
                                    {
                                        objCurrentConfiguration = new RFEConfiguration(objNewConfiguration);
                                        Monitor.Enter(m_arrReceivedData);
                                        m_arrReceivedData.Enqueue(objNewConfiguration);
                                        Monitor.Exit(m_arrReceivedData);
                                    }
                                }
                                else
                                {
                                    Monitor.Enter(m_arrReceivedData);
                                    m_arrReceivedData.Enqueue(sNewLine);
                                    Monitor.Exit(m_arrReceivedData);
                                }
                            }
                        }
                        else if (strReceived[0] == '$')
                        {
                            if ((strReceived.Length > 4) && (strReceived[1] == 'C'))
                            {
                                UInt16 nSize = 2; //account for CR+LF

                                switch (strReceived[2])
                                {
                                    case 'c':
                                        {
                                            //Calibration data
                                            nSize += (byte)(Convert.ToByte(strReceived[3]) + 4);
                                            break;
                                        }
                                    case 'b':
                                        {
                                            //Memory data dump
                                            nSize += (UInt16)((Convert.ToByte(strReceived[4]) + 1) * 16 + 10);
                                            break;
                                        }

                                }
                                //This is standard for all 'C' data dumps
                                if ((nSize > 2) && (strReceived.Length >= nSize))
                                {
                                    string sNewLine = strReceived.Substring(0, nSize);
                                    string sLeftOver = strReceived.Substring(nSize);
                                    strReceived = sLeftOver;
                                    Monitor.Enter(m_arrReceivedData);
                                    m_arrReceivedData.Enqueue(sNewLine);
                                    Monitor.Exit(m_arrReceivedData);
                                }
                            }
                            else if ((strReceived.Length > 1) && (strReceived[1] == 'q'))
                            {
                                //this is internal calibration data dump
                                ushort nReceivedLength = (byte)strReceived[2];
                                bool bLengthOK = (strReceived.Length >= (3 + nReceivedLength + 2));
                                if (bLengthOK)
                                {
                                    Monitor.Enter(m_arrReceivedData);
                                    m_arrReceivedData.Enqueue(strReceived);
                                    Monitor.Exit(m_arrReceivedData);
                                    strReceived = strReceived.Substring(3 + nReceivedLength + 2);
                                }
                            }
                            else if ((strReceived.Length > 1) && (strReceived[1] == 'D'))
                            {
                                //This is dump screen data
                                if (m_bDebugTraces)
                                {
                                    Monitor.Enter(m_arrReceivedData);
                                    m_arrReceivedData.Enqueue("Received $D" + strReceived.Length.ToString("D5"));
                                    Monitor.Exit(m_arrReceivedData);
                                }

                                if (strReceived.Length >= (4 + 128 * 8))
                                {
                                    string sNewLine = "$D" + strReceived.Substring(2, 128 * 8);
                                    string sLeftOver = strReceived.Substring(4 + 128 * 8);
                                    strReceived = sLeftOver;
                                    RFEScreenData objData = new RFEScreenData();
                                    if (objData.ProcessReceivedString(sNewLine))
                                    {
                                        Monitor.Enter(m_arrReceivedData);
                                        m_arrReceivedData.Enqueue(objData);
                                        Monitor.Exit(m_arrReceivedData);
                                    }
                                    else
                                    {
                                        Monitor.Enter(m_arrReceivedData);
                                        m_arrReceivedData.Enqueue(sNewLine);
                                        Monitor.Exit(m_arrReceivedData);
                                    }
                                }
                            }
                            else if ((strReceived.Length > 2) && (strReceived[1] == 'S'))
                            {
                                //Standard spectrum analyzer data
                                ushort nReceivedLength = (byte)strReceived[2];

                                if (m_bDebugTraces)
                                {
                                    Monitor.Enter(m_arrReceivedData);
                                    m_arrReceivedData.Enqueue("Received $S" + nReceivedLength.ToString("D5"));
                                    Monitor.Exit(m_arrReceivedData);
                                }

                                bool bLengthOK = (strReceived.Length >= (3 + nReceivedLength + 2));
                                bool bFullStringOK = false;
                                if (bLengthOK && (strReceived.Substring(3 + nReceivedLength, 2) == "\r\n"))
                                {
                                    bFullStringOK = true;
                                }

                                if (bFullStringOK)
                                {
                                    //So we are here because received the full set of chars expected, and all them are apparently of valid characters
                                    if (nReceivedLength <= MAX_SPECTRUM_STEPS)
                                    {
                                        string sNewLine = "$S" + strReceived.Substring(3, nReceivedLength);
                                        if (objCurrentConfiguration != null)
                                        {
                                            UInt16 nSweepSteps = objCurrentConfiguration.nFreqSpectrumSteps;
                                            if (m_bThreadTrackingEnabled)
                                            {
                                                nSweepSteps = nReceivedLength;
                                            }

                                            RFESweepData objSweep = new RFESweepData(objCurrentConfiguration.fStartMHZ, objCurrentConfiguration.fStepMHZ, nSweepSteps);
                                            if (objSweep.ProcessReceivedString(sNewLine, objCurrentConfiguration.fOffset_dB))
                                            {
                                                if (!m_bThreadTrackingEnabled)
                                                {
                                                    //Normal spectrum analyzer sweep data
                                                    Monitor.Enter(m_arrReceivedData);
                                                    m_arrReceivedData.Enqueue(objSweep);
                                                    Monitor.Exit(m_arrReceivedData);
                                                }
                                                else
                                                {
                                                    //tracking generator sweep data, we capture a sweep point every time to build a new full objSweepTracking
                                                    if (m_nRFGenTracking_CurrentSweepStep == 0)
                                                    {
                                                        objSweepTracking = new RFESweepData(m_objRFEGen.RFGenStartFrequencyMHZ, m_objRFEGen.RFGenStepFrequencyMHZ, m_objRFEGen.RFGenSweepSteps);
                                                    }
                                                    float fMaxDB = objSweep.GetAmplitudeDBM(objSweep.GetPeakStep());
                                                    objSweepTracking.SetAmplitudeDBM(m_nRFGenTracking_CurrentSweepStep, fMaxDB);

                                                    if (!m_bTrackingNormalizing || (fMaxDB > MIN_AMPLITUDE_TRACKING_NORMALIZE) || !m_bTrackingAllowed)
                                                    {
                                                        //if we are normalizing, make sure the value read is correct or either do not increase step
                                                        m_nRFGenTracking_CurrentSweepStep++;
                                                    }
                                                    else
                                                    {
                                                        nTrackingStepRetry++;
                                                        if (m_bTrackingNormalizing && nTrackingStepRetry > (m_objRFEGen.RFGenSweepSteps / 5))
                                                        {
                                                            //if we retried about the same number of steps the sweep have, then something is really wrong
                                                            m_objRFEGen.SendCommand_GeneratorRFPowerOFF();
                                                            m_bThreadTrackingEnabled = false; //be done with thread tracking activity, so main thread knows
                                                            Monitor.Enter(m_arrReceivedData);
                                                            m_arrReceivedData.Enqueue("Too many retries normalizing data. Review your setup and restart Spectrum Analyzer");
                                                            Monitor.Exit(m_arrReceivedData);
                                                            Monitor.Enter(m_arrReceivedData);
                                                            m_arrReceivedData.Enqueue(objSweepTracking); //send whatever we have, we will detect it outside the thread
                                                            Monitor.Exit(m_arrReceivedData);
                                                        }
                                                    }
                                                    if (m_bThreadTrackingEnabled)
                                                    {
                                                        if (m_nRFGenTracking_CurrentSweepStep <= m_objRFEGen.RFGenSweepSteps)
                                                        {
                                                            m_objRFEGen.SendCommand_TrackingStep(m_nRFGenTracking_CurrentSweepStep);
                                                            SendCommand_TrackingStep(m_nRFGenTracking_CurrentSweepStep);
                                                        }
                                                        else
                                                        {
                                                            //we are done with a tracking sweep capture objSweepTracking, make it available
                                                            m_nTrackingNormalizingPass++;
                                                            m_nTrackingPass++;
                                                            Monitor.Enter(m_arrReceivedData);
                                                            m_arrReceivedData.Enqueue(objSweepTracking);
                                                            Monitor.Exit(m_arrReceivedData);

                                                            //If we need to restart, do it from first step
                                                            m_nRFGenTracking_CurrentSweepStep = 0;

                                                            if ( (m_bTrackingNormalizing && (m_nTrackingNormalizingPass > m_nAutoStopSNATrackingCounter)) || 
                                                                 !m_bTrackingAllowed ||
                                                                 (!m_bTrackingNormalizing && ((m_nAutoStopSNATrackingCounter!=0) && (m_nTrackingPass > m_nAutoStopSNATrackingCounter)))
                                                               )
                                                            {
                                                                //if normalizing is completed, or if we have finished tracking manually or automatically, we are done with RF power
                                                                m_objRFEGen.SendCommand_GeneratorRFPowerOFF();
                                                                m_bThreadTrackingEnabled = false; //be done with thread tracking activity, so main thread knows
                                                            }
                                                            else
                                                            {
                                                                //start all over again a full new sweep
                                                                m_objRFEGen.SendCommand_TrackingStep(m_nRFGenTracking_CurrentSweepStep);
                                                                SendCommand_TrackingStep(m_nRFGenTracking_CurrentSweepStep);
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                Monitor.Enter(m_arrReceivedData);
                                                m_arrReceivedData.Enqueue(sNewLine);
                                                Monitor.Exit(m_arrReceivedData);
                                            }
                                        }
                                    }
                                    else
                                    {
                                        Monitor.Enter(m_arrReceivedData);
                                        m_arrReceivedData.Enqueue("Ignored $S of size " + nReceivedLength.ToString() + " expected " + FreqSpectrumSteps.ToString());
                                        Monitor.Exit(m_arrReceivedData);
                                    }
                                    strReceived = strReceived.Substring(3 + nReceivedLength + 2);
                                }
                                else if (bLengthOK)
                                {
                                    //So we are here because the string doesn't end with the expected chars, but has the right length. 
                                    //The most likely cause is a truncated string was received, and some chars are from next string, not this one
                                    //therefore we truncate the line to avoid being much larger, and start over again next time.
                                    int nPosNextLine = strReceived.IndexOf("\r\n");
                                    if (nPosNextLine >= 0)
                                    {
                                        strReceived = strReceived.Substring(nPosNextLine + 2);
                                    }
                                }
                            }
                            else if ((strReceived.Length > 3) && (strReceived[1] == 's'))
                            {
                                //Extended API spectrum analyzer data
                                ushort nReceivedLength = (byte)strReceived[2];
                                nReceivedLength = (ushort)(nReceivedLength * 0x100 + (byte)strReceived[3]);

                                if (strReceived.Length >= (4 + nReceivedLength + 2))
                                {
                                    if (nReceivedLength <= MAX_SPECTRUM_STEPS)
                                    {
                                        string sNewLine = "$S" + strReceived.Substring(4, nReceivedLength);
                                        Monitor.Enter(m_arrReceivedData);
                                        m_arrReceivedData.Enqueue(sNewLine);
                                        Monitor.Exit(m_arrReceivedData);
                                    }
                                    else
                                    {
                                        Monitor.Enter(m_arrReceivedData);
                                        m_arrReceivedData.Enqueue("Ignored $S of size " + nReceivedLength.ToString() + " expected " + FreqSpectrumSteps.ToString());
                                        Monitor.Exit(m_arrReceivedData);
                                    }
                                    string sLeftOver = strReceived.Substring(4 + nReceivedLength + 2);
                                    strReceived = sLeftOver;
                                }
                            }
                            else if ((strReceived.Length > 10) && (strReceived[1] == 'R'))
                            {
                                //Raw data
                                int nPos = strReceived.IndexOf('-');
                                if ((nPos > 2) && (nPos < 10))
                                {
                                    int nSize = Convert.ToInt32(strReceived.Substring(2, nPos - 2));
                                    if (strReceived.Length > (nSize + nPos + 2))
                                    {
                                        Monitor.Enter(m_arrReceivedData);
                                        m_arrReceivedData.Enqueue("Received RAW data " + nSize.ToString());
                                        m_arrReceivedData.Enqueue("$R" + strReceived.Substring(nPos + 1, nSize));
                                        Monitor.Exit(m_arrReceivedData);
                                        strReceived = strReceived.Substring(nSize + nPos + 1 + 2);
                                    }
                                }
                            }
                        }
                        else
                        {
                            int nEndPos = strReceived.IndexOf("\r\n");
                            if (nEndPos >= 0)
                            {
                                string sNewLine = strReceived.Substring(0, nEndPos);
                                string sLeftOver = strReceived.Substring(nEndPos + 2);
                                strReceived = sLeftOver;
                                Monitor.Enter(m_arrReceivedData);
                                m_arrReceivedData.Enqueue(sNewLine);
                                Monitor.Exit(m_arrReceivedData);
                            }
                            else
                            {
                                //diagnosis only
                                if (m_bDebugTraces)
                                {
                                    Monitor.Enter(m_arrReceivedData);
                                    m_arrReceivedData.Enqueue("DEBUG partial:" + strReceived);
                                    Monitor.Exit(m_arrReceivedData);
                                }
                            }
                        }
                    }
                    if (m_eMode!=eMode.MODE_TRACKING)
                        Thread.Sleep(10);
                    else
                        Thread.Sleep(2); //in tracking mode we want to be as fast as possible
                }

                Thread.Sleep(500);
            }
        }