Roadmap

Jef Driesen jefdriesen at telenet.be
Wed Sep 21 12:56:32 UTC 2011


Hi,

I'm planning a major cleanup of the public api before making a first 
official release. Because some of those changes require breaking 
backwards compatibility, I'm going to take this opportunity to introduce 
many changes that have been on my todo list for a long while, but have 
been postponed forever to avoid breaking backwards compatibility as much 
as possible.

The remainder of this (long) email is an overview of the planned 
changes. There are a couple of questions as well.

1. Decide on a version scheme

The current plan is to use a typical major.minor.micro scheme. The 
infrastructure to support this scheme is already in place for a long 
time, but it's just not being used.

The main question is then how to increment these numbers? Either based 
on features or binary compatibility? I have a personal preference for 
the last method. It might also be a good idea to be able to distinguish 
between release and development versions. For example using a "-dev" 
suffix.

Worth reading: http://apr.apache.org/versioning.html

2. Separate public and private headers

All public header files are moved to the include/libdivecomputer 
subdirectory. The main benefit is that the example applications can use 
the recommended include style (e.g. #include 
<libdivecomputer/header.h>), regardless of whether they are build inside 
the build tree, or standalone. And as a bonus, it becomes very clear 
which header is considered public or private.

3. Improved error codes

The device and parser error codes will be merged to a single set. At 
the same time a few extra error codes are introduced:

* DC_STATUS_SUCCESS     /* Success */
* DC_STATUS_UNSUPPORTED /* Unsupported operation */
* DC_STATUS_INVALIDARGS /* Invalid arguments */
* DC_STATUS_NOMEMORY    /* Out of memory */
* DC_STATUS_NODEVICE    /* Device not found */
* DC_STATUS_NOACCESS    /* Access denied */
* DC_STATUS_IO          /* Input/output error */
* DC_STATUS_TIMEOUT     /* Timeout */
* DC_STATUS_PROTOCOL    /* Protocol error */
* DC_STATUS_DATAFORMAT  /* Data format error */
* DC_STATUS_CANCELLED   /* Operation cancelled */

These are roughly identical to the current error codes, with a few 
modifications. The old TYPE_MISMATCH code is changed into the more 
general INVALIDARGS. The old ERROR is changed into the new DATAFORMAT or 
INVALIDARGS, depending on the context. The NODEVICE and NOACCESS codes 
have been added to return more fine grained error information when 
opening a connection to the low-level hardware (e.g. serial/irda/usb). 
Note that these two new error codes are not intended to report the 
status of the communication with the actual dive computer!

Are there any error codes missing?

4. Namespacing the public api

All public API (functions, structs, enums, etc) should be prefixed with 
"dc_" (which is short for libdivecomputer of course) to reduce the 
chances of conflicts with other libraries.

In recent additions this prefix is already used (e.g. dc_datetime_t and 
dc_buffer_t), but in older code it needs to be added. Note that this 
will break backwards compatibility everywhere!

5. Improved naming consistency

In a few places the naming of the typedef's is inconsistent. For 
example there is a callback named device_event_callback_t and 
dive_callback_t (missing "device" in its name), an enum named 
device_type_t and device_event_t (missing "type" in its name).

I intend to introduce a more consistent naming scheme:

dc_event_type_t;      /* An enum listing all possible types. */
dc_event_progress_t;  /* A struct corresponding to one specific type. 
*/
dc_event_devinfo_t;
dc_event_clock_t;
dc_event_callback_t;  /* A callback function. */

Related to this issue is the question whether the callback function 
should return the object pointer for which it is called or not (e.g. the 
this or self pointer)? Currently the event callback has this pointer 
(because you need this pointer for the fingerprint feature), while all 
others don't. I want to make this consistent by either adding it to all 
callbacks or removing it. Technically, you can always pass the object 
pointer by means of the userdata parameter, but it can be convenient to 
have it for free (at the expense of needing an extra parameter in the 
callback function signature).

Does anyone have a particular preference regarding adding/removing this 
object pointer?

6. Cleanup the parser api

The parser api needs some major improvement.

The biggest issue here is that the parser_sample_value_t union is 
passed by value in the sample callback. This means we can't introduce 
new sample types in the future without breaking backwards compatibility 
(because extending the union may change its size). This can be avoided 
by breaking the union into individual structs and pass them by reference 
with a pointer. This is similar to the current event callback, so it 
will improve consistency too.

The downside is the application will have to cast the pointer to the 
correct data type manually. It might be possible to keep the union (but 
still passed as a pointer of course), to eliminate the need for a manual 
cast, but this might not be entirely portable. I'll need to investigate 
this further.

Another concern are the sample events. Currently we have a large list 
with all possible event types supported by the many dive computers. But 
this starts to become a big mess because the data associated with each 
type varies greatly between different dive computers, so it's nearly 
impossible to map this into a single data structure. Therefore, I 
propose the remove the event sample type, and use the vendor type for 
this purpose. Then we can just document the format and pass the complete 
data to the application.

Note that in a later stage, we can always add back the more general 
purpose events (e.g. gas switches, etc), but then with an appropriate 
data structure for each event and not the single catch-all data 
structure we have now. This will need further discussion.

7. Re-order structures to eliminate padding

