libcyphal
                                
                                
                                
                                    libcyphal copied to clipboard
                            
                            
                            
                        Asynchronous Service Server
The current Service Server ( https://github.com/UAVCAN/libuavcan/blob/legacy-v0.5/libuavcan/include/uavcan/node/service_server.hpp ) requires applications to immediately (or synchronously) reply to service request inside their callback. Their is no mechanism to respond to request after some amount of work has been done externally (asynchronously) from the callback.
For example, say you had a service call that erased a large configuration. This erase process takes significant time and the application doesn't want to block in the service callback while the erase occurs. An asynchronous service server (insert better name here) would allow the callback to initiate the erase, and then later report the result of the operation as the service response to the client.
Indeed, there is some value in this. But please note that processing a service request normally should not involve time-consuming operations because that may cause the client to time-out. In your configuration erase example you may want to express the asynchronous nature of the operation in the service definition itself. For example, you could define the protocol such that the server responds immediately upon commencement of the erase operation instead of blocking until it's completed.
@thirtytwobits do you think this is in the scope of Libuavcan v1?
I was able to implement this using a ServiceServer<ServiceType, CallbackType> and a GenericPublisher<ServiceType, ServiceType::Response>. The callback for the service server used the full data structure types, using them to capture transfer data and suppress the automatic response.
serviceCallback(const uavcan::ReceivedDataStructure<Request>& request, uavcan::ServiceResponseDataStructure<Response>& response) {
    // Don't respond, we'll do it later
    response.setResponseEnabled(false);
    // Save the info required to respond correctly
    m_last_client_node_id = request.getSrcNodeID();
    m_last_tid = request.getTransferID();
    m_last_priority = request.getPriority();
}
I later used the genericPublisher to publish the response.
m_pub.publish(response, uavcan::TransferTypeServiceResponse, m_last_client_node_id, m_last_tid);
I still think adding this feature to libuavcan is valuable, but I'm happy that applications can currently do it in a sane manner.
This is designed-in for v1, see #333