Jan Kowalski
Jan Kowalski

Reputation: 45

Problem with passing constantly reading serial buffer data to another class

Long story short. ; I have a class named Scope. And this class contains all logic for scope operations etc. It also starts backround thread that constantly read serial port data (in my case events was unreliable):

  Thread BackgroundReader = new Thread(ReadBuffer);
    BackgroundReader.IsBackground = true;
    BackgroundReader.Start();

  private void ReadBuffer()
        {
            SerialPort.DiscardInBuffer();
            while (!_stopCapture)
            {
                int bufferSize = SerialPort.BytesToRead;
                byte[] buffer = new byte[bufferSize];
                if(bufferSize > 5)
                {
                    SerialPort.Read(buffer, 0, bufferSize);
                    Port_DataReceivedEvent(buffer, null);
                }
                Thread.Sleep(_readDelay);
            }
            CurrentBuffer = null;
        }

In Scope class there is a public field named Buffer

public byte[] Buffer
        {
          get
            {
                return CurrentBuffer;
            }
        }

And here is event fired while there is new data readed

 private void Port_DataReceivedEvent(object sender, EventArgs e)
        {
            //populate buffer
            Info(sender, null);
            CurrentBuffer = ((byte[])sender);

            foreach(byte data in CurrentBuffer)
            {
                DataBuffer.Enqueue(data);
            }

            if (DataBuffer.Count() > _recordLength)
            {
                GenerateFrame(DataBuffer.ToArray());
                DataBuffer.Clear(); ;
            }
        }

To make code more manageable, I splitted it in several classes. One of this classes is for searching specific data pattern in current stream and create specific object from this data. This code works in way that send to serial port specific command and expect return frame. If reponse is not received or not ok, send is performed again and again until correct response arrives or there will be timeout. Response is expected to be in current buffer. Those strange string manipulation is for debug purposes.

public class GetAcknowledgedFrame
    {
        byte[] WritedData;
        string lastEx;
        string stringData;

        public DataFrame WriteAcknowledged(Type SendType, Type ReturnType, JyeScope scope)
        {
            var stopwatch = new Stopwatch();
            stopwatch.Restart();
            while (stopwatch.ElapsedMilliseconds < scope.TimeoutTime)
            {
                try
                {
                    if (SendType == typeof(GetParameters))
                    {
                        WriteFrame(new ScopeControlFrames.GetParameters(), scope.SerialPort);
                    }
                    else if(SendType == typeof(GetConfig))
                    {
                        WriteFrame(new ScopeControlFrames.GetConfig(), scope.SerialPort);
                    }
                    else if (SendType == typeof(EnterUSBScopeMode))
                    {
                        WriteFrame(new ScopeControlFrames.EnterUSBScopeMode(), scope.SerialPort);
                    }
                    return ReturnFrame(ReturnType, scope.Buffer, scope.TimeoutTime);
                }
                catch (InvalidDataFrameException ex)
                {
                    lastEx = ex.Message;
                    System.Threading.Thread.Sleep(10);
                }
            }
            stringData = "";
            foreach (var data in scope.Buffer)
            {
                stringData += data + ",";
            }
            stringData.Remove(stringData.Length - 1);
            throw new TimeoutException($"Timeout while waiting for frame acknowledge: " + SendType.ToString() + ", " + ReturnType.ToString() + Environment.NewLine+ "Add. err: "+lastEx);
        }


        private DataFrame ReturnFrame(Type FrameType, byte[] buffer, int timeoutTime)
        {
            if (FrameType == typeof(DataFrames.DSO068.CurrConfigDataFrame))
            {
                DataFrames.DSO068.CurrConfigDataFrame CurrConfig = new DataFrames.DSO068.CurrConfigDataFrame(buffer);
                return CurrConfig;
            }
            else if (FrameType == typeof(DataFrames.DSO112.CurrConfigDataFrame))
            {
                DataFrames.DSO112.CurrConfigDataFrame CurrParam = new DataFrames.DSO112.CurrConfigDataFrame(buffer);
                return CurrParam;
            }
            else if (FrameType == typeof(CurrParamDataFrame))
            {
                CurrParamDataFrame CurrParam = new CurrParamDataFrame(buffer);
                return CurrParam;
            }
            else if (FrameType == typeof(DataBlockDataFrame))
            {
                DataBlockDataFrame CurrData = new DataBlockDataFrame(buffer);
                return CurrData;
            }
            else if (FrameType == typeof(DataSampleDataFrame))
            {
                DataSampleDataFrame CurrData = new DataSampleDataFrame(buffer);
                return CurrData;
            }
            else if (FrameType == typeof(ScopeControlFrames.ScopeReady))
            {
                ScopeControlFrames.ScopeReady ready = new ScopeControlFrames.ScopeReady(buffer);
                return ready;
            }
            else
            {
                throw new InvalidOperationException("Wrong object type");
            }
        }

        private bool WriteFrame(DataFrame frame, IStreamResource port)
        {
            WritedData = frame.Data;
            port.Write(frame.Data, 0, frame.Data.Count());
            return true;
        }
    }

From main class (and main thread) I call method in this class, for example:

 var Ready = (ScopeControlFrames.ScopeReady)new GetAcknowledgedFrame().WriteAcknowledged
                            (typeof(ScopeControlFrames.EnterUSBScopeMode), typeof(ScopeControlFrames.ScopeReady), this);

The problem is when I pass "this" object (that has thread working in background) to my helper class. It seems like helper class not see changing data in this object. The problem started when I separate code of my helper class from main class. My questions: - I know that object are passed by reference, that means I think that when object is dynamically changing its state (in this case data buffer should changing while new data is received) all classes that has reference to this object are also seeing this changes. Maybe I'm missing something? - I tried passing array (by ref), arrays are also reference types. But this not help me at all. Maybe I'm missing something? I tried changing this class to static, it not helped. Many thanks for help.

Upvotes: 0

Views: 128

Answers (1)

PhillipH
PhillipH

Reputation: 6222

The code below;

Info(sender, null);
CurrentBuffer = ((byte[])sender);

is creating a new reference variable called CurrentBuffer. Any other code holding a reference 'pointer' to the CurrentBuffer value prior to this line of code will not get the new value of CurrentBuffer when its reset.

Upvotes: 1

Related Questions