Next round of api improvements.
Jef Driesen
jefdriesen at telenet.be
Wed Dec 5 16:00:15 UTC 2012
Hi,
There have been some interesting discussions since I posted my original
email. Some of those discussions happened off list (mainly because they
were already ongoing before I send out my email), so I think it's a good
idea to summarize what has been discussed so far, the decisions that
have been made already (or not), new issues that popped up etc.
BTW, there will be a slight change of plans regarding the next v0.3
release. The changes that are being discussed in this thread, will be
postponed until after the v0.3 release. The v0.3 release will be an
intermediate release, with some smaller api cleanups (which should not
affect most apps), some new features and bugfixes. This will also give
us some more time to work out the new api design.
> 1. Object ownership, lifetime and memory management.
> =====================================================
The application will own all objects. Simplicity and consistency is
considered more important than efficiency.
> 2. Querying available sample values?
> =====================================
The current proposal is that each sample will provide a bitmap with the
available values. We introduce some new function to retrieve the bitmap
(tentative name, suggestions are welcome):
dc_sample_get_available (sample, &bitmap);
and then applications can test the returned bitmap for the individual
types, and if present, call the corresponding getter function:
if (bitmap & DC_SAMPLE_FOO) {
dc_sample_get_foo (sample, &foo)
}
> 3. Supported dive and sample data
> ==================================
3a. Dive data
==============
The original list hasn't changed much:
* date/time
* divetime
* maxdepth
* gasmixes
* tank pressures (begin/end)
* temperature
For multivalued fields, like the gas mixes and tank pressure, the
current proposal is to use a struct with a count and a pointer to the
actual data array:
struct {
unsigned int count;
foo_t *foo;
};
Note that such a struct would behave a bit different from the others.
Normally the caller passes a pointer to a struct (or plain C datatype)
to the getter function, so the storage is provided by the caller and the
getter function just fills in the value(s). But in this case we return a
pointer to a foo_t struct that is not owned by the sample object. This
may not be such a big deal considering the app will own the sample
object, but I wanted to make sure this doesn't go unnoticed :-)
Support for salinity and atmospheric pressure has already been
requested. The primary use-case is probably for doing decompression
calculations. This has already been implemented in the master branch
using a structure like this:
struct dc_salinity_t {
enum {DC_WATER_FRESH, DC_WATER_SALT} type;
density; /* Optional, zero if unavailable. */
};
For devices which don't support atmospheric pressure directly, and
provide an altitude ranges instead (e.g. "0-300m" "300-1000m"
"1000m-1500m), an estimation for the atmospheric pressure can be
calculated with the barometric formula [1]. For ranges, the upper value
of the range is probably the best choice, because it yields the lowest
pressure. However, because diving at sealevel is probably the most
common case, an exception could be made to consider the first range
always at sealevel (e.g 1013.25 mbar).
There has been some discussion regarding the exact semantics of the
temperature field. On one hand it's important to clearly define the
exact semantics, but on the other hand the device may provide one or
more temperature temperature values with some different semantics. For
example we can define the temperature field to be the minimum
temperature, but the device can provide the minimum, maximum or average
value, or the temperature before and after the dive, or the temperature
at maximum depth, or one or more of the above. How do we support this?
One option is to keep the exact semantics vague, and just supply
whatever temperature value the device supplies. This is not ideal,
because it leaves applications that care about the exact interpretation
in the cold, and it also doesn't work well in case the device provides
more than one value.
An alternative option is to move the temperature data into the samples.
All the values mentioned above can easily be attached to the correct
sample. You still won't get a full temperature profile (only a few data
points), but at least their is no confusion about the semantics. For
example a temperature value attached to sample at maximum depth, is
clearly the temperature at max depth, and so on.
Another suggestion was to use flags to make the exact semantics clear.
For example if the default semantics is the minimum temperature, provide
a flag to overrule this interpretation with another one (e.g at max
depth, etc).
struct temperature {
flags;
value;
... /* Maybe multiple values here? */
};
And last but not least we can provide a struct with all possible
values:
struct temperature {
minimum;
maximum;
average;
...
};
and then provide some means to let the application know which values
are available (using a bitmap again, or some magic values to indicate
"not present").
No decision for the temperature issue has been made yet.
3b. Sample data
================
The basic list doesn't need much discussion:
* time
* depth
* temperature
* tank pressure
There are also a couple less important ones, but as long as they are
reasonable device independent, I see no reason not to support them too:
* heartrate
* airtime
* CNS/OTU
* ...
Note that this is definitely not a complete list. We'll probably need a
few extra types for tec divers (setpoints), and there may be others that
I forgot.
There has been some discussion regarding the CNS values (but the
underlying discussion applies to any other type too). The natural unit
for the CNS values is obviously a percentage. But there are devices that
don't supply a percentage. For example the Suunto has OLF (Oxygen Limit
Fraction), which is hybrid between CNS and OTU (e.g. whichever is
highest), and Oceanic has their 02 bar graphs. Although both give some
indication of the CNS loading, they are not easily translated to a
percentage.
What to do in this case? Just not support it, or again provide some
flag with the exact interpretation?
3c. Events
===========
The current proposal is to reserve the events exclusively for things
that have no duration (and thus no need for the begin/end flags) and
don't need to carry any data values. In that case, we can use a simple
bitfield to get all the events for the sample at once.
dc_sample_get_available (sample, &bitmap);
if (bitmap & DC_SAMPLE_EVENTS) {
dc_sample_get_events (sample, &events);
if (events & DC_SAMPLE_EVENT_BOOKMARK) {
/* Bookmark event. */
}
if (events & DC_SAMPLE_EVENT_VIOLATION) {
/* Decostop violation event. */
}
}
While this should work well for true events like the decostop
violations, bookmarks, etc we'll need another solution for things like
gas changes, decompression info, etc. The idea is deliver this info as
sample values, rather than events.
For example the gasswitch event would be changed into an "active
gasmix" sample value. The main difference is that you will now get the
current gasmix on every sample, and not just the gaschange. For the
gasmix sample value, the corresponding data type would be the index of
the gasmix in the header (see above).
Decompression data can be supported in a similar way. For each sample
you can get the deco status, with a data structure like this:
dc_deco_t {
enum {NDL, DECOSTOP} type;
time; /* Optional */
depth; /* Optional */
};
If you're not in deco, the type will be set to NDL, and the time
contains the remaining no decompression limit (if available). If you're
in deco, the type will be set to DECOSTOP, and the time and depth
contain the time and depth of the next decompression stop (if
available). With such a structure we can support both devices that
provide just a simple ndl/deco flag, or a some more detailed info.
We already committed some changes to the master branch to move into
that direction. The DC_EVENT_DECOSTOP now contains the depth (in meters)
and time (in seconds) as two packed 16bit values, and a new DC_EVENT_NDL
was introduced. It's not perfect yet, because for the current api we
were limited to the existing data structures (hence the packing), but
it's a step in the direction of the model explained here.
Of course we can consider to extend the type with deepstops and safety
stops, or add an extra field for TTS (Time To Surface), and things like
that. But the main point is that we move away from the event model as
much as possible.
3d. Units
==========
The two choices are SI (second, meter, Kelvin, Pascal) or metric
(second, meter, Celsius, bar). The only difference between the pressure
units "Pascal" and "bar" is a scaling factor, so then it comes down to
Kelvin or Celsius for the temperatures.
I'm also seriously considering to adopt the subsurface style unit
system, where the units are carefully chosen to make them fit into an
integer: second, millimeter, milli Kelvin and millibar. This should
provide plenty of precision for our purpose, while avoiding all kinds of
floating point issues, such as rounding (e.g. 15.0 may actually be
14.99999) and equality (comparing floating point's for equality is
tricky).
No decision has been made yet. I would like to know what application
developers (and not just the subsurface ones) think of this.
3e. Vendor extensions
======================
We want some way to support vendor specific extensions. But it's not
completely clear yet how the interface should look like. It's not the
highest priority, because the above is far more important, but it's good
to keep extensibility in mind!
Anyway, this has been discussed on the mailinglist, so I won't repeat
all the proposals again here.
[1] http://en.wikipedia.org/wiki/Barometric_formula
Jef
More information about the Devel
mailing list