For most I/O stream implementations the serial communication specific
functions are meaningless. Implementing them as no-ops allows the dive
computer backends the call the I/O stream functions unconditionally.
However, implementing the no-op with a dummy function returning
DC_STATUS_SUCCESS, does not only add some (small) overhead at runtime,
but also requires many such functions. This is inconvenient and the same
result can easily be obtained by using a NULL pointer instead.
The consequence is that the logic is reversed now. To obtain the
previous behaviour of returning the DC_STATUS_UNSUPPORTED error code
again, you'll need to implement a dummy function. But that's fine
because it's the less common case.
Add a function to query the underlying transport type. This allows the
dive computer backends to implement transport specific behaviour where
necessary.
For the built-in I/O implementations, the transport type is obviously
always hardcoded, but for a custom I/O implementation the application
needs to provide the correct type. Hence the transport type can't be
hardcoded in the vtable and needs to be passed as a parameter.
Wih the custom I/O implementation, an application can use its own
low-level I/O layer instead of using one of the built-in ones. The
application only needs to provide a set of callback functions, and
libdivecomputer will wrap them into a I/O stream.