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.
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.
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