We are developing WinCE SerialPort Application on .net compact framework 3.5.
In The serialPort Class we have DataReceived event, un fortunately it is firing only once.
Our serialport settings are below:
_com = new SerialPort();
_com.PortName = str_comport;
_com.BaudRate = pBaudRate;
_com.ReadTimeout = 1000 * 10 * 1;
_com.WriteTimeout = 1000 * 10 * 1;
_com.Handshake = Handshake.None;
_com.ReceivedBytesThreshold = 1;
_com.RtsEnable = true;
_com.DtrEnable = true;
_com.Parity = pParity;
_com.DataBits = pDataBits;
_com.StopBits = pStopBits;
_com.DataReceived += new SerialDataReceivedEventHandler(this.Receive);
_com.Open();
....
private void Receive(object sender, SerialDataReceivedEventArgs e)
{
_receivedString = _port.ReadExisting();
_log.WriteFile("RX : " + _receivedString);
}
We have tried opening port first and attaching data received Event also but of no use.
and the same code works fine on Windows XP/Windows 7 Machine.What could be the possible reason.
We need to know more about what your expectation and the data coming in looks like. What does your Receive method look like?
The ReceivedBytesThreshold can be thought of as a trigger point on the input buffer. When the buffer size goes past that, only in a forward direction, you get an event. In this case it means when the receive buffer size goes from 0 to 1 byte, you'll get an event. You won't get one from, say 200 to 201. You don't get an event for every byte either.
So to make this effective, when you receive the event, you need to read all data from the buffer, bringing its size back to zero and effectively "resetting" the event trigger.
Related
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!
this is my first question on here, since I couldn't find it answered anywhere.
I am not particularly new to WPF and C#, but I've never read SerialData with it before, and I'm having rudimentary problems I'm sure.
Setup:
Arduino clone (SparkFun Pro Micro) sending "Hello!" + a number to the USB serial port (COM5) once every second:
String hello = "hello!";
Serial.println(hello + i);
i++;
delay(1000);
And trying to receive it in WPF, with a simple button that refreshes the data to a TextBlock (tbData).
SerialPort sp = null;
String str = null;
int i = 0;
public MainWindow()
{
InitializeComponent();
sp = new SerialPort("COM5", 9600);
sp.DataReceived += new SerialDataReceivedEventHandler(ReceiveData);
sp.Open();
}
void ReceiveData(object sender, SerialDataReceivedEventArgs e)
{
str = sp.ReadLine();
}
private void Refresh_Click(object sender, RoutedEventArgs e)
{
tbData.Text = str;
}
But nothing happens, I seem to be getting an empty string, since the TextBlock doesn't show anything when I press the Refresh_Click button.
I can get it to work with a new Thread, but it keeps timeouting, and I read on here (Timeouts in C# serial port) that the best (and simplest it seems) method is using a SerialDataReceived event.
t = new Thread(() =>
{
int i = 0;
while (run)
{
SerialString = sp.ReadLine();
Thread.Sleep(1000);
}
sp.Close();
});
What I am missing must be something along the lines of changing the size of the buffer? Or something similar?
It seems I've found the answer!
I am pretty clueless about Serial communications, but today I came across the MODE cmd function:
C:\Users\Username>mode
Status for device COM5:
-----------------------
Baud: 9600
Parity: None
Data Bits: 8
Stop Bits: 1
Timeout: ON
XON/XOFF: OFF
CTS handshaking: OFF
DSR handshaking: OFF
DSR sensitivity: OFF
DTR circuit: OFF
RTS circuit: OFF
And I noticed that it changed whenever I had the Arduino IDE report the data to me - which it would always do successfully! - and whenever I tried to make WPF do the same.
Above is the MODE return after I tried to run my own code, and:
Status for device COM5:
-----------------------
Baud: 9600
Parity: None
Data Bits: 8
Stop Bits: 1
Timeout: OFF
XON/XOFF: OFF
CTS handshaking: OFF
DSR handshaking: OFF
DSR sensitivity: OFF
DTR circuit: ON
RTS circuit: ON
this is what it showed after opening Tools>Serial monitor in the Arduino IDE, and closing it again immediately.
I changed my WPF code from:
sp = new SerialPort("COM5", 9600);
sp.Open();
to:
sp = new SerialPort("COM5", 9600);
//sp.ReadTimeout = 200;
sp.DtrEnable = true;
sp.RtsEnable = true;
sp.DataBits = 8;
sp.StopBits = StopBits.One;
sp.Open();
And now both the threading example and the SerialDataReceived event runs smoothly (well, except I can't update a UI thread within a SerialDataReceived thread).
I hope someone out there finds this useful.
For some research of network activity on my private network, I came across NightHawk. So after downloading and testing, I tried to print out some Tcp packets when "sniffing". This worked for me very fine.
But when clicking the "stop button", the sniff function pauses for around 3 seconds and resumes sniffing to the network and printing arriving packets.
After searching for the missing -= of a "sniffing to the network" event handler, I found one and fixed it. BUT the problem is still active.
So for some reason - I can't find out - the OnPacketArrival event is still "alive" AND called from somewhere, even though I stopped capturing AND removed the event handler.
Edit:
As requested, here is some code:
// start listening on a device (combobox index)
public void StartDevice(int deviceIndex)
{
Started = true;
DeviceInfo = DeviceInfoList[deviceIndex];
Device = WinPcapDeviceList.Instance[deviceIndex];
Sniffer = new Sniffer(DeviceInfo);
ARPTools = new ARPTools(DeviceInfo);
NDTools = new NDTools(DeviceInfo);
SSLStrip = new SSLStrip();
Scanner = new Scanner(DeviceInfo);
Sniffer.SnifferResult += new SnifferResultHandler(sniffer_OnSnifferResult);
SSLStrip.SSLStripped += new SSLStripHandler(SSLStrip_OnSSLStripped);
Scanner.ScannerResponse += new ScannerResponseReceived(scanner_OnResponse);
Scanner.ScanComplete += new ScannerEventHandler(scanner_OnScanComplete);
Scanner.HostnameResolved += new ScannerHostnameResolvedHandler(scanner_HostnameResolved);
// open device, set filters & events, start capturing
Device.Open(DeviceMode.Promiscuous, 1);
Device.Filter = "(arp || ip || ip6)";
Device.OnPacketArrival += device_OnPacketArrival; // Subscribe the event for arriving packets
Device.StartCapture();
}
// stop listening on a device
public void StopDevice()
{
Started = false;
if (Device == null) return;
Device.StopCaptureTimeout = TimeSpan.FromMilliseconds(200);
Device.StopCapture();
Device.OnPacketArrival -= device_OnPacketArrival; // This is to unsubscribe the event. This was coded by me
Device.Close();
}
So has someone an explanation for this?
Thanks in advance!
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.
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;
}
`