Asynchronous Operations in ASCOM
As of this release of the ASCOM Interfaces (both COM and Alpaca), asynchronous methods are provided for all operations. Some older methods are not asynchronous, and they are now deprecated. For details on how the transition to “all asynchronous” was accomplished, and the changes that made this possible see Release Notes for Interfaces as of ASCOM Platform 7.
Background for Developers
An asynchronous operation uses two interface members: an initiator method to start the operation and a completion property that can be polled to monitor the operation’s progress.
Fundamentally, an asynchronous method initiates an operation and returns immediately, enabling the caller (an app) to read propereties, including the completion property, and possibly initiate other operations in parallel. If, during initiation, the device knows that it cannot successfully complete the requested operation, it must raise an exception instead of returning from the method call.
There are subtlties and consequences to ths mode of operation. To help developers, we have provided developer information on the details of asynchronous operations in ASCOM on our main website in the document Asynchronous Programming and Exceptions (external). Please consider looking at this.
How can I tell if my asynchronous request fails?
This section is written from an app developer’s point of view.
All asynchronous (non-blocking) methods in ASCOM are paired with corresponding completion properties that allow you to determine if the operation (running in the background) has finished. There are two places where a requested async operation can fail:
When you call the method that starts the operation, for example
Move(). If you get an exception here, it means the device couldn’t start the operation, for whatever reason. Common reasons include an out-of-range request or an unconnected device.Later you read the completion property that tells you whether the async operation has finished, for example
IsMoving. If you see the value change to indicate that the operation has finished, you can be 100% certain that it completed successfully. On the other hand, if you get an exception here (often aDriverException), it means the device failed to finish the operation successfully. In this case, the device is compromised and requires special attention.
What do I do if something goes wrong?
This section is written from an device / driver developer’s point of view.
If you determine that the operation cannot be started when the initiator method is called, e.g. a supplied parameter is incorrect or the device is not connected, the method must raise an exception rather then returning to the caller.
If something goes wrong after the operation has been initiated, report this to the client by raising an exception when the client tries to read the completion property. The exception should continue to be raised on each attempt to read the completion property until it is reset at the start of the next operation that uses that completion property.
Tip
Have a look at this article
Why exceptions in async methods are "dangerous" in C# (external). While the article uses the C#
language and async/await to illustrate the so-called “dangers” (failing
to await), the exact same principles apply here. For example you really
must use Focuser.IsMoving to determine completion of a
Focuser.Move(). Focuser.IsMoving is the ‘await’ in this
cross-language/cross-platform environment. If you ignore
Focuser.IsMoving and instead “double-check” the results by
comparing your request with the results, you run several risks,
including
A lost exception (an integrity bust),
A false completion indication if the device passes through the requested position on its way to settling to its final place, and
needing to decide what “close enough” means.
Plus it needlessly complicates your code. We have to design for, and require, trustworthy devices/drivers.