2

I've been working on a program that communicates on SerialPort and having problem with it. It's communication is below 50% or less. If not, it times out most of the time.

From my research into this issue, I found out that global or system timer resolution by default is minimum 10ms or greater.

Serial Communication (RTS) and Windows 7

So, if you are using Thread.Sleep in your communication to pause for X number of milliseconds, the best it can do is 10ms or greater for a no-op or pause.

In my case, that is too long for my program to communicate with an external device. The device replies back within 10ms as soon as it gets a request from my program. If my program is not ready to receive the answer back, then my program will time out.

The only way to solve this issue is to adjust or alter the system timer resolution. To do that I was told to use Windows methods timeBeginPeriod and timeEndPeriod from winmm.dll. Although I am able to import these methods for my Windows .NET version of my program, I would like to know if there is any replacement for these methods in .NET frameworks.

Community
  • 1
  • 1
ThN
  • 3,235
  • 3
  • 57
  • 115
  • The responsiveness of SerialPort's DataReceived event has nothing to do with the timer resolution. It uses a waitable event that causes a thread context switch when the "data received" event is signaled by the driver. Expecting guaranteed 10 msec responses are a lost cause on Windows, it is not a real-time operating system. A driver is required. – Hans Passant Nov 05 '12 at 16:15
  • @HansPassant, Nope. This isn't about DataReceived. I've also tried it and it in itself gave me more grief than solve my issue. so, I created a single thread for writing and reading through serialport. Knowing exactly how long it takes for the device to reply, I momentarily pause for my software to switch the LINE (RTS) for read. Once read it switches the line (rts) for write. It only takes 2 or 3 milliseconds. So, I use thread.sleep. As described above, thread.sleep(1) will wait for 10ms or more. Hans it may be lost cause, but my communication has been solid 100% so far after 3 weeks headache – ThN Nov 05 '12 at 16:44
  • This makes little sense. Why sleep at all? Just call Read() directly without *any* sleep, it only returns when something was received. – Hans Passant Nov 05 '12 at 16:48
  • @HansPassant, Driver is required??? What comes with Visual Studio 2010 is not enough? I didn't install anything special. I am using a framework tool, SerialPort, that came with Visual Studio 2010. After few settings, I am able to communicate. It is probably using generic driver. – ThN Nov 05 '12 at 16:48
  • It sounds to me that you are making a pretty classic mistake when reading data from the serial port. You are ignoring the return value of the SerialPort.Read() call. It will **not** be the number of bytes you ask for. Yes, calling Sleep() is a band-aid for that, it delays your program long enough to allow the driver to receive enough bytes. It is however not the correct workaround, you should instead keep calling Read() until you got the entire device response. – Hans Passant Nov 05 '12 at 16:54
  • DataReceived is not reliable from what I have experienced. It doesn't capture everything all at once. In fact, mostly what you get is bits and pieces of bytes or data, which you have to queue into a buffer for you to process. It created more problems than solve any for me. It doesn't wait for all the bytes to arrive in its input buffer even though you set the ReceivedBytesThreshold to a desired value. – ThN Nov 05 '12 at 16:58
  • "Capture all at once" is your mistake. As I explained, sleeping is not the solution for that, **especially** not in a time-sensitive protocol. Just keep calling Read() in a loop. Whether in a DataReceived event handler or directly after turning on RTS. – Hans Passant Nov 05 '12 at 17:15
  • @HansPassant, I don't think DataReceived event has a problem "capturing data all at once." Right now, I am reading all the data at once straight from serialport input buffer without any problem, but because it fires way too soon before all the data sent from a device is received it becomes random. That is a big problem for me. I can make my program wait for little over 8 miliseconds for all the data to arrive and it shouldn't take too long. Out of 500,000 good packets my program hits about 56 timeouts randomly. Now that is way better than 80% timeouts and 20% good packets. Tested it all day :) – ThN Nov 06 '12 at 13:55

1 Answers1

2

If your goal is to avoid invoking platform specific DLL functions and just using the .Net framework then for short timeouts a loop with the System.Diagnostics.Stopwatch might be your best bet.

The Stopwatch will automatically use the high resolution timer when present.

public static void Pause(long ms) 
{
    Stopwatch t = new Stopwatch();
    t.Start();
    while(t.ElapsedMilliseconds < ms) { }
    t.Stop();
}

This will block your calling thread and hog the CPU while in the pause loop, to mitigate some of this (if you are using a multi-core system you can set your process's or thread's affinity to another core. How Can I Set Processor Affinity in .NET?

Community
  • 1
  • 1
Louis Ricci
  • 20,804
  • 5
  • 48
  • 62