The Aeris 500AI serial number appears to be located at a slightly
different offset, and with an unusual encoding. It's a BCD encoded
number, but with the digits of each byte swapped.
At the moment, the encoding of the serial number is tied to the global
pointer mode. To support devices where this is no longer the case, a new
entry for the serial number encoding is added.
By adding the logbook and profile functions to the vtable, a dive
computer backend can now easily replace the default implementation with
a custom one, without having to duplicate the common code.
The large and complex oceanic_common_device_foreach() function is
refactored into two independent helper functions. One for reading the
entries in the logbook ringbuffer, and another for reading the profile
data.
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.
For devices without a logbook ringbuffer, such as the Oceanic Veo 1.0
and the Aeris XR-1 NX, the ringbuffer begin and end are identical. In
this case, the changes in the previous commit will always result in a
fatal error due to an invalid ringbuffer pointer. To avoid the error, we
exit before trying to use the pointers.
Until now, an invalid logbook pointer was silently ignored and handled
as an empty ringbuffer. But this hides real errors, which is worse than
failing if no dives are present. Trying to download dives from an empty
device should be a rather uncommon scenario anyway.
Most of the changes needed for the F11 are the standard model specific
tweaks. But the F11 also has another interesting "feature". If you try
to download a full memory dump using the standard B1 read command, then
the data starts to repeat after the first 64K. It seems that somehow,
the B1 command can only address the first 64K of the memory. To avoid
this problem, the newer B4 read command needs to be used instead.
This might be a firmware bug, or maybe internally they store the address
in a 12bit variable, which causes the upper bits to get lost? That would
explain the repeating data.
The Hollis TX1 has several new features compared to the other models. It
supports trimix and up to 6 different gas mixes can be configured. It
also has twice the amount of memory, which requires an extra bit for the
ringbuffer pointers.
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.
The new vendor event provides a mechanism to deliver auxiliary data,
which is automatically retrieved during the data transfer, but not
accessible through the library interface otherwise. Possible examples
include handshake data and/or device identification data.
This event is mainly intended for diagnostic purposes, in combination
with the memory dumping support. Very few applications will actually
need it for anything else.
The hardcoded version strings are now grouped into arrays, according to
their corresponding layout descriptor. The main advantage of using
arrays is that new versions strings can now easily be added, without
having to modify any code.
I forgot to update the device and parser initialization functions to
store the context pointer into the objects. As a result, the internal
context pointers were always NULL.
The public api is changed to require a context object for all
operations. Because other library objects store the context pointer
internally, only the constructor functions need an explicit context
object as a parameter.
Adding the "dc_" namespace prefix (which is of course an abbreviation
for libdivecomputer) should avoid conflicts with other libraries. For
the time being, only the high-level device and parser layers are
changed.
The public header files are moved to a new subdirectory, to separate
the definition of the public interface from the actual implementation.
Using an identical directory layout as the final installation has the
advantage that the example code can be build outside the project tree
without any modifications to the #include statements.
The assumption that two consecutive dive profiles are stored without any
gaps in between them, appears to be incorrect in some cases. Instead of
failing with an error we just skip those gaps now.
The Aeris Elite T3 appears to update the global logbook pointer
incorrectly when overwriting old dives. As a result there can be logbook
entries pointing to profile data that has already been overwritten with
newer dives, and those cause problems when calculating the total amount
of bytes in the profile ringbuffer.
As a workaround we validate the logbook pointers immediately after
downloading. At this early stage we can check manually for ringbuffer
overflows without having to rely on the values stored in the data.
If a logbook entry contains an invalid ringbuffer pointer, the error is
not returned immediately, but delayed until the end of the download.
With this approach we can download at least the dives before the
problematic logbook entry.
In a ringbuffer implementation with only two begin/end pointers, it's
impossible to distinguish between an empty and a full ringbuffer. The
correct interpretation mode needs to be specified by the user.
The logbook ringbuffer is now considered empty if any of the pointers is
outside the valid ringbuffer area. Compared to checking only against a
special empty value, this approach makes the code more robust against
invalid pointers.
Some devices do not appear to set the ringbuffer pointers to their
normal empty values (e.g. pointing outside the ringbuffer memory). In
that case, there appears to be a single entry. But since that entry
contains uninitialized memory (e.g. all 0xFF bytes), we are able to
detect this special situation.
Introducing a common base class allows to share more code between the
backends. Sharing the fingerprint data eliminates the need to pass it
with a function parameter.
The memory layout of all Oceanic devices is very similar, which allows
to share the parsing code between the different backends. Differences in
the layout are passed by means of a new layout descriptor structure.
Memory buffers are now allocated dynamically to support devices with
different amounts of memory.