The dc_parser_set_data() function allows to re-use a parser object for
multiple dives. The advantages of this feature are actually very limited
in practice. The reduction in memory consumption is almost negligible,
because the amount of internal state in the parser is typically very
small. But the implementation requires some additional complexity
because each backend needs code to reset its internal state. Therefore,
the function is removed and the data and size needs to be passed
directly to the dc_parser_new() and dc_parser_new2() functions instead.
Because keeping a reference to the data has also caused issues in the
past, especially for applications implemented in a garbage collected
language, the data will now also get copied internally.
Because the sample struct is passed by value, the size of the structure
can't be changed without also changing the function signature and
breaking backwards compatibility. This prevents adding new fields in the
future, to support some new features.
When passing the sample struct by reference using a pointer, the size of
the pointer does always remains the same.
For gas consumption calculations it's very convenient to know whether a
tank is used for example in a sidemount configuration, or as
oxygen/diluent tank on a rebreather.
For rebreather dives, it's convenient to know whether a gas mix is used
as a closed-circuit mix (oxygen/diluent) or as an open circuit mix
(bailout).
Some dive computers report the time of the next decompression stop,
while others report the Time To Surface (TTS). Some models can even
report both.
Add a TTS field to the deco sample to support both values.
Some dive computers, especially freediving computers, supports multiple
samples per second. Since our smallest unit of time is one second, we
can't represent this, and the extra samples are dropped. Therefore, the
units are changed to milliseconds to prepare supporting this extra
resolution.
For dive computers where the reference time (epoch) of the device is
unknown, libdivecomputer uses the current time of the device (devtime)
and the host system (systime) to synchronize both clocks.
Currently, both timestamps are passed directly to the constructor of the
parser. With the new public function, the application can adjust the
timestamps afterwards.
Some dive computers store the depth as an absolute pressure value (in
bar). To convert to a depth value (in meters), the atmospheric pressure
and water density are required. For dive computers that do not have
those values available, libdivecomputer uses a default value. With the
new public api functions, applications can adjust those default values.
Some dive computers already provided a backend specific calibration
function. Those functions are now deprecated. They are kept around to
maintain backwards compatibility for now, but they will be removed in
the next version.
Report the decompression algorithm (Buhlmann, VPM, RGBM or DCIEM), and
if available also the parameters. For now only the conservatism setting
is supported, and for the Buhlmann algorithm also the Gradient Factors
(GF).
The Suunto DX supports 3 CCR diluents and 8 OC gas mixes. Since the gas
mix index in the data is relative to either the set of CCR diluents or
OC gas mixes (depending on the dive mode) and libdivecomputer reports
both sets, the index needs to be adjusted.
There is no need to lookup the gas mix index, because the number is
stored directly in the event data, right next to the oxygen and helium
values. This actually removes an ambiguity in cases where the user has
configured two or more identical gas mixes. In that case, the lookup
would always find the first gas mix.
Add a new type to distinguish between closed circuit (CCR) and
semi-closed circuit (SCR) diving. Some dive computers from HW and
DiveSystem/Ratio support this.
Because the CCR/SCR abbreviations are more commonly used, let's take the
opportunity to also rename the existing DC_DIVEMODE_CC. To preserve
backwards compatibility, a macro is added to map the old name to the new
one.
Reported-by: Jan Mulder <jlmulder@xs4all.nl>
Allthough most dive computers always use local time and don't support
timezones at all, there are a few exceptions. There are two different
sources of timezone information:
- Some of the newer Uwatec/Scubapro devices use UTC internally and also
support a timezone setting. This UTC offset is currently taken into
account to obtain the dive date/time, but the UTC offset itself is
lost.
- Uwatec/Scubapro and Reefnet devices rely on the clock of the host
system to synchronize the internal device clock and calculate the
dive date/time. The consequence is that the resulting date/time is
always in the timezone of the host system.
In order to preserve this timezone information, the dc_datetime_t
structure is extended with a new "timezone" field, containing the UTC
offset in seconds. Devices without timezone support will set the field
to the special value DC_TIMEZONE_NONE.
The dc_datetime_localtime() and dc_datetime_gmtime() functions will
automatically populate the new field with respectively the local
timezone offset and zero. The dc_datetime_mktime() function will take
into account the new timezone field for the conversion to UTC. The
special value DC_TIMEZONE_NONE is interpreted as zero.
The vendor_product_parser_create() and vendor_product_device_open()
functions should be called indirectly, through the generic
dc_device_open() and dc_parser_new() functions. And the
vendor_product_extract_dives() functions are internal functions that
should never have been part of the public api in the first place.
Just like the D4i and D6i, the new header is a few bytes larger. The
correct variant can again be detected by means of the logbook id tag at
the start of the header.
One of the newer D4i and D6i firmware versions (for example v1.5.9),
introduces a new variant of the data format. The new dive header is 8
bytes larger. The correct variant can be detected by means of the
logbook id tag at the start of the header.
Both the allocation and initialization of the object data structure is
now moved to a single function. The corresponding deallocation function
is intended to free objects that have been allocated, but are not fully
initialized yet. The public cleanup function shouldn't be used in such
case, because it may try to release resources that haven't been
initialized yet.
Instead of freeing the object data structure in the backend specific
cleanup function, the memory is now freed automatically in the base
class function. This reduces the amount of boilerplate code in the
backends. Backends that don't allocate any additional resources, do no
longer require a cleanup function at all.
The new gasmix sample contains the index of the active gas mix.
This new sample is intended as a replacement for the existing gas change
events (SAMPLE_EVENT_GASCHANGE and SAMPLE_EVENT_GASCHANGE2). To maintain
backwards compatibility, the legacy events are marked as deprecated but
not removed yet.
The newest Suunto models (e.g. D4i, D6i, D9tx and DX) support a few
additional events (type 0x15 and higher), which are not supported yet
because their interpretation isn't known.
Due to a nasty bug, these unkown events result in "ghost" events. When
such an unknown event is encountered, the sample type field isn't set
explicitely. Therefore it simply retains the value from the previous
sample, whatever that might be. If the previous sample happens to be an
event as well, then the unknown event will show up as a duplicate event.
But if the previous sample is not an event, then the resulting event
type is undefined.
This is fixed by always resetting the event type explicitely. Those
unknown events are also suppressed now and no longer delivered to the
application.
Allthough I haven't observed this bug with the Suunto Eon and Vyper,
they could be affected too.
For the older models, gas mixes are disabled by setting their oxygen
percentage byte to 0x00 or 0xFF. Trying to parse such a byte as a valid
percentage results in an invalid gas mix.
Because the device doesn't allow you to enable a gas mix if the previous
gas mix has already been disabled, we can simply stop parsing the gas
mixes once the first disabled gas mix has been found.
The gas mode should not only be taken into account for parsing the gas
mix definitions, but also for the initial gas mix. Because the logic
needs to be kept in sync, it's convenient to have all related code in a
single place, and cache the value.
Because the gas mode takes precedence over the individual gas mix
definitions, we can simplify the code by taking the gas mode into
account immediately when parsing the gas mixes.
The initial gas mix index has been confirmed for the D6i only. For the
other two models, it's an educated guess that the byte offset will be
identical.
The Suunto dive computers record gas change events in the profile data.
But because there is no gas change event stored on the first sample, the
application doesn't know which gas mix is in use, until the very first
gas change event occurs.
For the Suunto HelO2, the index of the initial gas mix is stored in the
dive header. This is most likely also the case for the other models, but
I haven't found yet where exactly it is stored. As a temporary solution,
we simply assume the initial gas mix is the first gas in the list with
available gas mixes. This should be a reasonable assumption for most
dives.
Fixes ticket #2
The gas mix data is used from multiple functions, and the code to parse
that data is duplicated in each function. Because this is error prone,
the code is moved to a single place, and the data cached in the parser.
This event is on when accumulating deco time. Once you reach the floor
deco time will start decreasing and the event will stop. Going below the
floor again will re-activate the event.
Signed-off-by: Michael Andreen <harv@ruin.nu>
The Suunto DX has support for 8 gas mixes (OC) and 3 diluents (CC).
Because it's still unknown how rebreather dives are stored, we simply
return all 11 gas mixes. For the rest, the DX data format is very
similar to that of the existing Suunto models, with only a few
different offsets here and there.
When the number of parameters is zero, there are no sample values, and
the offset variable is never increased. The result is an infinite loop.
In practice this shouldn't happen because there should always be at
least one sample value (e.g. depth). But if a new data format is
available, which is not yet supported by the parser, we might be trying
to interpret the wrong byte.
Currently, each backend has it's own function to verify whether the
object vtable pointer is the expected one. All these functions can be
removed in favor of a single isintance function in the base class,
which takes the expected vtable pointer as a parameter.
Functions which are called through the vtable, don't need to verify the
vtable pointer, and those checks are removed.
The term "backend" can be confusing because it can refer to both the
virtual function table and the device/parser backends. The use of the
term "vtable" avoids this.