Creating and keeping a stream alive in c# - c#

I'm using the pretty nifty nmeasharp project to decipher an NMEA stream I'm receiving on a serial port in c#. It all works fine out of the box, but I want to mirror the data to an IP address, and am getting stuck.
The nmeasharp package gets it's data from any stream, so I used to hook it up to the serial port stream, which worked fine:
_nmeaParser.Source = serialport.BaseStream;
Now, I want to use the serial port event to trigger my own routine, where I can redirect the data, so i remove the assignment above, and set:
_serialport.DataReceived += new serialDataReceivedEventHandler(HandleNewSerialPortData);
This event is triggered, and the method gets called. All good at this point, but the nmeasharp code is still looking for a stream to listen to, since I haven't assigned it to a stream anymore.
The following method is where I need to set up a stream to nmeasharp, and write whatever new data the serial port has just received out to that stream.
private void HandleNewSerialPortData(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
this.serialDataAvailable(indata); // raise event that writes string to IP
if (_nmeaParser.Source == null) _nmeaParser.Source = new MemoryStream(840);
if (_nmeaParser.Source.CanWrite) _nmeaParser.Source.Write(ASCIIEncoding.UTF8.GetBytes(indata), 0, indata.Length);
// Unsuccessful attempts
// MemoryStream s = new MemoryStream(ASCIIEncoding.UTF8.GetBytes(indata));
// s.CopyTo(_nmeaParser.Source);
// sp.BaseStream.CopyTo(this.NmeaDataStreamFromSerialPort);
}
I've tried several variations of trying to write to the nmeasharp stream, but none work. One that showed promise was initialising a new stream every time, but that meant that the stream was closed after every DataReceived event, which truncated and missed out serial messages. The (unsuccessful) code was:
_nmeaParser.Source = new MemoryStream(ASCIIEncoding.UTF8.GetBytes(indata));
I've read lots of tutorials, read all the msdn documentation I could find, and still can't get this simple thing working. This has to be easy, right...?
Edit: I would like to keep the nmeasharp code stock if possible, as it works fine, and as the serial data isn't always ASCII, would like to keep it binary (streams) rather than sending it the data as a string. I can fix up the IP redirection for binary later.
Thanks.

I would try to create two streams. Read from the serial stream manually, and copy to both streams.
Set the nmeaParser to use one of them, and have the IP handler read from the second one.
You can look here for a good solution on how to copy streams.

Related

C# - Bluetooth programming

In my program, I send a command to a device and it sends some data back. Whenever the data is available, the following event handler gets invoked.
private void notify_change(GattCharacteristic sender, GattValueChangedEventArgs args)
{
lock (this._dataRec)
{
notCounter++;
byte[] bArray = new byte[args.CharacteristicValue.Length];
DataReader.FromBuffer(args.CharacteristicValue).ReadBytes(bArray);
dataQ.Enqueue(Encoding.ASCII.GetString(bArray));
Monitor.Pulse(this._dataRec);
}
}
Sometimes, I noticed that this gets called before previous data has been read (or something like that; from the list of commands, data seems to be missing). Looks like the buffer gets overwritten whenever the function is invoked. Is there a way to add data to the buffer rather than overwriting it?
In my program, I send a command to a device and it sends some data
back.
Since you are trigger response by your calls, be sure that you don't make buffer overflow on device side. Minimal theoretical gap between two packets is 7.5ms but in practice it is about 20-30ms. So if you are sending in a loop, your device will lost (overwrite) packets if gap is less than your HW setup can handle.
The GATT protocol has two options to receive unsolicited information. They are notifications and indications. notifications are one with out acknowledgement from the receiver where as indications require an acknowledgment from the receiver. so you probably need indications and if this is not an option you need to ensure that the data is copied before the next notification.
see the following from the Bluetooth specification.

C# Serialport or USB HID connection?

For my project I need to communicate with an Cypress PSoC5. I can use a serial connection or a USB HID connection.
I created a C# project for sending and reading data to/from PSoC5. Right now I'm using the ReceivedData event of the serialport to get notified if there is new data. Basically my project can either receive a datastream that should be plotted in realtime or just some settings I want to update within the GUI.
Right now I face the problem that the ReceivedData event fires very often (every 32 bytes), which is of course not good when there is a datastream. Basically I receive 24000 bytes per second if I get data for the plot. I know I can adjust the ReceivedBytesThreshold, but then I will not get an event for data below the threshold.
Can anyone tell if there is an approach to handle this?
Would it be an advantage to use the PSoC5 as a HID device instead?
By default SerialPort.ReadBufferSize is set to 4096 bytes. Slighly more info here. But you can easily change it to accomodate necessary amount of data. Then in DataReceived event handler do something like this
static void Serial_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (Serial.BytesToRead < 24000) return;
... //Recieve and process your data here
}
24000 is given here for example.

SerialPort DataReceived event called or maybe sometimes with 7 data bits [duplicate]

