Checking device status, while receiving data from serial port c# - c#

Life status of device connected via serial port.
Hello everyone.
How can I check if the device responds to the request? I'm googling this for couple days and tried lot of solutions also from SO, but nothing gave me results that I've expected. After lot of tries I'm in point described below. I think I'm very close but now I need little help, so thanks for every answer in advance.
The current situation
What am I doing right now is very simple. First of all I'm opening serial port serialPort.Open() at very beggining of app (data is receiving almost all the application running time).
As this is just an example in my form is only one label called labelStatus and labelStatus.Text = "Not connected"
Next I'm adding a timer and it's tick method, that contains execute of serialPort.Write(). Timer Interval is set to 100 if that matters.
private void timer_Tick(object sender, EventArgs e)
{
if (serialPort.IsOpen)
{
serialPort.WriteLine("r"); //I'm sending "r" message and device send data back
}
}
Next step is create DataReceived event like below (very simplified version, in my app received data is parsing to floats and storing in array, but it's just to show the problem)
private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string someVariable = serialPort.ReadLine();
labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Connected"));
//If i received something that means the device is plugged in and connection is correct (still very simplified)
}
One last thing is create ErrorReceived method.
private void serialPort_ErrorReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Not connected"));
}
Untill now everything works brilliant. Sending data works. DataReceived event is executig each 100 miliseconds when data is send. My data is received properly with no problems. When I start application labelStatus text is "Not connected" (device cable is not plugged in). When I plugged in device labelStatus text changing to "Connected". But now when I plugged of cable ErrorReceived event is not executing and labelStatus text is still "Connected". So as I've asked before: How can I check is device still connected to computer? (Or maybe: how to execute ErrorReceived event, when data is not receiving?).
Note: Serial port ReadTimeout is set to 300 miliseconds.
What have I tried
I've tried lot of things but this one in my head seems to should work but doesn't.
I've modified DataReceived event and I've put serialPort.ReadLine() into try/catch block with TimeoutException where I've tried to manually execute ErrorReceived method like below
private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
try
{
string someVariable = serialPort.ReadLine();
labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Connected"));
//If i received something that means the device is plugged in and connection is correct (still very simplified)
}
catch (TimeoutException)
{
serialPort_ErrorReceived(null, null);
}
}
I was hoping that will work like I want.
BTW. Sorry for my English. It's not perfect, but I do my best. Cheers!

Listen to the WM_DEVICECHANGE event that will be fired when a device is removed or inserted.
Here is an example of a implementation and some more information:
Detect serial port insertion/removal
http://www.codemiles.com/download/file.php?id=719 (USB Sample)
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363480(v=vs.85).aspx

