Shifting a 32bit value by 32 is undefined.
Instead of using shifts to create the mask, explicitly create it by
subtracting 1 from the signbit value (and using bitwise NOT to fill all
the higher bits).
This commit looks confusing because Jef wanted me to not have two places
where I use the bitwise not. So instead of creating an equivalent mask
variable and not having to change the return statements we end up with a
mask that is the bitwise invert of what was there before this commit and
therefore the return statements need to change as well.
Coverity CID 207769
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
The communication protocol is identical to the G2 protocol, but with a
different USB VID/PID (c251:2006).
Note that unlike the G2, the Aladin Square seems to support only 33 byte
USB HID packets (1 byte report id and 32 bytes payload), even when the
actual command is much smaller. Without padding the commands, the dive
computer doesn't reply at all. Because the padding is already there, to
support the Windows api, no further changes are necessary.
Currently the date/time parsing assumes the reference time (epoch) of
the device clock is unknown. Hence we retrieve the current time of the
device (devtime) and the host system (systime) during the download.
Since both timestamps represent the same instant in time, but with a
different reference time, we can calibrate the device clock as follows:
ticks = parser->systime - (parser->devtime - timestamp) / 2
But this produces wrong results once the device clock has been adjusted
manually. Adjusting the device clock will suddenly increase (or
decrease) the devtime, while the systime continues ticking forwards
normally. Hence all dives recorded before the time adjustment will get
an incorrect date/time value.
Fortunately all devices appear to use a fixed epoch (2000-01-01 00:00:00
UTC) and we can simply replace the calibration with a hardcoded value.
Reported-By: Linus Torvalds <torvalds@linux-foundation.org>
Those two samples are no longer unknown. The first one contains some
freedive related data, and the second one contains some additional data
with several sub types. At the moment only the tank and gas mix info is
used.
In the trimix data format, the tank and gas mix information is no longer
stored in the header, but in a special sample. Because this sample is
usually located at the end of the profile, the info isn't available yet
during the first pass. Hence the need for a second pass.
Without this change, the tank and gas mix samples will be missing unless
the caller calls the dc_parser_get_field() function before calling the
dc_parser_samples_foreach() function.
The trimix dive header is only 84 bytes large, instead of 0xB1 bytes.
The difference is quite hard to notice, because compared to the normal
Galileo data format, the majority of the fields are located at exactly
the same offset. But there are also some subtle differences, like the
settings field containing the freedive and gauge bits.
To fix this bug, a new header table is added. The rest of the code is
updated to use this new table instead of the old trimix flag. The only
place where the old flag is still used is for the decoding of the tank
and pressure sample.
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.
The Uwatec Aladin Tec 2G doesn't support freedive mode. This appears to
be a bug in SmartTrak and LogTrak. They both report gauge and air/nitrox
dives as apnea dives.
Unlike the other models, the Aladin Tec 2G uses only a single byte to
store the oxygen percentage, and there is no need to manually re-map the
deco mix.
Normally, the oxygen percentage is stored using two bytes (little endian
byte order). Thus for a device supporting two gas mixes, four bytes will
be used, and the corresponding gas mix id for each byte is as follows:
ID: 0 0 1 1
After re-mapping the id of the deco mix, this becomes:
ID: 0 0 2 2
Since oxygen percentages are limited to the range 0-100%, the highest
byte (marked with an X) should always be zero and can thus be ignored:
ID: 0 X 2 X
Now, because an oxygen percentage of zero indicates a disabled gas mix,
this is equivalent to a device supporting three (or even four) gas
mixes, each stored using only a single byte:
ID: 0 1 2 3
We can take advantage of this knowledge to avoid having to re-map the
deco mix id.
In freedive mode the sample rate is only 1 second instead of 4 seconds.
The tank pressure fields appear to be re-used for some other (unknown)
purposes, and should be ignored.
The gauge and freedive mode bits are stored in the settings field. The
location of the gauge bit appears to be the same for all models. For the
freedive bit it depends on the model, and also not all models support
it.
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 dive computer records the raw absolute pressure. To convert this
pressure value into a depth, we need to divide by the salinity factor,
not multiply!
The internal Uwatec tank id should be converted to the libdivecomputer
tank index. If there is no corresponding tank, the tank pressure samples
are dropped for the following reasons:
Some models appear to record an absolute tank pressure sample, even if
there is no pressure sensor attached to the corresponding tank. In this
case only the tank index changes. The sample value simply retains the
last pressure of the previous tank. Since we don't have any real
pressure data, dropping those samples is fine.
The Galileo Trimix supports up to 10 tanks and gas mixes. However, the
existing alarm based gas switch events have only 2 bits available, and
can support at most 4 gas mixes. Therefore, the trimix variant stores
another 4 bit value in the second alarm byte.
For the first three gas mixes (and possibly also the fourth), both alarm
bytes appear to be always set to the same value. For the higher mixes,
the value in the first alarm byte is always zero. This doesn't cause any
problems, because in the data stream the second alarm byte is stored
after the first one, and our final value is always the last one.
The non-trimix variant also has the second alarm byte, but the gas mix
bits appear to be always zero. In order to avoid taking this zero as the
final value, a separate table is used for the trimix variant.
The begin/end pressure for unused tanks is normally zero. But I noticed
that in some cases both pressure values are stored as 0xFFFF. Since that
corresponds to a pressure of 511.99 bar, this is most likely some
special magic value, and not a valid pressure.
Tanks where either the begin or end pressure is 0xFFFF are now ignored
too.
Now that we are able to parse the event bytes properly, there is no need
to pass the raw event bytes to the application.
In the current implementation, the vendor event was broken for devices
with multiple event bytes anyway. Because we deliver all event bytes at
once, the application doesn't know which bytes contain a valid value
(originating from the profile data) or just a dummy zero value.
Right now only gas switch and bookmark events are supported, because
none of the other uwatec events can easily be mapped onto the existing
libdivecomputer events. But the basic infrastructure for supporting more
events is in place now.
The id of the uwatec deco mix is always 2, even for devices which
support maximum two gas mixes. Strictly speaking, this change is more
correct than commit 4fd825cdac341a2d4a1366c6deb7d4a71bbdf94d, allthough
in practice they are equivalent.
The bitmask for the gas mix bits was wrong. With the new mask we also no
longer have to disable the alarm based gas switches for the Meridian and
Chromis.
Originally I assumed it's not possible to enable a gas mix if the
previous gas mix has already been disabled. However, this assumption
turns out to be wrong. For devices with support for 3 gas mixes, it's
possible to enable only the first and the third gas mix, and leave the
second gas mix disabled.
This is fixed by checking all gas mixes, instead of aborting once the
first disabled gas mix has been found. Due to this change the uwatec gas
mix id's are no longer sequential and need to remapped to the
corresponding internal array index.
The Uwatec dive computers report the depth based on fresh water. Salt
water dives need a correction to take into account the salinity. There
is only a fresh/salt water flag present in the data, but Uwatec appears
to assume a salinity factor of 1.025.
The gas mix index stored in the alarm bytes is occasionally out of range
(larger than the number of available gas mixes). The index refers to one
of the disabled gas mixes. Since those are excluded now, this results in
a fatal error instead of a switch to a nonsense gas mix.
To workaround this problem, the alarm based gas switches are disabled
until we figure out how to parse them correctly.
The Chromis is almost identical to the Meridian, and will probably need
the same workaround. Although I don't have any data to confirm this,
let's just keep the two in sync.
Gas mixes are disabled by setting their oxygen percentage byte to 0x00.
This is clearly an invalid gas mix, and it makes no sense to return it
back to the application.
It seems the device doesn't allow you to enable a gas mix if the
previous gas mix has already been disabled. Therefore we can simply stop
parsing the gas mixes once the first disabled gas mix has been found.
According to the technical specifications, the Uwatec Aladin Tec 2G
supports maximum two gas mixes. The data appears to confirm this,
because the extra third gas mix always contains unrealistic oxygen
percentages.
However, I came across some data containing gas switches to the third
gas mix. The interesting part is that according to the Uwatec
application, this is actually a switch to the second gas mix in the
header. One possible explanation is that for models with up to 3 gas
mixes, they are labelled respectively "bottom", "travel" and "deco" mix.
But the documentation for the Aladin Tec 2G only refers to the bottom
and deco mix. So it might be that internally the index of the deco mix
is always the 3th mix, regardless of whether a travel mix is supported
or not.
If the only allowed values for the gas mix index are 0 (for the bottom
mix) or 2 (for the deco mix), then manually remapping the deco mix is
equivalent with ignoring the lowest bit. This has the advantage that the
required bitmasks and shifts are no longer different from those for the
other models.
For the Galileo Trimix we don't know yet where and how the gas mixes are
stored. Right now, we just pretend there are no gas mixes available,
which is misleading.
Originally, I assumed that the trimix firmware update changed the model
number from 0x11 (Galileo) to 0x19 (Galileo Trimix). But that assumption
appears to be wrong because I received data from a Galileo with model
number 0x11, but with the trimix data format. Another explanation might
be that the trimix data format is not specific to the trimix firmware.
Anyway, this is easily fixed by treating both models identically.