Description
The problem
When writing the driver for the OWON HDS200 I encountered a problem that had no perfect solution.
Some commands, like :DMM:MEAS?
, can be sent without any rate limiting. When requesting data with SCPITransport::SendCommandQueuedWithReply()
the call will be blocked until the data is returned. It is then safe to immidiately sent another command.
Other commands, like :DMM:RANGE {V, mV}
takes a really long time. As the command is write only, there is no waiting for a reply. If a request is sent directly after, then it will either get dropped, or might possible get the wrong data. I currently block for around 800 ms to avoid this.
This problem have a few possible solutions:
-
Do all the rate limiting with usleep(). This might freeze the GUI for a couple of seconds when doing things that takes longer time.
-
Use the already built in rate limiting. Then everything will be slow. A
:DMM:MEAS?
will do something like 1.2 readings per second, instead of 15. Other things like the scope might be even worse. -
Extend the SCPITransport to have some kind of dynamic rate limiting. Something where each command could have a "settle time" that will block the next command until it is safe to run. This is the solution I propose.
How do we implement this?
API changes
All SCPITransform::Send*()
functions will have an extra argument added:
std::chrono::milliseconds settle_time = chrono::milliseconds(0)
This settle_time is optional and will default to 0 ms.
This will not need any refactoring in other classes.
Storing the required data
SCPITransport::m_txQueue
will be changed from:
std::list<std::string> m_txQueue;
to
std::pair<std::string,std::chrono::milliseconds> m_txQueue;
In this way we can store both the command and the associated "settle time".
Nothing in the scopehal-apps repo uses m_txQueue
outside of the SCPITransport
class. So this should be easy to change.
Sending data
All code that does some kind of timing in SCPITransport
should do it like this instead:
If settle_time > 0
Use settle_time
Else
Use m_rateLimitingInterval
I have not yet looked into what exact stepts that will be needed for this. It could possibly be as easy as letting RateLimitingWait()
be aware of the settle_time.
Notes
- If settle_time > 0, then this value will always be used, even if it is lower than the global rate limit.