This is solution in my case
Regarding to Martjin's answer i need to further explain my situation. First of all I want to say that I'm not installing any hardware into my computer, so in my opinion WM_DEVICECHANGE event was not what i need (but of course thanks for information, I've learned something new). Application is reading data from scale. Scale after plug into com port is not sending any data and actually there's no communication between it and computer at all. The only way to read data is to send request to scale, so I have to rely on that.
First try
The plan:
Add two static int fields (flags) checkOld and checkNew,
increment checkNew in DataReceived, check in timer Tick method
is checkOld is equal to checkNew. If true that means checkNew
was not increment, and that means DataReceived was not executed.
`
private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
checkNew++;
string someVariable = serialPort.ReadLine();
labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Connected"));
//If i received something that means the device is plugged in and connection is correct (still very simplified)
}
private void timer_Tick(object sender, EventArgs e)
{
if (serialPort.IsOpen)
{
serialPort.WriteLine("r"); //I'm sending "r" message and device send data back
}
if (checkOld == checkNew)
{
labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Not connected"));
}
}
`
The plan was good but when I've tested it result was not even good. What happened? Actually device status was blinking connected-not connected-connected-not connected etc. I've wrote some data to output and get answer. The timer was looping so fast that DataReceived event could not always increment checkNew value.
Final solution
Based on what I had at the moment I've decided to add some little changes. Instead of comparing two integers values try to collect couple last values ad check if all were the sem or not.
The plan:
Add three static fields: first six elements array of integers
statusArray, second integer index with value equals to 6 (last
element of array + 1), third integer checkNew,
increment checkNew in
DataReceived event,
in timer Tick event fill array to index,
decrement index value untill whole array is filled, and if index == 0 reset index value to
6,
and last check if last six values of checkNew, stored in
statusArray are the same. If true that means DataReceived did not
executed six times in a row, and now I can be sure that connection is
lost.
`
static int index = 6;
static int checkNew = 0;
static int[] statusArray = {0,0,0,0,0,0};
private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
checkNew++;
string someVariable = serialPort.ReadLine();
labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Connected"));
//If i received something that means the device is plugged in and connection is correct (still very simplified)
}
private void timer_Tick(object sender, EventArgs e)
{
if (serialPort.IsOpen)
{
serialPort.WriteLine("r"); //I'm sending "r" message and device send data back
}
if (index == 0)
index = 6;
index--;
int value = statusArray[index] = checkNew;
}
`

Related

C# to arduino communication

Good afternoon everyone,
I'm experimenting with serial communication between c# and arduino.
To understand how the comms work with regards to sending numbers (I know, there's alot being discussed already but bear with me) I want to send the value of a trackbar to the arduino, and then translate this number in movement of a servo.
If I understand correctly, integers can't be sent directly but have to be converted into bytes first.
So for this I would convert the numeric value of the trackbar into a byte array
in C# :
byte[] Numbers;
Numbers = BitConverter.GetBytes(trackBar1.Value);
Via serial communication I would send the value
port.Write(Numbers, 0, 1);
And this is where I'm going wrong I think
The trackbar value goes from 0 to 255, so I guess I'd need to know the bytes that equal 0 to 255 to be able to adjust the last number (in my example '1') to get the correct number after translation in Arduino?
As for Arduino, I would 'translate' the bytes as follows:
int IncomingValue = Serial.parseInt();
And then I'd like to use the IncomingValue for my servo.
My question is what I'm doing incorrectly.
thanks
For those interested in tinkering with c# to arduino serial communication (just desribing the issue I had) and sending a value of a trackbar to use in arduino:
make yourself a form project and name it whatever you like.
Then create a trackbar. I will create a trackbar with a minimum value of 0 and a maximum of 255 as follows:
trackbar1.Minimum = 0;
trackbar1.Maximum = 255;
trackBar1.TickFrequency = 10; // this will set ticks every 10 units.
Now we can setup the actual communication between c# and arduino. I'll start with c#.
Opening a port:
port = new SerialPort("COM5", 9600); //Set your Arduino COM port and baud rate
port.Open();
Now we also need to create an event to close the port when the program shuts:
void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (port != null && port.IsOpen)
{
port.Close();
}
}
Now we have set up the port, but we still need data to send. In our example we told we were going to send the value of the trackbar. To do this, click on your trackbar and find the trackBar1_Scroll event and double click it.
This basically creates the event of scrolling the trackbar and now we have to describe in this event what we want to happen.
We want to send the data of the trackbar via serial. The trackbar value is retrieved as follows:
trackbar1.value
Now we know how to retrieve the value, we have to look at the options of sending it, there's 3 options using port.write(), we'll use this later:
-Write(String)
-Write(Byte[], Int32, Int32)
-Write(Char[], Int32, Int32)
but as I'm working with an int, I found that the second one was the one I needed.
As you can see we need a Byte array to be able to send this, so we will cast our trackbar data into a byte array by using BitConverter and declaring a byte array called Numbers:
byte[] Numbers = BitConverter.GetBytes(trackBar1.Value);
Now we have every element we need:
The port which has been opened. We also described when to close it.
The trackbar and its data to send.
The data of the trackbar 'packaged' the correct way to be able to send it.
the only thing we didn't do is describe the scroll event, but now we have the correct data format, we can:
private void trackBar1_Scroll(object sender, EventArgs e)
{
byte[] Numbers = BitConverter.GetBytes(trackBar1.Value);
port.Write(Numbers, 0, 1);
}
so in c# our code will look like this:
public Form1()
{
InitializeComponent();
trackBar1.Minimum = 0;
trackBar1.Maximum = 255;
trackBar1.TickFrequency = 10;
port = new SerialPort("COM5", 9600);//Set your board COM
port.Open();
this.FormClosed += new FormClosedEventHandler(Form1_FormClosed);
}
void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (port != null && port.IsOpen)
{
port.Close();
}
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
byte[] Numbers = BitConverter.GetBytes(trackBar1.Value);
port.Write(Numbers, 0, 1);
}
As for arduino, all we need to do is:
A] Start our serial
B] Read the incoming data
#include <LiquidCrystal.h> // include the LCD library
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); //define the LCD display
int Number; //define the number int (the one we'll store our received trackbar value in)
void setup()
{
Serial.begin(9600); //A] Start our serial
}
void loop()
{
lcd.setCursor(0, 0); // Set the LCD cursor at the top left corner
if (Serial.available() > 0 ) { //B] Read the incoming data
nummer = Serial.read(); //
lcd.print(nummer); //
} //
else {}; //
}
I used an LCD to read the data as I couldn't figure out a way to open the serial monitor with the serial communication between c# and arduino happening.
that's why I included an LCD.
I feel explaining this is beyond the scope of this little issue I had.
I hope this helps other beginners like me in the future.
thanks to those who were helpful!

