/// <summary>
        /// This function will process a received, full consistent string received from remote device
        /// and fill it in all data
        /// </summary>
        /// <param name="sLine">string received from device, previously parsed and validated</param>
        /// <param name="fOffsetDB">currently specified offset in DB</param>
        public bool ProcessReceivedString(string sLine, float fOffsetDB)
        {
            bool bOk = true;

            try
            {
                if ((sLine.Length > 2) && (sLine.Substring(0, 2) == "$S"))
                {
                    RFESweepData objSweep = new RFESweepData((float)StartFrequencyMHZ, (float)StepFrequencyMHZ, TotalSteps);
                    objSweep.CaptureTime = DateTime.Now;
                    for (ushort nInd = 0; nInd < TotalSteps; nInd++)
                    {
                        byte nVal = Convert.ToByte(sLine[2 + nInd]);
                        float fVal = nVal / -2.0f;

                        SetAmplitudeDBM(nInd, fVal + fOffsetDB);
                    }
                }
                else
                    bOk = false;
            }
            catch (Exception)
            {
                bOk = false;
            }

            return bOk;
        }
        public RFESweepData GetAverage(UInt32 nStart, UInt32 nEnd)
        {
            RFESweepData objReturn = null;

            //string sDebugText = "";

            if (nStart > m_nUpperBound || nEnd > m_nUpperBound || nStart > nEnd)
            {
                return null;
            }

            try
            {
                objReturn = new RFESweepData(m_arrData[nEnd].StartFrequencyMHZ, m_arrData[nEnd].StepFrequencyMHZ, m_arrData[nEnd].TotalSteps);

                for (UInt16 nSweepInd = 0; nSweepInd < objReturn.TotalSteps; nSweepInd++)
                {
                    //sDebugText += "[" + nSweepInd + "]:";
                    float fSweepValue = 0f;
                    for (UInt32 nIterationInd = nStart; nIterationInd <= nEnd; nIterationInd++)
                    {
                        if (nSweepInd == 0)
                        {
                            //check all the sweeps use the same configuration, but only in first loop to reduce overhead
                            if (!m_arrData[nIterationInd].IsSameConfiguration(objReturn))
                                return null;
                        }

                        fSweepValue += m_arrData[nIterationInd].GetAmplitudeDBM(nSweepInd,null,false);
                        //sDebugText += m_arrData[nIterationInd].GetAmplitudeDBM(nSweepInd).ToString("f2") + ",";
                    }
                    fSweepValue = fSweepValue / (nEnd - nStart + 1);
                    //sDebugText += "(" + fSweepValue.ToString("f2") + ")";
                    objReturn.SetAmplitudeDBM(nSweepInd, fSweepValue);
                }
            }
            catch
            {
                objReturn = null;
            }
            return objReturn;
        }
        /// <summary>
        /// 
        /// 
        /// 
        /// </summary>
        /// <param name="sFile"></param>
        /// <returns></returns>
        //

        /// <summary>
        /// Will load a RFE standard file from disk. If the file format is incorrect (unknown) will return false but will not invalidate the internal container
        /// If there are file exceptions, will be received by the caller so should react with appropriate error control
        /// If file is successfully loaded, all previous container data is lost and replaced by data from file
        /// </summary>
        /// <param name="sFile">File name to load</param>
        /// <param name="sModelText">model data text. If it is a normal sweep file, then this comes from spectrum analyzer. If it is tracking or normalization 
        /// then this is from both signal generator and spectrum analyzer</param>
        /// <param name="sConfigurationText">configuration text. If it is a normal sweep file, then this comes from spectrum analyzer. If it is tracking or normalization 
        /// then this is from Signal Generator and some required parameters from spectrum analyzer too.</param>
        /// <returns></returns>
        public bool LoadFile(string sFile, out string sModelText, out string sConfigurationText)
        {
            sConfigurationText = "Configuration info Unknown - Old file format";
            sModelText = "Model Unknown - Old file format";

            FileStream myFile = null;

            try
            {
                myFile = new FileStream(sFile, FileMode.Open);

                using (BinaryReader binStream = new BinaryReader(myFile))
                {
                    myFile = null;

                    string sHeader = binStream.ReadString();
                    if ((sHeader != FileHeaderVersioned()) && (sHeader != FileHeaderVersioned_001()))
                    {
                        //unknown format
                        return false;
                    }

                    double fStartFrequencyMHZ = binStream.ReadDouble();
                    double fStepFrequencyMHZ = binStream.ReadDouble();
                    UInt32 nMaxDataIndex = 0;
                    if (sHeader == FileHeaderVersioned_001())
                    {
                        //in version 001 we saved a 16 bits integer
                        nMaxDataIndex = binStream.ReadUInt16();
                    }
                    else
                    {
                        nMaxDataIndex = binStream.ReadUInt32();
                    }
                    UInt16 nTotalSteps = binStream.ReadUInt16();

                    if (sHeader != FileHeaderVersioned_001())
                    {
                        sConfigurationText = "From file: " + binStream.ReadString();
                        sModelText = "From file: " + binStream.ReadString();
                    }

                    //We initialize internal data only if the file was ok and of the right format
                    CleanAll();
                    m_arrData = new RFESweepData[nMaxDataIndex];

                    for (UInt32 nSweepInd = 0; nSweepInd < nMaxDataIndex; nSweepInd++)
                    {
                        RFESweepData objRead = new RFESweepData((float)fStartFrequencyMHZ, (float)fStepFrequencyMHZ, nTotalSteps);

                        if (sHeader == FileHeaderVersioned_001())
                        {
                            objRead.CaptureTime = new DateTime(2000, 1, 1); //year 2000 means no actual valid date-time was captured
                        }
                        else
                        {
                            //Starting in version 002, load sweep capture time too
                            int nLength = (int)binStream.ReadInt32();
                            string sTime = (string)binStream.ReadString();
                            if ((sTime.Length == nLength) && (nLength > 0))
                            {
                                objRead.CaptureTime = DateTime.Parse(sTime);
                            }
                        }

                        for (UInt16 nStep = 0; nStep < nTotalSteps; nStep++)
                        {
                            objRead.SetAmplitudeDBM(nStep, (float)binStream.ReadDouble());
                        }
                        Add(objRead);
                    }
                }
            }
            finally
            {
                if (myFile != null)
                    myFile.Dispose();
            }

            return true;
        }
        public bool Add(RFESweepData SweepData)
        {
            try
            {
                if (IsFull())
                    return false;

                if (m_MaxHoldData == null)
                {
                    m_MaxHoldData = new RFESweepData(SweepData.StartFrequencyMHZ, SweepData.StepFrequencyMHZ, SweepData.TotalSteps);
                }

                if (m_nUpperBound >= (m_arrData.Length - 1))
                {
                    if (m_bAutogrow)
                    {
                        ResizeCollection(10 * 1000); //add 10K samples more
                    }
                    else
                    {
                        //move all items one position down, lose the older one at position 0
                        m_nUpperBound = m_arrData.Length - 2;
                        m_arrData[0] = null;
                        for (int nInd = 0; nInd <= m_nUpperBound; nInd++)
                        {
                            m_arrData[nInd] = m_arrData[nInd + 1];
                        }
                    }
                }

                m_nUpperBound++;
                m_arrData[m_nUpperBound] = SweepData;

                for (UInt16 nInd = 0; nInd < SweepData.TotalSteps; nInd++)
                {
                    if (SweepData.GetAmplitudeDBM(nInd,null,false) > m_MaxHoldData.GetAmplitudeDBM(nInd,null,false))
                    {
                        m_MaxHoldData.SetAmplitudeDBM(nInd, SweepData.GetAmplitudeDBM(nInd,null,false));
                    }
                }
            }
            catch
            {
                return false;
            }

            return true;
        }
 public void CleanAll()
 {
     if (m_arrData != null)
     {
         Array.Clear(m_arrData, 0, m_arrData.Length);
     }
     m_arrData = new RFESweepData[m_nInitialCollectionSize];
     m_MaxHoldData = null;
     m_nUpperBound = -1;
 }
 public bool IsSameConfiguration(RFESweepData objOther)
 {
     return (Math.Abs(objOther.StartFrequencyMHZ - StartFrequencyMHZ) < 0.001 && Math.Abs(objOther.StepFrequencyMHZ - StepFrequencyMHZ) < 0.001 && (objOther.TotalSteps == TotalSteps));
 }
        public RFESweepData Duplicate()
        {
            RFESweepData objSweep = new RFESweepData(m_fStartFrequencyMHZ, m_fStepFrequencyMHZ, m_nTotalSteps);

            Array.Copy(m_arrAmplitude, objSweep.m_arrAmplitude, m_nTotalSteps);

            return objSweep;
        }
