I have cases where I need to read small bits of data from a device over a TCP socket. Right now, I have pretty much cobbled together an event driven system where I set an enumeration of the type of data I am looking to read, then I issue a write command and send the query to the device. Then in the DataAvailable event of the socket, I take action when the data comes back based on the enumeration set. This works fine when I am say first starting up and am reading all the necessary data from the device(s) initially. But it’s messy when I want to basically have a function where I query the device and get a current value.
For example, some devices have a volume setting. I want to query the current volume level. So with the event driven model, it interrupts the flow of the code. I can’t say something like:
If MyDevice.GetCurrentVolume = 6 Then
// Do Some Action
Instead I have to jump through hoops of sending the volume query command, then waiting for some property to get updated at some point in the future and reading from that property. In any case there’s a delay of some period of time between when I send the query and when I get the data back. Xojo does not handle waiting for synchronous information very well. There’s not a good way to “Delay” things in Xojo.
So I struggle with this. Do I code the method like this:
Function GetCurrentVolume as Integer
Until socket.Lookahead = The_Data_I_am_looking_for
Problem is then you can sit in that loop for a long time perhaps or it can give spinning cursors, etc.
I’m open to suggestions for how to do this. Yes, event driven is good, but when trying to do things in a sequential fashion, event driven is just a pain or perhaps I’m not looking at it correctly.
No, you’re getting it right. Async requires completely different thinking and coding.
when you request the volume from the socket, does the data come with and indication that it is volume data?
Yes, somewhat. Here’s what you get:
/usr/local/bin # volume_read.sh
Left: -24 db Right: -24 db
And maybe asynchronous here is the way to go because it literally took about 8 seconds for the script to run on the device and report back the data.
I just feel like my TCPSocket DataAvailable event is getting enormous and unwieldy. But maybe that’s just the way it has to be!
So I’ve done some more investigating and I have found that I can just send writes to my devices as fast as I can. Even in situations like above where it takes 8 seconds to respond, it’s OK. It all buffers and comes back correctly. So I’ve been trying to execute one command, wait to make sure that command gets its response back and handled before sending the next command, etc. This has made my DataAvailable event rather complex and cumbersome. Now I can just dump all my commands to the device and then in DataAvailable, I’ll probably just use a series of RegEx’s to extract the data I need. Just need to properly handle the socket’s buffer and what to do with data when it is partially read in but I think I have that figured out too.
The only problem is I can’t use a Formula to get back some of the data I want. I need to wait until it becomes available. But I guess I’ll just have to work around that as instances where I have to sequentially wait 8 seconds for a response is clearly not reasonable - particularly in a system with a lot of potential devices with each one delaying 8 seconds!
I’d like to suggest that in your DataAvailable event that you add the data to a buffer and then use a timer to call a method later (like 1ms later). That way you can be receiving more data while you are processing. Using this method can significantly increase performance.
That’s an interesting idea so if more data comes in while the timer is executing that data gets added to the buffer and could be acted upon even before the time fires the due to being triggered by receiving that additional data.
But is there a chance that the code in the timer could
be altering the buffer at the same time the DataAvaialble event is trying to alter it? Probably a very small chance but is it something to be worried about?
Unless you spin up a thread to do the processing, or use DoEvents, you should be safe. Timer.Action and TCPSocket.DataAvailable both run on the main thread and cannot overlap.