C# Serial Receive Limit

I am working on a project where I need to be able to communicate between C# and Arduino. I am stuck on an issue where I need to be able to start a timer in c# when data is received from the Arduino, then if the timer runs out, it triggers a relay to turn off power. The code looks something like this.
Arduino
char incoming_char=0;
#define RECEIVER_PIN A0
#define THRESHOLD 80
void setup() {
Serial.begin(9600); //for debug
pinMode(13, OUTPUT);
}
void loop() {
incoming_char=Serial.read();
// read the input on RECEIVER_PIN
int sensorValue = analogRead(RECEIVER_PIN);
if( sensorValue > THRESHOLD ) {
Serial.print("A"); //Send a letter back to VS
}
}
C#
public void TimerTick(object source, ElapsedEventArgs e)
{
Tick++;
System.Diagnostics.Debug.WriteLine("Ticking! " + Tick);
if (Tick > 10)
{
UPCTimer.Stop();
}
}
private void ArduinoSerial_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("We GOT DATA!");
if (UPCTimer.Enabled == false)
{
UPCTimer.Start();
System.Diagnostics.Debug.WriteLine("We started the timer!");
Tick = 0;
}
Right now when the laser is triggered, it just spams WE GOT DATA endlessly until it the item passes through. What I would like to be able to do, is only act on the first character that's sent to VS from the Arduino, then ignore all the other input until the timer is disabled again. is there anyway to do this?
You can add code to the arduino firmware to wait for the analogue signal to drop below the threshold, possibly with hysteresis before allowing for data to be sent again.
Ie add a tripped variable when threshold is tripped to true or 1. Check this value when checking the threshold:
if( tripped == 0 && sensorValue > THRESHOLD )
{
tripped = 1;
//send A to serial port
}
else if( sensorValue < THRESHOLD - hysteresis )
{
tripped = 0;
}
Arduino_DataReceived is an event handler. Something has to subscribe to the event in order for it to do anything. Somewhere in your setup code, you have a line like:
ArduinoSerial.DataReceived += ArduinoSerial_DataReceived;
If you want to ignore this data until the timer is disabled, then immediately after you say "We GOT DATA!" you can unsubscribe by adding a line like:
ArduinoSerial.DataReceived -= ArduinoSerial_DataReceived;
And then you can subscribe again once you are ready to start receiving again.
An alternate approach is to use a class-level boolean to flag when you are ignoring input. Wrap all of your c# code in something like if (!Ignoring) { } and set Ignoring to true inside that block so that all subsequent calls are ignored. When you are ready to start responding again, just set Ignoring back to false.