A few structures have unnecessary padding bytes inserted by the 
compiler due to alignment requirements (e.g. device_clock_t). These 
useless padding bytes can easily eliminated by re-ordering the fields in 
the structure. This breaks backwards compatibility, but since some of 
the other changes will break compatibility anyway, it's a good 
opportunity to get rid of the padding too.

8. Drop deprecated functionality

There are a few functions that have a better alternative, and can be 
removed.

For example the *_set_timestamp() functions in the reefnet and uwatec 
backends can be replaced with the more general device_set_fingerprint() 
function. You can still use an integer timestamp with the correct 
serialization to the binary fingerprint.

Another candidate for removal are the *_set_maxretries() functions. I 
think it's better to just handle this completely internally. In the end, 
the backend should know best how many attempts should be made to retry a 
failed command.

The device_version() function is also obsolete. All backends that have 
a mandatory version/handshake sequence during the communication perform 
this already internally. Only when you need the data returned by these 
commands for some reason, you can call the function explicitly. But 
although this functions looks device independent, it is not because you 
need to know the buffer length in advance. And then we could equally 
well turn it into a backend specific function. In cases such as the 
sensusultra handshake, where you wouldn't be able to call the function 
at any time, there is already a backend specific function to retrieve 
the cached handshake packet. We could even go one step further and 
introduce a special vendor event to pass the raw version/handshake 
packet to the application.

Would this cause trouble for anyone?

9. Improved tools

I plan to create a new "dctool" commandline application that is more 
flexible than the current universal application. the idea is to have a 
tool supports a number of actions:

dctool [<options>] action [<args>]

Planned actions are dump, dives, parse, extract, read and write. The 
major difference with the universal application is that the new tool 
will only perform a single action, but the output can be piped to the 
next action. This will require defining a common data format to pass the 
data through the pipe.

Note that this isn't a high priority item because it doesn't have any 
impact on the public api, and hence can be completed later on.

10. Stable numbers for the backend types (and merging device and 
parser)

To maintain backwards compatibility, the existing enum values shouldn't 
change when new backends are added. To achieve this, and at the same 
time keep backends from the same manufacturer grouped together, I 
propose to introduce two numbers to identify each backend: one for the 
vendor, and one for the device itself. This is similar to the USB 
VID/PID numbers. Both the VID and PID numbers can then be encoded into a 
single 16 or 32-bit number to make up the enum value.

Additionally, I would like to merge both the device_type_t and 
parser_type_t enums into a single enum. Right now every device backend 
has a corresponding parser backend (with a few exception where a parser 
can be shared by several device backends), and there is no good reason 
to keep just a single enum. I'm still looking for a good name for the 
new enum.

11. Return dc_buffer_t pointer instead of integer

I plan to make all dc_buffer_*() functions return the dc_buffer_t 
pointer to indicate success or failure, instead of an integer. These 
functions can only fail due to out-of-memory errors, so returning NULL 
makes more sense, and additionally it allows to chain calls.

12. Units: hydrostatic vs density

A few backends (e.g reefnet, cobalt, ostc) store the depth values (d) 
as pressure values (P). This makes a lot of sense considered the fact 
that a depth sensor is actually a pressure sensor. But it also means a 
conversion is necessary, and that requires knowledge of the atmospheric 
pressure (Patm) and the water density (rho):

P = rho * g * d + Patm

or if you prefer:

d = (P - Patm) / rho * g

Since those values are not always provided by the device (atmospheric 
pressure can be measured, but water density can't and is thus typically 
a user configurable setting or simply unknown), the calibration 
constants have to be provided by the user.

Note that this conversion has no influence on the decompression 
calculations, because those are done with the pressure values. The 
conversion to depths is strictly for displaying to humans, who prefer to 
see depths :-)

The use of the atmospheric pressure is straightforward, but for the 
water density their are many possibilities (density, salinity ratio, 
etc). In the current implementation a "hydrostatic" value is used, which 
is nothing more than the multiplication of the density with the standard 
gravity (and thus is equivalent to the pressure of 1m of seawater). The 
mean reason why this was chosen is simplicity in the implementation, and 
the nice correspondence with the simplified formula used by divers in 
the field:

PRESSURE(bar) = DEPTH(m) / 10 + 1
PRESSURE(atm) = DEPTH(ft) / 33 + 1

by defining the parameters (see units.h for the constants) as:

atmospheric = BAR
hydrostatic = MSW

However I'm not convinced the use of this "hydrostatic" parameter is 
very intuitive, compared to using the more well-known density value. 
Using the density directly would basically hide the gravity constant 
from the public api. Do you have any preference towards using 
hydrostatic vs density?

Note that you can still obtain the same results as with the simplified 
formula, by defining the parameters as:

atmospheric = BAR
density     = MSW / GRAVITY ~= 1019.7 kg/m^3

The math for imperial units is similar, resulting in these parameters:

atmospheric = ATM
hydrostatic = FSW / FEET
density     = (FSW / FEET) / GRAVITY ~= 1027.2 kg/m^3

13. Documentation

I should take some time to write proper documentation (e.g. doxygen or 
something similar). But since my time is pretty limited, this has the 
lowest priority.

That's it for now. Feedback is welcome as usual.

Jef





More information about the Devel mailing list