I'm trying to diagnose why some USB serial port adapters do not work well with .NET. The behavior of the affected adapters is after SerialPort.Write(). Calling any of
the SerialPort.Readxxx() methods causes the method to block until about ReadTimout.
The workaround that I have discovered is to use a loop to block while BytesToRead is
<= 0, and then everything works as expected. Why?
I have collected some debug logs using Sysinternals' Portmon. Why is this happening?
without.log = bad behavior/bad USB adapter
with.log = with the while loop/bad USB adapter
ftdi.log = good behavior/good USB adapter
I wrote two native implementations of ReadByte() and can now better characterize the issue.
With ReadIntervalTimeout and ReadTotalTimeoutMultiplier set to MAXDWORD ReadFile(), it is
supposed to wait until a byte is in the receive buffer and return as described on MSDN's
COMMTIMEOUTS structure page.
The Portmon logs show that this is how ReadByte() is setting up the serial port. But if
the receive buffer is empty when ReadFile() is called ReadFile() it waits until ReadTotalTimeoutConstant and then returns.
Microsoft's ReadByte() also sets up a Comm event; the Portmon logs clearly shows the event is firing, but ReadByte() never reads the receive buffer. I implemented this in my native version of ReadByte() and it works perfectly with the affected USB-to-serial adapter.
Native ReadByte()
The best idea to read SerialPort is using async-ous method:
_port = new SerialPort();
_port.DataReceived += new SerialDataReceivedEventHandler(OnComPortDataReceived);
void OnComPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] ba = new byte[_port.BytesToRead];
total = _port.Read(ba, 0, _port.BytesToRead);
}
Related
I am trying to read data from a device connected via USB.
For creating the trigger the code looks like:
private SerialPort realTimePort;
realTimePort = new SerialPort();
realTimePort.BaudRate = 9600;
realTimePort.PortName = "COM4";
realTimePort.ReadTimeout = 5000;
realTimePort.ReadBufferSize = 32768;
realTimePort.ReceivedBytesThreshold = 1;
realTimePort.BaudRate = 9600;
realTimePort.ReadBufferSize = 4096;
realTimePort.ParityReplace = 63;
realTimePort.Parity = Parity.None;
realTimePort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(realTimePort_DataReceived);
realTimePort.Open();
To read the data, which was sent, the code looks like:
public void realTimePort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// Do something with the data
}
With one version of the device everything works fine and the trigger starts, when data was sent, but with a newer software-version of the device realTimePort_DataReceived is never triggered.
At first i thought, that the problem might be, that the device never sends data, but then i tried to read the data with "Tera Term" and there i can see exactly, what i am expecting. I also compared the data with "Tera Term", which was sent of the devices with the different software-versions, but it is exactly the same string.
Do you have any ideas, why the event is triggered with the older software-version and not with the newer one?
An employee of the manufacturer of the device already gave me the specification of the SerialPort, because i had this problem, but it didn't help me.
It is hard to reproduce the issue as i am not aware what type of device you are using and what type of data is sends here are some tips you can evaluate a quick check list to ensure the correct data receiving.
1. Play with RTS or DTR port flags for new version device
Basically some new versions of hardware uses flags of SerialPort e.g. DTR (Data Terminal Ready) indicates that your code is ready to receive, and RTS (Request to Send) a request to device to actually send data. for older hardware types it was not mandatory to use these flags although in modern devices its still not but just a standard practice so you should experiment & try enabling these by your code e.g.
realTimePort.RtsEnable = true; //enable this mode
realTimePort.DtrEnable = true; //and also this one
2. Try to read device error stream
It is possible that your new version hardware is sendind data over error stream, the tool you was using utilizes both streams for data read so you can subscrive to error event like.
realTimePort.ErrorReceived += new SerialErrorReceivedEventHandler(sPort_ErrorReceived);
private static void sPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
{
//process your error, it will give you further hint about why part of your question.
}
Morning all,
I'm developing a C# WPF application which continuously reads barcodes (about one every minute) from a DATALOGIC scanner (DS4800-1000) and send them to a server which replies with details about that specific barcode. This scanner is connected to a tablet running Windows 8.1 (non RT) through a USB-to-serial converter from MOXA (model UPort 1100).
Whenever a new barcode is read, the DataReceived event is fired and handled with the following method:
private void port1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Log.log(Log.LogLevel.Info, "MainScreen.port1_DataReceived");
Thread.Sleep(100);
String data = "";
// If the com port has been closed, do nothing
if (!comport1.IsOpen)
{
Log.log(Log.LogLevel.Info, "MainScreen.port1_DataReceived - COM CLOSED");
data = "COM CLOSED"; // Must be < 16 chars
}
else
{
// Obtain the number of bytes waiting in the port's buffer
int bytes = comport1.BytesToRead;
// Create a byte array buffer to hold the incoming data
byte[] buffer = new byte[bytes];
// Read the data from the port and store it in our buffer
comport1.Read(buffer, 0, bytes);
data = Encoding.Default.GetString(buffer);
Log.log(Log.LogLevel.Info, "Data received from barcode scanner number 1: " + data);
}
// COM port is handled by a different thread; this.Dispatcher calls the original thread
this.Dispatcher.Invoke((Action)(() =>
{
ExtractBarcodeData(data);
} ));
}
I'm observing a strange behavior: at random times, I see no reaction at all on the application, although the scanner actually reads a new barcode, while I would expect a new DataReceived event as the previous barcodes. Logs say me that the port is actually open and I can also close it using a specific button which closes and reopen it. Here comes the exception (on the Open() call): A device attached to the system is not functioning.
I can not reproduce this error in no way, it's totally unpredictable and random! Anyone has got any idea why the DataReceived event is not triggering?
Thanks,
FZ
Most USB-to-serial converters have this problem. They may disappear from the system and appear again. All opened handles at this situation become invalid.
Please, open the Device Manager and verify the power management tab for each USB hubs there. The system should not power off the hub.
i'm having a problem with virtual serial ports in C#: when i call the Write function, it automatically throws a TimeOutException, but the client receives the data.
It only happens with virtual ports (i'm using Free Virtual Serial Ports from HDDSoftware, with a bridge COM12<->COM13). I open COM12 with the Visual Studio and the COM13 with Hercules. The application throws the timeout exception but Hercules receives the message.
It doesn't matter if i set 1000ms or 1000000ms of Read/Write port timeout.
Thanks!!
using (SerialPort port = new SerialPort("COM13"))
{
// configure serial port
port.BaudRate = 9600;
port.DataBits = 8;
port.Parity = Parity.None;
port.StopBits = StopBits.One;
port.Open();
port.ReadTimeout = 10000;
byte[] buffer = Encoding.ASCII.GetBytes("HELLO WORLD");
try
{
port.Write(buffer, 0, buffer.Length);
}
catch(TimeoutException)
{
Console.WriteLine("Write timeout");
}
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss"));
try
{
byte[] buf = new byte[100];
port.Read(buf, 0, 1);
}
catch(IOException)
{
Console.WriteLine("Read timeout");
}
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss"));
}
After a few tests (putting the Write into a try-catch), the Read operation also throws a TimeOutException instantly.
This is what i get when run the test. It is supposed to be:
12:16:06
(Read timeout)
12:16:16
port.Write(buffer, offset, count);
It is up to the device driver to decide how to implement this. But all the ones I know follow the rule that the underlying WriteFile() call is allowed to return *lpNumberOfBytesWritten < nNumberOfBytesToWrite. Or to put it another way, the write is not "transactional".
A decent mental model is that Write() writes one byte from the buffer at a time, count times. At some point, entirely unpredictable when, writing one more byte will stall when the driver's transmit buffer fills up to capacity and cannot store another byte. Eventually triggering the exception.
So part of the buffer will still make it to the other end. You cannot tell what part from the SerialPort class. A time-out is a gross communication failure that's pretty hard to recover from. If that's a show-stopper then you need to consider writing one byte at a time (fine, serial ports are slow) or pay attention to WriteBufferSize - BytesToWrite to check if the buffer fits and implement your own timeout.
As Hans Passant said, it was a problem with the Virtual COM software. I tried with Virtual Serial Port from Eltima Software and worked fine!
My C# desktop class library communicates with COM serial port.
The com is not real com, it is a USB to COM cable connected to USB to COM on another computer, the other computer uses a simulator to send data.
This solution works fine and then port opens successfully:
serialPort.Open();
if (serialPort.IsOpen)
{
serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
}
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
var length = serialPort.BytesToRead;
byte[] buffer = new byte[length];
serialPort.Read(buffer, 0, length);
for (int i = 0; i < buffer.Length; i++)
{
System.IO.File.AppendAllText(#"c:\TestLogging.txt", string.Format("[Time = {0}] Data was received from serial port !", DateTime.Now)); }
}
The simulator send data all the time, and I receive the data in my class, BUT i dont receive it all the time, i see printing of 1 line every 30 seconds - although it suppose to print all the time!
What is weird - If i place break point in the line var length = .. then i see a the prints for the time i was halting on the break.. the data transferred seems to be "cached" and when i hit "Play" I receive the data but only for the time i was pausing the process.
I think you're too late registering the DataReceived eventhandler there. You should register to it before you open the port:
serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
serialPort.Open();
if (serialPort.IsOpen)
{
}
Try connecting your machines using HyperTerminal and check if the communication works. If it does, then it's your application's fault (double-check serialport settings). Otherwise it's probably the cable or the port itself.
Are you sure you're not getting any faulty data? Have you subscribed to SerialPort.ErrorReceived event handler? If you catch some SerialError.Frame errors there, then you probably have a faulty cable or the port is broken, or there are some conditions that are jamming the comunication (not vary likely but it can happen, for example if there is some strong source of power near by, for example an inverter).
OK, what is the problem ?
I am using USB to COM cable, and not true COM port.
The behavior of data receiving event from SerialPort is different.
I listen and catch the data event, but instead of getting array of bytes (as in real COM) - I receive every time a single byte (array in size of 1)..
Meaning: On DataReceived event when working with USB to COM port: i get this: 1-1-1-1-1-1 each DataReceived event give me 1 byte.
Real physical COM .DataReceived event give me: 5-30-42 etc.. Array of bytes
So my solution when working on USB to COM ports (some might call it "virtual COM port") I need to check if serialPort.BytesToRead is bigger then X, then i actually do
if (serialPort.BytesToRead > 2) //I dont want to get it 1-1-1.. want to get it atleast 2-2-2-2
serialPort.Read(buffer, 0, length);
Since serialPort.BytesToRead will tell me how many bytes are in current chunk, and Read. in my terms will get the buffer and clean it.
I need to write a program, that will listen to communication in ModBus network through RS485.
I am connected to the network with RS485 <> USB dongle.
I can read some data using SerialPort.DataReceived event, but it gives strange results.
Data is often split, when it should come in one piece. (Modbus Master transmits every 100ms).
class Serial
{
private SerialPort port;
Queue<byte[]> buffer;
public Serial()
{
buffer = new Queue<byte[]>();
port = new SerialPort("COM3", 19200, Parity.Even, 8, StopBits.One);
port.DataReceived += port_DataReceived;
}
public void Open()
{
if (port.IsOpen)
{
port.Close();
}
port.Open();
}
void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] buff = new byte[port.BytesToRead];
port.Read(buff, 0, port.BytesToRead);
buffer.Enqueue(buff);
}
}
I don't have any start sign in transmission.
Delay between frames is min. 3.5 chars, and max delay between chars is 1.5 chars.
This is entirely normal, serial ports are very slow devices. The DataReceived event is fired as soon as one byte was received. You'll need to call Read() and pay attention to the value it returns, the number of bytes it was able to retrieve from the input buffer. Which might be more than one but is only very rarely equal to the number of bytes in a "packet", that could only happen if the machine got very slow for some reason.
Beware that the debugger is one way to make it that slow, a breakpoint or single-stepping the event handler code gives the driver enough time to receive all the bytes in a packet. So that the Read() call returns them all. But that stops working as soon as you stop debugging that code.
You could use the ReceivedBytesThreshold property to delay the event but that can only work when a packet has a fixed size. Simply append the bytes you get into byte[], using the 2nd argument of the Read() call. And don't process the packet until you have them all.