How to store data through web service when data coming to my serial port will be asynchronous?

I have one device "installed" on a users desk (a desk is nothing but a chair or table on which user will sit), and I will be supporting thousands of desks.
A user will have one "chip" and the user will scan this chip on the device which is installed on their desk.
The device will read the data off the chip and will send it to my laptop which will also have one of the devices installed, except this device is the main device responsible for collecting all user scan chip data.
All the data will be routed to my device via a wifi router and I will listen to this from my Main device and read data from this device from my laptop via serial port connection.
This data sending will happen as each user number scans his/her chip.
I have created a windows form application which will continuously run in the background on my laptop, and will be listening to my serial port on which main device is connected.
This is my code taken from here: Source Code Reference:
public partial class MainUI : Form
{
SerialPortManager _spManager;
public MainUI()
{
InitializeComponent();
UserInitialization();
}
}
private void UserInitialization()
{
_spManager = new SerialPortManager();
_spManager.NewSerialDataRecieved += new EventHandler<SerialDataEventArgs>(_spManager_NewSerialDataRecieved);
this.FormClosing += new FormClosingEventHandler(MainUI_FormClosing);
}
private void MainUI_Load(object sender, EventArgs e)
{
_spManager.StartListening()
}
void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int dataLength = _serialPort.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = _serialPort.Read(data, 0, dataLength);
if (nbrDataRead == 0)
return;
// Send data to whom ever interested
if (NewSerialDataRecieved != null)
{
NewSerialDataRecieved(this, new SerialDataEventArgs(data));
}
}
void _spManager_NewSerialDataRecieved(object sender, SerialDataEventArgs e)
{
if (this.InvokeRequired)
{
// Using this.Invoke causes deadlock when closing serial port, and BeginInvoke is good practice anyway.
this.BeginInvoke(new EventHandler<SerialDataEventArgs>(_spManager_NewSerialDataRecieved), new object[] { sender, e });
return;
}
//data is converted to text
string str = Encoding.ASCII.GetString(e.Data);
if (!string.IsNullOrEmpty(str))
{
//Here i will store that data in to my database through web service.
//What i should use whether WCF service or Web Api because data will be continuos like at a
//time more than 10 or 100 user can scan data at the same time so this event will be fired continuously.
//I am using entity framework to store data in to my database and how to ansynchornously call web service to store my data
//so that my call doesnt block incoming data to serial port
}
}
My main concern is I will have numerous users who will scan data at the same time and how I will handle when more than 10 or 100 user scan the data at the same time.
How can I mitigate this potential issue?
Ok, if i got the question right you need to do something like this ...
void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int dataLength = _serialPort.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = _serialPort.Read(data, 0, dataLength);
if (nbrDataRead == 0)
return;
// Send data to api
string str = Encoding.ASCII.GetString(e.Data);
if (!string.IsNullOrEmpty(str))
{
var api = new HttpClient();
api.BaseUrl("http://somewhere.com");
api.PostAsJsonAsync("api/Something", str)
}
if (this.InvokeRequired)
{
// Using this.Invoke causes deadlock when closing serial port,
// and BeginInvoke is good practice anyway.
this.BeginInvoke(new EventHandler<SerialDataEventArgs>(
_spManager_NewSerialDataRecieved), new object[] { sender, e
});
return;
}
}
// i think this can go completely ...
void _spManager_NewSerialDataRecieved(object sender, SerialDataEventArgs e)
That posts the data to webapi but whilst that post is taking place on another thread the serial port can carry on receiving data
close your serial port and load every some-amount-of-time. After that some-amount-of-time open the port and scan all devices, then close it again.
public void MainUI.Load(Object sender, Eventargs e)
{
if (_spmanager != null && !_spManager.IsOpen)
//*write the code here where it opens and starts listening
_spmanager.StartListening();
//*write the code here where it waits a little bit then
_spmanager.Close();
}
Therefore everytime it loads it starts when the port is closed, it opens for a little bit, scans whatever values are true and then closes again.
I am not very sure about this but it is just an idea of how to handle it. The code might not be accurate or currect I just wrote it quickly. Take the idea from this

