C# Serialport or USB HID connection? - c#

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.

Related

Garbage Value Reading Serial Port Data

I am working on making GUI for a Smart Water flow meter whose communication protocol is RS485,
as per instructions from Communication Manual i am sending an inquiry packet and i am receiving proper response in serial port terminal. But when i am trying to do it on my C# app.
Things are happening oppositely.
string data = "[H201815000081]";
private void button1_Click(object sender, EventArgs e)
{
serialPort1.Write(data);
incoming_data = serialPort1.ReadExisting();
text_reciever.Text = incoming_data;
}
// text_reciver is the text box of my gui where i want to display the
// values from flow meter.Data Type of incoming_data is string
Here is the code, i am sending an inquiry code to the device and in return i am getting garbage values on my text box. Some times it is stream of Question mark symbol (?), some time it shows nothing.
But when i revert myself to serial port terminal (Real Term).
It is showing proper values as mentioned in communication manual.
Please assist in this regards.
After looking around i just found the answer to my question.
The point is previously i was communicating with serial port teminal, where everything was working fine, but when it comes to interacting with peripherals one need to make sure that Serialport.DTRProperty is enabled.
When opening the serial port one must enable the DTR property by:
serialPort1.DtrEnable = true;
Otherwise the windows form will read the garbage value.
the incoming data would be serial number of device (ASCII Format) and Water flow values

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.

Creating and keeping a stream alive in 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.

C# .Net Serial DataReceived Event response too slow for high-rate data

I have set up a SerialDataReceivedEventHandler, with a forms based program in VS2008 express. My serial port is set up as follows:
115200, 8N1
Dtr and Rts enabled
ReceivedBytesThreshold = 1
I have a device I am interfacing with over a BlueTooth, USB to Serial. Hyper terminal receives the data just fine at any data rate. The data is sent regularly in 22 byte long packets. This device has an adjustable rate at which data is sent. At low data rates, 10-20Hz, the code below works great, no problems. However, when I increase the data rate past 25Hz, there starts to recieve mulitple packets on one call. What I mean by this is that there should be a event trigger for every incoming packet. With higher output rates, I have tested the buffer size (BytesToRead command) immediatly when the event is called and there are multiple packets in the buffer then. I think that the event fires slowly and by the time it reaches the code, more packes have hit the buffer. One test I do is see how many time the event is trigger per second. At 10Hz, I get 10 event triggers, awesome. At 100Hz, I get something like 40 event triggers, not good. My goal for data rate is 100HZ is acceptable, 200Hz preferred, and 300Hz optimum. This should work because even at 300Hz, that is only 52800bps, less than half of the set 115200 baud rate. Anything I am over looking?
public Form1()
{
InitializeComponent();
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
this.Invoke(new EventHandler(Display_Results));
}
private void Display_Results(object s, EventArgs e)
{
serialPort1.Read(IMU, 0, serial_Port1.BytesToRead);
}
Did you try to ajust time latency on the USB serial converter? I had the same problem with a FTDI USB to serial converter. I use an oscilloscope to see my IN and OUT data coming from the device and I could see that the computer was always slow to respond. By default, time latency on the device is set to 16 ms. I changed it to 2 ms and it makes a big difference. Go to your USB Serial Converter in the Device Manager and in the advanced settings, change Latency time to 2 ms. It should works. Try it.
Why do you Invoke() the call to DisplayResults?
This will push it to the MessageLoop, an unnecessary delay.
It would be better if DataReceived() pushed data onto a (thread-safe) queue for decoupled processing.
I also think you could run into problems with split packages.
You could try setting ReceivedBytesThreshold = 22, which will result in the event being fired when there are at least 22 bytes to read. Note that it will be at least 22. There may be more.
I don't think I would personally do this though, because what happens if your packet size changes in the future, for example to 12 bytes? You would end up with 12 bytes in the buffer but not firing the event at all.
Far better to leave it set to 1, which will fire the event when at least 1 byte is available. Then push all received bytes into a list or a queue as Henk has already posted.
Note that the DataReceivedEvent has no knowledge of what you consider a packet of data to be of course. It just fires when there are bytes available. It is up to the developer to assemble these bytes into a meaningful message or packet.
The problem lies in the received data handler.
I ran a separate thread with a while(true) loop and serial.ReadLine(), all works perfectly.
using System.Threading;
Thread readThread = new Thread(Read);
readThread.Start();
Hope someone else doesn't need to spend 3 hours fixing this.

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