@scottdixon would you say that extracting the C++ code generator from libuavcan into a separate, independently reusable entity, is feasible? My attempt to identify items that generated code might depend on shows that most of those come from the C++ standard library rather than the UAVCAN implementation library, meaning that, proper design provided, one can easily reuse code generated for one UAVCAN library with another UAVCAN library.
This is valuable not only from the standpoint of code reusability but also for consistent application design. For example, a node may have both CAN and serial interfaces exposed; suppose that UAVCAN is used over both of those. There is libuavcan for CAN; for serial, either an ad-hoc implementation or a separate library (if there is one) will need to be used. The transports are quite different, but the DSDL layer is identical, so it would make sense to reuse the same generated code with all involved transports.
Another practical example of code reuse between different implementations is libuavcan vs. libcanard. Having a common C++ code generator for both (regardless of the fact that libcanard is a C99 implementation) reduces the code maintenance effort considerably (applications that cannot leverage C++ will not benefit from this, obviously).
If library-independent code generation is implemented, it would automatically resolve this issue as well:
…including the following implied sub-issue, assuming that the virtualized application is implemented in C++:
A possible solution is to let the virtualized systems perform DSDL object serialization on their own, thus effectively eliminating the type information, and interact with the UAVCAN bus by cutting directly into the transport layer of the host’s stack. So that, for example, when a virtualized application needs to emit a particular transfer, it would serialize it internally and then hand over the chunk of bytes to the host accompanied by the port-ID, destination node-ID, priority, and whatever else is needed to let the transport layer dispatch the data correctly. Data reception is the reverse of that: the virtualized application instructs the host which port-ID it is interested in, and the host takes care to route all incoming transfers accordingly.
I am weakly considering right now if there is merit in having the code generator I made for PyUAVCAN transformed into a library-independent one, too.
I seem to remember @kjetilkjeka planning on implementing a similar approach for his Rust implementation (couldn’t find the discussion but it’s certainly somewhere public).
If we were to do this, it could become a slight paradigm shift, because UAVCAN libraries would be essentially just implementations of transports only rather than of the full protocol stack as they are now. Continuing this line of reason, one might see the appeal of the following proposal because it underlines the weakness of the logical coupling between DSDL and the rest of the stack: