0

I'm currently write a method that read data consecutively from serial port in C# winform for .NET framework.

I write an event handler for it, but since its static, i cannot call variable from outside. Now i'm thinking of how to getting data from the static method to outside. Like share data between static method and normal method.

Ofc this won't work correctly. I want sp variable go into mySerialPort but i don't know how.

private void GetComPortData()
{
    SerialPort mySerialPort = new SerialPort("COM5");
    mySerialPort.BaudRate = 115200;
    mySerialPort.Parity = Parity.None;
    mySerialPort.StopBits = StopBits.One;
    mySerialPort.DataBits = 8;
    mySerialPort.Handshake = Handshake.None;
    mySerialPort.RtsEnable = true; //change to false if not need rts
    mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
    mySerialPort.Open();
    

    //how to make mySerialPort = sp?
    //string dataComPort = mySerialPort.ReadExisting();
    var data = dataComPort.Split(new[] { '/' },4);
    /*Do some work to show data in datagridview*/
    mySerialPort.Close();
}
//handle comport data
private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
    SerialPort sp = (SerialPort)sender;
    string indata = sp.ReadExisting();
}

I also tried to change static to other reference type, but it doesn't work. Any help is much appreciated.

2
  • 2
    Seems to me that your DataReceivedHandler doesn't need to be static. I'm sure you have a good reason for making it that way, but please explain your thinking.
    – IV.
    Commented Nov 27, 2023 at 13:42
  • You would have do the datagridview display in the DataReceivedHandler. And of course you are not allowed to call mySerialPort.Close(); inside GetComPortData, because this will happen immediately after opening the port and not wait for data to be received. DataReceivedHandler will most likely receive the data after GetComPortData has returned. Commented Nov 27, 2023 at 13:43

1 Answer 1

1

In addition to the excellent comment by Olivier about 'not closing' the serial port, there is also the likelihood of DataReceived being on a different thread. You may have to BeginInvoke to prevent a cross-threading exception if you plan to "do some work to show data in datagridview". I used to do this sort of thing quite a lot and here's an example of what worked for me for receiving the event and then locking a critical section while the handler loops to get "all" (may require some kind of throttling) of the data available in the buffer while displaying chunks <= 16 bytes in the DGV.

data grid view


Set up DataGridView

public partial class MainForm : Form
{
    public MainForm() =>InitializeComponent();
    BindingList<DataReceived> DataSource { get; } = new BindingList<DataReceived>();
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        dataGridView.DataSource = DataSource;
        dataGridView.AllowUserToAddRows = false; // Critical for this example.
        dataGridView.Columns[nameof(DataReceived.Timestamp)].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
        dataGridView.Columns[nameof(DataReceived.Data)].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;

        MockSerialPort mySerialPort = new MockSerialPort("COM5");
        mySerialPort.BaudRate = 115200;
        mySerialPort.Parity = Parity.None;
        mySerialPort.StopBits = StopBits.One;
        mySerialPort.DataBits = 8;
        mySerialPort.Handshake = Handshake.None;
        mySerialPort.RtsEnable = true;
        mySerialPort.DataReceived += DataReceivedHandler;
        mySerialPort.Open();
    }
    .
    .
    .

Handle DataReceived

    .
    .
    .
    SemaphoreSlim _criticalSection = new SemaphoreSlim(1, 1);
    private async void DataReceivedHandler(object sender, MockSerialDataReceivedEventArgs e)
    {
        await _criticalSection.WaitAsync();
        if(!IsDisposed) BeginInvoke((MethodInvoker)delegate 
        {
            try
            {
                if (sender is MockSerialPort port)
                {
                    while (port.BytesToRead > 0)
                    {
                        byte[] buffer = new byte[16];
                        int success = port.Read(buffer, 0, buffer.Length);
                        string display = BitConverter.ToString(buffer, 0, success).Replace("-", " ");
                        var data = new DataReceived { Data = display };
                        DataSource.Add(data);
                    }
                }
            }
            finally
            {                    
                _criticalSection.Release();
            }
        });
    }
}

class DataReceived
{
    public string Timestamp { get; } = DateTime.Now.ToString(@"hh\:mm\:ss\.fff tt");
    public string? Data { get; set; }
}

I used a MockSerialPort to test this. Full Code

Not the answer you're looking for? Browse other questions tagged or ask your own question.