Serial Data - Data Delays - How to Cure?

Greetings - I have a small RF Power Meter (called a W1) that can have commands sent to it via serial/USB. The commands tell it to do various things such as return data for forward power, reflected power, standing wave ratio, etc. I then use that data to populate fields in the user window. The radio sending the RF power does so for various periods of time and as such, I need to continuously monitor those data points. I had planned on sending the three main commands of “F”, “R”, and “S” repeatedly, every second or so, using a timer.

In my testing I’ve found that there is some delay in getting the data into the “DataReceived” handler of SerialConnection1, OR into my variable. I set up my variable (as a Global) with an initial value of “zzz”. If my code sends commands as below, I get “zzz” into my TextArea1 box three times. Un-commenting the MessageBox commands results in the correct responses being displayed. So, clearly there is an issue with that data getting put into the serial buffer or my variable fast enough. I am on a Mac, so I ran the “screen” terminal application and connected to my device. Giving it those commands by hand as fast as I could resulted in the device responding instantly, so it appears there is no problem with the device itself or its ability to send replies quickly.

I read a rather longish thread in the forum regarding “pausing” a program, and I do understand that under normal circumstances, it’s not a great thing to do. However, in my case I simply cannot proceed with subsequent command sending until the received data is actually available to my code.

Any ideas on how to get around this annoying problem?

Regards, Jim

Here is my simple code to fire off three commands:

TextArea1.Value = "Data returned = "

W1command = “F”
SerialConnection1.XmitWait
SerialConnection1.write(W1command)
//MessageBox(“Uno”)
TextArea1.Value= TextArea1.Value + " " + W1data

W1command = “R”
SerialConnection1.XmitWait
SerialConnection1.write(W1command)
//MessageBox(“Dos”)
TextArea1.Value= TextArea1.Value + " " + W1data

W1command = “S”
SerialConnection1.XmitWait
SerialConnection1.write(W1command)
//MessageBox(“Tres”)
TextArea1.Value= TextArea1.Value + " " + W1data

You’re not allowing any time for the device to respond. In the terminal, your response time is measured in milliseconds (probably 10ths or 100ths of seconds). In code, time is measured in microseconds or less. You simply have to provide enough time for the device to respond before you read the value.

The best solution would be to restructure your code to be asynchronous and read the value in the DataReceived event. Then send the next appropriate command. You’ll be creating a State Machine to do so. Alternately, you could just throw in a sleep command after each Write, but that seems clunky and runs the risk of potentially missing responses if the sleep is too short.

I would be polling the Serial controller to “force” your response (Serial.Poll). I would do that in a timer, and yes you can then look into the DataAvailable event if you want (but for Serial stuff with HW I’ve always relied on timers - call me old school).

I would set a flag indicating whether your previous response has been received and then wait (while loop) before proceeding with next command. But that is just me.

Hey Jim,

As a fellow RF guy - nice to see you doing some work in this area. Sounds like a cool application. It almost sounds like a ham radio app - I’m also a ham.

Anyhow, as others have pointed out you need to let there be time for the data to arrive at the device. @Tim_Hare is correct when he says to just let the data come in asynchronously. It’s a bit harder to get your head around asynchronous and event driven communications, but believe me - once you do, things work a lot better.

So send your command to your device to get the data. The device will respond. Then in the data available event process the incoming data and send it to your textfields, ,etc.

The other problem with forcing the system to wait is that sometimes that can actually slow down the background operations of the serial or telnet connections. In some platforms like iOS it seems to completely stop it!

I’ve had some situations where I need things to happen serially so I need to wait. I admit that Xojo does not have a good mechanism for this. The challenge is to design around that. I have an app where I need to read a bunch of different configuration data from multiple devices connected on the network when the app first starts up. I used to try to read this synchronously and I got it working but I ended up going the async route. It’s more complicated but much faster in the end. I send all my commands at once. Then in the Data Available event, I literally store the data to a property as it comes in. Then I fire a timer, to process the data. I have different steps set up for this and start with the first step. One I get that data, I then move to the next step, etc. This can all be done while data is coming into the socket and being appended to the property that stores it. It’s a bit more abstract in thinking as you are kinda doing things in parallel but you’ll be much happier in the end.

73 de NA9D

I have to address different devices regularly in my main project – some serial, some Bluetooth, some API-driven. It took me a long time to figure out, but the best way of handling such data I found was to develop console helper applications that do the device communication. You don’t have pull their ports; that’s all done in their main loop’s doevents. In fact I am slowing them down on macOS with MBS methods because they had been simply too fast, using too much CPU idling (and thus polling their ports).

I don’t have to use timers in the main Desktop app. The IPCSocket (MBS on Windows) is really fast, and the main app basically idles around until a helper socket fires.
But I have to admit that’s currently a tedious path. Hopefully the announced Worker class will make things easier.

Hi Jon,

Yep, I’m W6JHB and am working on a Mac program to display pertinent data from the Elecraft W1 Power Meter. Still not having a lot of success, even with the fine suggestions I’ve gotten here. One thing that has me perplexed is that some of the documentation and even your comments say to use the “DataAvailable” event. I find no such event in the SerialConnection - what I get to use is “DataReceived”. I’m using Xojo 2020R1. Was something changed recently? I’m sure getting some funky results - partial data, short some characters, etc.

Aha. Yes DataReceived is an API2.0 event while those of us who have been around a while still refer to DataAvailable.

I’ll send you a private message with me email address. More than happy to help a fellow ham.

So Jim what is happening here is that your OS has not returned the full contents of the serial port. Understand that things come in chunks depending on when in the clock cycle the data is received. RS-232 connections are vastly slower than the bus speed inside your Mac. So in terms of clocks cycles, your machine will spend a lot of time waiting. When data does arrive, it is sent to the DataReceived event. So if you have a device that sends:

“The Quick Brown Fox Jumped Over the Lazy Sleeping Dog.”

Your RS-232 port might receive the data like:

The Q
uick
Brown Fox J
um
ped o
ver th
e laz
y
sl
eeping
dog.

It’s up to you to assemble that data into the structure you want. The way I do it, is I know that my incoming data is generally in a certain format. If it’s simple enough, I can use something like InStr (or now IndexOf in API2) to look for the data. If it’s more complex, I use a RegEx expression.

Now I am not sure in API2 what the correct command is but traditionally to access the data in the receive buffer w/o pulling it out and emptying it, you use the command LookAhead. And yes it is still LookAhead. I then examine the buffer to see if it has the data I want. If not, I leave it along and wait for the next event when the next chunk of data comes in. Once I have the data I want, I then empty the entire buffer and go from there.

But if you are trying to let the event fire and then expect that all your data will be there the first time, you will be disappointed.

Jim, If you’ve ever talked to anyone on a digital mode like Amtor, you know exactly what I mean by data coming in chunks. :slight_smile:

Folks,

Thanks for the great information in your replies. Working with Jon Ogden, the process has been fixed. Turns out that my serial data came in far, far slower than the computer’s code was running and everything got tangled up. Waiting for the end of data byte in the DataReceived routine before sending the subsequent command(s) resolved things.

Regards, Jim / W6JHB

Glad you got it working. Sounds awfully close to what was suggested here near the beginning of the thread.