MSVS C# SerialPort Received Data Loss

I'm trying to create a Serial Communication tool on MSVS using C#. it communicates with the Photon MCU and a bluetooth dongle.
When the "start" button is pressed, the UI sends a "1" to the Photon which it first sends the current time stamp and starts streaming data from the function generator. When the "stop" button is pressed, It first sends 10 "2"s (due to the timer issue on the photon's end) which the when the Photon receives, it stops transmitting the function generator's data. Then it sleeps for a second and sends a "3" which it sends another current time stamp. Then the UI discards data in the InBuffer and stops reading data.
connectBT is connected with the start button and the disconnectBT is connected with the stop button.
This is the code that I have right now:
SerialPort serial = new SerialPort();
string recieved_data;
int startBuffer = 0;
private void connectBT(object sender, RoutedEventArgs e)
{
startBuffer++; // keep track of BT open counter
if (serial.IsOpen) Debug.WriteLine("BT Open");
// first time BT is open and BT is not open
if (!serial.IsOpen)
{
if (startBuffer == 1)
{
// COM port properties
serial.PortName = "COM7";
serial.BaudRate = 38400;
serial.Handshake = Handshake.None;
serial.Parity = Parity.None;
serial.DataBits = 8;
serial.StopBits = StopBits.One;
serial.ReadTimeout = 200;
serial.WriteTimeout = 50;
serial.Open();
}
startButton.Content = "Recording";
Send_Data("1"); // tell Photon to start sending data
serial.DiscardInBuffer(); // discard whatever is in inbuffer
serial.DataReceived += new SerialDataReceivedEventHandler(Recieve); // start receiving data
}
// after BT has been opened and start button has been pressed again
else if (serial.IsOpen && startBuffer > 1)
{
startButton.Content = "Recording";
Send_Data("1");
serial.DiscardInBuffer();
serial.DataReceived += new SerialDataReceivedEventHandler(Recieve);
}
}
// stop button is pressed
private void disconnectBT(object sender, RoutedEventArgs e)
{
// send "2" ten times to tell photon to stop transmitting function generator data
int i = 0;
while (i < 10)
{
Send_Data("2");
Thread.Sleep(1);
i++;
}
Thread.Sleep(1000);
Send_Data("3"); // send a 3 to tell photon to send the last time stamp
Thread.Sleep(1000);
serial.DiscardInBuffer(); // discard in buffer
serial.DataReceived -= Recieve; // stop receiving data
//serial.Close(); // close BT
startButton.Content = "Start";
}
private void Recieve(object sender, SerialDataReceivedEventArgs e)
{
recieved_data = serial.ReadLine();
Debug.WriteLine(recieved_data);
}
I'm running into an issue where when I press the "stop" button, the last chunk of data that was sent from the bluetooth is lost. I never receive the last time stamp that I'm supposed to have received when the stop button is pressed. According to our math, we're supposed to be receiving 500 points per second (500Hz) but I only receive about 100 of them.
My theory is that the UI is receiving data at a slower (or a delayed) rate and the serial.DiscardInBuffer discard the received data even before that the data can be printed to the Debug output. I know for a fact that all the data between the first and last I receive are all there because of counter values associated with the data packets. Basically if I were to receive 1~500 data points, I only receive 1~100. I've also tried it with just termite with sending 1,2, and 3 as the UI is supposed to be and I get all the data as I need them. I don't close BT on purpose.
What can I do to prevent this data loss? What am I doing wrong in my code that I shouldn't be doing or be doing for the correct bluetooth protocol? This is my first time writing bluetooth code so I'm fairly unfamiliar with it.
Not sure if that's the cause of your problem, but your Receive has a very big pitfall.
You only read one line per Receive event, and on one event there can be more than one line to read, then they are being accumulated and discarded at the end.
ReadLine is meant to be used in a synchronous way like an stream where you read one line, process it then you write, not to be used with the DataReceived event.
You have two options: spin a new thread in a continuous loop reading with serial.ReadLine() (it will block until a new line is available) or the better approach, read the serial buffer on each Receive event.
To do it like that you can do smething like this:
List<byte> tmpBuffer = new List<byte>();
static byte newLineB = Encoding.ASCII.GetBytes("\n")[0];
void Receive(object sender, SerialDataReceivedEventArgs e)
{
lock (tmpBuffer)
{
while (serial.BytesToRead > 0)
{
byte[] segment = new byte[serial.BytesToRead];
serial.Read(segment, 0, segment.Length);
tmpBuffer.AddRange(segment);
ProcessBuffer();
}
}
}
private void ProcessBuffer()
{
int index = 0;
while ((index = tmpBuffer.IndexOf(newLineB)) > -1)
{
string line = Encoding.ASCII.GetString(tmpBuffer.Take(index + 1).ToArray());
//Do whatever you need to do with the line data
Debug.WriteLine(line);
tmpBuffer.RemoveRange(0, index + 1);
}
}
As you can see, the received data is being stored on a temporal list used as a buffer (yes, an array and using Buffer functions would be faster, but for small messages and for simplicity a list is enough for most cases), then the received data is added to the buffer and when there are no more bytes left the list is processed in search of string lines.
Also note the read is in a loop, I have run in cases where there were data received while the function was being executed and no receive event was fired, so the better for this is to create a loop to read while there is still data.
Thank you all for your response, they all helped me reaching the solution for my issue, but in the end what fixed it was delaying the time between sending the "3" and discarding my inBuffer and closing the Receive connection.
async Task DelayBT()
{
await Task.Delay(100);
}
Thread.Sleep() didn't work because of its nature disabling all action within the thread (which I still needed) so this method worked like a charm. I just called await DelayBT where I needed the delay.
Hope this helps anyone running into the same issue as me.

For serial port programming in C#, When I am in the middle of a DataRecived handler, how can I jump into another DataRecieved Handler

I have a serial port and a bunch of DataRecieved handler, I want one to be activated at some point if a certain condition is true in another handler.
For example
// write some message to StartCommHandler
private void StartCommHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
byte[] startComResp = new byte[7];
if (sp.BytesToRead < 7)
return;
else
sp.DataReceived -= StartCommHandler;
sp.Read(startComResp, 0, startComResp.Length);
if ( //true response)
{
// enable StartMeasureHandler and write to it:
sp.DataReceived += StartMeasureHandler;
// write some message to StartCommHandler
}
else
{
// enable StartCommHandler and write to it again:
sp.DataReceived += StartCommHandler;
// write the message to StartCommHandler
}
// some other code that should not be read if else is selected
}
private void StartMeasureHandler(object sender, SerialDataReceivedEventArgs e)
{
//some code
}
when I enable the "StartMeasureHandler" and write to it, I expect that I should jump to it and the rest of the code should be ignored. But it continues reading the rest of the code in the "StartCommHandler" .
In other words, how should I jump out of one handler to another handler
p.s.: I know that I can put codes in if else statement, but I still need to know a solution to my issue to solve a more complicated problem.
Thanks
TL;DR: There's only one good way to deal with serial stream -- with a state machine. Make the compiler write that state machine for you and be happy.
Even better than swapping event handler is to not use the DataReceived event at all. Use sp.BaseStream.ReadAsync. Then you can write all your data handling code in blocking style which is easy, and the compiler will convert it to continuation-passing style, which performs well.
No threading to mess with. And it bypasses the most buggy parts of the SerialPort class.
I've written a blog post on the subject, which you can read for more details on why to avoid DataReceived and BytesToRead.
You should just be able to call
if ( /*true response*/)
{
sp.DataReceived += StartMeasureHandler;
StartMeasureHandler(object sender, SerialDataReceivedEventArgs e);
return;
}
// ...
It is still just a function.

Categories

Resources