I am working out with serial com port.
I have insert this code in my program.
I able to send data to the devices and fail to read data from the devices.
In debug mode, i only able to get serialport.BytesToRead = 0.
May i know why this will happen??
while (serialport.BytesToRead > 0)
{
int byte_count = serialport.BytesToRead;
byte[] buffer = new byte[byte_count];
int read_count = serialport.Read(buffer, 0, byte_count);
string echo = ASCIIEncoding.ASCII.GetString(buffer, 0, read_count);
echo = System.Text.Encoding.UTF8.GetString(buffer);
Console.WriteLine(echo);
}
First use another program, like Putty or HyperTerminal to verify that the device and connection is in working order and to double-check that you are using the correct port, baudrate, parity, stopbits and databits. If you can't get anything out of the device with such a program then it won't work either using your own code.
Next focus on the handshaking. A common mistake is to leave it at none and then not turn on the DtrEnable and RtsEnable signals. A device won't send anything when it thinks that you're offline. SysInternals' PortMon utility can be handy, it shows you what's going on at the device driver level.
When to you read from the SerialPort? Are you trying to read right after you send? In that case you might try to read before there is actually anything to read from the port.
You should use the DataReceived event to read data.
Note that this event might trigger before all data is received, so you might have to retrieve the data over several calls of DataReceived until you get all the data you are supposed to.

How to open SerialPort only when data received, not all the time, in C#?

I have written the function DataReceivedHandler, and it works perfectly, but the port should be kept open to read coming data. On my project, the port should be keept available so other pages can use it if there isn't any data coming from Arduino. How can I open it only when the data received?
private static void DataReceivedHandler( object sender,SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = "";
System.Threading.Thread.Sleep(1000);
indata = sp.ReadExisting();
// Console.WriteLine("Data Received:");
if (indata == "kitchen_light_on\r\n")
f1.update_flag("kitchen_light", 1);
else
if(indata == "kitchen_light_off\r\n")
f1.update_flag("kitchen_light", 0);
}
You need one SerialPort object which stays open and is shared by all the various pages.
Note that the System.IO.Ports.SerialPort class is designed badly, and you've fallen into one of its traps. You can never compare the result of ReadExisting() to anything, because you might get part of your data now and part later. You first have to concatenate together an entire message and then you can process it. Or you might get multiple messages at once, in which case you'll need to split them apart before processing.
I fully agree with Ben. If your goal is to make sure to get the complete message and nothing dirty attached to it for your Windows program to understand what to do, I would recommend to use header and tail identifiers, something like >hereYourMessage< and/or to make your messages from the Arduino much shorter.
You can then recognize a complete message taking the characters/number or whatsoever between the >< and strip them out to pass the message to get fired.

How to Read Device Data From serial port

I have one device which sends data on COM port say on COM13. Now i want to read that data and display it in the RichTextBox or in any text control.
I have written the application with the help of IO and IO.Ports but comport.DataRecived event does not fire, even though device is sending data on that port.
I have some software on which i define the port number and it successfully display data, which insure me that data is receiving on the Port but i am unable to receive.
Is there any way i can read data?
comm.Parity = cboParity.Text;//None
comm.StopBits = cboStop.Text;//One
comm.DataBits = cboData.Text;//8
comm.BaudRate = cboBaud.Text;//9600
comm.DisplayWindow = rtbDisplay;//Null
comm.PortName = "COM13";
comm.OpenPort();
cmdOpen.Enabled = false;
cmdClose.Enabled = true;
cmdSend.Enabled = true;
public bool OpenPort()
{
if (comPort.IsOpen)
{
comPort.Close();
}
comPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
comPort.PortName = _portName;
comPort.Open();return true;
}
This normally comes from a wrong configuration of a serial port. It is not enough to simple open a serial port and waiting for some data to come in. You have also to set all the SerialPort.Properties to a correct value for your wanted connection.
Some of the common ones are BaudRate, DataBits or Parity, but to be really sure you have to set all of them. Even such things as RtsEnable or ReadTimeout.
You have to set the all, cause the configuration state will be saved from the port itself. So if one application opens such a port, makes some changes to the configuration and closes it, the next application that opens the port starts with this configuration, till it change it.
Update
Seems to be a problem i can't see from here. ;-))
The only advice i can give you is to use a Monitor tool, to better understand what your other application really does and what comes on the wire. Additionally you can set up two virtual com ports to test reading and writing on one machine (even within the same application), to have a better control about when will which data be send.
Have you read the documentation for the DataReceived event?
From MSDN:
The DataReceived event is not guaranteed to be raised for every byte received. Use the BytesToRead property to determine how much data is left to be read in the buffer.
The DataReceived event is raised on a secondary thread when data is received from the SerialPort object. Because this event is raised on a secondary thread, and not the main thread, attempting to modify some elements in the main thread, such as UI elements, could raise a threading exception. If it is necessary to modify elements in the main Form or Control, post change requests back using Invoke, which will do the work on the proper thread.
The snippet you've posted is quite rough, but I'd set the ReceivedBytesThreshold property to one. This ensures the event firing when at least one byte is present in the incoming buffer.
Cheers
Use PortMon to capture the working software, and then capture your software; then compare the traces. Pay particularly close attention to all the configuration parameters, making sure they are the same (as Oliver mentioned).

Categories