Beispiel #8
0
        private void CreateWaterfallTestData()
        {
            m_WaterfallSweepMaxHold.CleanAll();

            m_objRFEAnalyzer.AmplitudeBottomDBM = -100;
            m_objRFEAnalyzer.AmplitudeTopDBM = -10;

            UInt16 nTotalSteps = 100;

            for (UInt16 nMaxHoldInd = 0; nMaxHoldInd < nTotalSteps; nMaxHoldInd++)
            {
                RFESweepData objNewSweep = new RFESweepData(100.0f, 10.0f / 112, 112);
                m_WaterfallSweepMaxHold.Add(objNewSweep);

                for (UInt16 nSweepDataInd = 0; nSweepDataInd < objNewSweep.TotalSteps; nSweepDataInd++)
                {
                    float fAmplitude = -100.0f;
                    //a mark on the 6th position
                    if (nSweepDataInd == 5)
                    {
                        fAmplitude = -30.0f;
                    }
                    //every of the 10 divisions (112/10)
                    if ((nSweepDataInd % 12) == 0)
                    {
                        fAmplitude = -40.0f;
                    }
                    //A 15 steps band for the first half of the sweep time
                    if (nMaxHoldInd < 50)
                    {
                        if (nSweepDataInd > 35 && nSweepDataInd < 50)
                        {
                            fAmplitude = -50.0f;
                        }
                    }
                    //every 5 sweeps interval
                    if ((nMaxHoldInd % 10) < 5)
                    {
                        if (nSweepDataInd == 65)
                        {
                            fAmplitude = -30.0f;
                        }
                    }
                    objNewSweep.SetAmplitudeDBM(nSweepDataInd, fAmplitude);
                }
                Thread.Sleep(10); //to force some time difference between samples
            }
            UpdateWaterfall();
        }
        /// <summary>
        /// Internally adjust the sweep amplitude based on normalized amplitude objNormalizedAmplitudeReference provided
        /// </summary>
        /// <returns></returns>
        public bool NormalizeAmplitude(RFESweepData objNormalizedAmplitudeReference)
        {
            if (!IsSameConfiguration(objNormalizedAmplitudeReference))
                return false;

            for (UInt16 nInd = 0; nInd < TotalSteps; nInd++)
            {
                //normal realtime
                float dDB = GetAmplitudeDBM(nInd) - objNormalizedAmplitudeReference.GetAmplitudeDBM(nInd);
                SetAmplitudeDBM(nInd, dDB);
            }

            return true;
        }
 /// <summary>
 /// removes any prior loaeded normalization data
 /// </summary>
 public void ResetTrackingNormalizedData()
 {
     m_SweepTrackingNormalized = null;
     m_SweepTrackingNormalizedContainer = null;
 }
        /// <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);
            }
        }
        /// <summary>
        ///
        ///
        ///
        /// </summary>
        /// <param name="sFile"></param>
        /// <returns></returns>
        //

        /// <summary>
        /// Will load a RFE standard file from disk. If the file format is incorrect (unknown) will return false but will not invalidate the internal container
        /// If there are file exceptions, will be received by the caller so should react with appropriate error control
        /// If file is successfully loaded, all previous container data is lost and replaced by data from file
        /// </summary>
        /// <param name="sFile">File name to load</param>
        /// <param name="sModelText">model data text. If it is a normal sweep file, then this comes from spectrum analyzer. If it is tracking or normalization
        /// then this is from both signal generator and spectrum analyzer</param>
        /// <param name="sConfigurationText">configuration text. If it is a normal sweep file, then this comes from spectrum analyzer. If it is tracking or normalization
        /// then this is from Signal Generator and some required parameters from spectrum analyzer too.</param>
        /// <returns></returns>
        public bool LoadFile(string sFile, out string sModelText, out string sConfigurationText)
        {
            sConfigurationText = "Configuration info Unknown - Old file format";
            sModelText         = "Model Unknown - Old file format";

            FileStream myFile = null;

            try
            {
                myFile = new FileStream(sFile, FileMode.Open);

                using (BinaryReader binStream = new BinaryReader(myFile))
                {
                    myFile = null;

                    string sHeader = binStream.ReadString();
                    if ((sHeader != FileHeaderVersioned()) && (sHeader != FileHeaderVersioned_001()))
                    {
                        //unknown format
                        return(false);
                    }

                    double fStartFrequencyMHZ = binStream.ReadDouble();
                    double fStepFrequencyMHZ  = binStream.ReadDouble();
                    UInt32 nMaxDataIndex      = 0;
                    if (sHeader == FileHeaderVersioned_001())
                    {
                        //in version 001 we saved a 16 bits integer
                        nMaxDataIndex = binStream.ReadUInt16();
                    }
                    else
                    {
                        nMaxDataIndex = binStream.ReadUInt32();
                    }
                    UInt16 nTotalSteps = binStream.ReadUInt16();

                    if (sHeader != FileHeaderVersioned_001())
                    {
                        sConfigurationText = "From file: " + binStream.ReadString();
                        sModelText         = "From file: " + binStream.ReadString();
                    }

                    //We initialize internal data only if the file was ok and of the right format
                    CleanAll();
                    m_arrData = new RFESweepData[nMaxDataIndex];

                    for (UInt32 nSweepInd = 0; nSweepInd < nMaxDataIndex; nSweepInd++)
                    {
                        RFESweepData objRead = new RFESweepData((float)fStartFrequencyMHZ, (float)fStepFrequencyMHZ, nTotalSteps);

                        if (sHeader == FileHeaderVersioned_001())
                        {
                            objRead.CaptureTime = new DateTime(2000, 1, 1); //year 2000 means no actual valid date-time was captured
                        }
                        else
                        {
                            //Starting in version 002, load sweep capture time too
                            int    nLength = (int)binStream.ReadInt32();
                            string sTime   = (string)binStream.ReadString();
                            if ((sTime.Length == nLength) && (nLength > 0))
                            {
                                objRead.CaptureTime = DateTime.Parse(sTime);
                            }
                        }

                        for (UInt16 nStep = 0; nStep < nTotalSteps; nStep++)
                        {
                            objRead.SetAmplitudeDBM(nStep, (float)binStream.ReadDouble());
                        }
                        Add(objRead);
                    }
                }
            }
            finally
            {
                if (myFile != null)
                {
                    myFile.Dispose();
                }
            }

            return(true);
        }
        /// <summary>
        /// Saves a file in RFE standard format. Note it will not handle exceptions so the calling application can deal with GUI details
        /// Note: if there are sweeps with different start/stop frequencies, only the first one will be saved to disk
        /// </summary>
        /// <param name="sFilename"></param>
        public void SaveFile(string sFilename, string sModelText, string sConfigurationText, RFEAmplitudeTableData AmplitudeCorrection)
        {
            if (m_nUpperBound < 0)
            {
                return;
            }

            RFESweepData objFirst = m_arrData[0];
            int          nTotalSweepsActuallySaved = 0;

            //Save file
            FileStream myFile = null;

            try
            {
                myFile = new FileStream(sFilename, FileMode.Create);

                using (BinaryWriter binStream = new BinaryWriter(myFile))
                {
                    binStream.Write((string)FileHeaderVersioned());
                    binStream.Write((double)objFirst.StartFrequencyMHZ);
                    binStream.Write((double)objFirst.StepFrequencyMHZ);
                    //NOTE: if we have different values for start/stop, we are saying we have more than we actually saved
                    //This is why we will save these parameters later again with nTotalSweepsActuallySaved
                    binStream.Write((UInt32)m_nUpperBound);

                    binStream.Write((UInt16)objFirst.TotalSteps);
                    binStream.Write((string)sConfigurationText);
                    binStream.Write((string)sModelText);

                    for (int nSweepInd = 0; nSweepInd <= m_nUpperBound; nSweepInd++)
                    {
                        if (!m_arrData[nSweepInd].IsSameConfiguration(objFirst))
                        {
                            break;
                        }

                        //new in v002 - save date/time for each captured sweep
                        string sTime = m_arrData[nSweepInd].CaptureTime.ToString("o");
                        binStream.Write((Int32)sTime.Length);
                        binStream.Write((string)sTime);

                        nTotalSweepsActuallySaved++;
                        for (UInt16 nStep = 0; nStep < objFirst.TotalSteps; nStep++)
                        {
                            binStream.Write((double)m_arrData[nSweepInd].GetAmplitudeDBM(nStep, AmplitudeCorrection, AmplitudeCorrection != null));
                        }
                    }

                    //Save file fields again (will overwrite old ones), just to make sure nTotalSweepsActuallySaved is properly saved with actual value used
                    myFile.Seek(0, SeekOrigin.Begin);
                    binStream.Write((string)FileHeaderVersioned());
                    binStream.Write((double)objFirst.StartFrequencyMHZ);
                    binStream.Write((double)objFirst.StepFrequencyMHZ);
                    binStream.Write((Int32)nTotalSweepsActuallySaved);
                }
            }
            finally
            {
                if (myFile != null)
                {
                    myFile.Dispose();
                }
            }

            try
            {
                myFile = new FileStream(sFilename, FileMode.Open);

                using (BinaryWriter binStream = new BinaryWriter(myFile))
                {
                    myFile = null;

                    binStream.Write(FileHeaderVersioned());
                    binStream.Write(objFirst.StartFrequencyMHZ);
                    binStream.Write(objFirst.StepFrequencyMHZ);
                    binStream.Write(nTotalSweepsActuallySaved);
                }
            }
            finally
            {
                if (myFile != null)
                {
                    myFile.Dispose();
                }
            }
        }
 public bool IsSameConfiguration(RFESweepData objOther)
 {
     return(Math.Abs(objOther.StartFrequencyMHZ - StartFrequencyMHZ) < 0.001 && Math.Abs(objOther.StepFrequencyMHZ - StepFrequencyMHZ) < 0.001 && (objOther.TotalSteps == TotalSteps));
 }