Skip to content

Update Upstream libdivecomputer to 0.9.0. #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

mikeller
Copy link
Member

  • Wait longer before retrying and ignore invalid bytes
  • Add support for the Halcyon Symbios
  • Remove some unused variables
  • Use the GCC unused attribute to silence warnings
  • Remove the duplicated C_ARRAY_SIZE macros
  • Replace the dc_descriptor_iterator function
  • Mark the descriptor parameter as const
  • Check the descriptor transport in the filter
  • Remove the rfcomm filter function
  • Select a bluetooth enabled model as the default
  • Verify the checksum in the dive header
  • Read the model number for diagnostics purposes
  • Add support for the Puck Lite
  • Limit the size of the fingerprint to 4 bytes
  • Include the fingerprint data in the logs
  • Ignore zero pressure values
  • Add support for a new Sirius profile version
  • Add support for the OSTC 5
  • Add support for the average depth
  • Fix the decoding of the temperature
  • Fix the active gasmix detection
  • Use a layout descriptor with a generic decode function
  • Read the payload and trailer byte separately
  • Add support for the Cressi Archimede
  • Add support for time synchronization
  • Add extra debug information to the log
  • Add support for a new Sirius header version
  • Fix the name of the include guard
  • Fix the ppO2 scaling factor
  • Link the tank to the corresponding gas mix
  • Add support for new record types
  • Update the filter function
  • Change the order of the functions
  • Rename the prefix functions
  • Use a case-insensitive comparision
  • Add support for a new Cressi Nepto firmware
  • Fix the Cressi Nepto filter function
  • Fix the ppO2 sensor index
  • Always initialize all fields to zero
  • Fix the deco stop depth scaling factor
  • Report the device model number
  • Detect NAK response packets
  • Ignore invalid start bytes
  • Add support for the Seac Tablet
  • Support RDBI responses with a variable size
  • Increase the size of the firmware version buffer
  • Add a new Perdix 2 hardware model
  • Fix a small mistake in the debug output
  • Fix the date/time parsing
  • Add a new Perdix 2 hardware model
  • Add some extra debug logging
  • Release version 0.9.0

jefdriesen and others added 30 commits December 20, 2024 09:09
When an error occurs, simply re-sending the failed command doesn't
always work. Sometimes we appear to receive some stale data from the
previous attempt, despite the fact that the input queue is purged before
retrying.

To improve the chances of re-synchronizing on the start of the next
packet, wait a bit longer before re-trying and also ignore all received
bytes until an ACK byte is encountered. This isn't entirely reliable,
because the payload data isn't escaped and can also contain ACK bytes,
but it's better than nothing.

Below is a real-life example of such a case.

First, we hit a timeout:

  [8.122494] INFO: Write: size=2, data=E742
  [8.122663] INFO: Write: size=8, data=708F020080000000
  [11.130287] INFO: Read: size=0, data=
  [11.130308] ERROR: Failed to receive the answer. [in src/mares_iconhd.c:213 (mares_iconhd_packet)]

Next, we retry a few times:

  [11.130321] INFO: Sleep: value=100
  [11.230536] INFO: Purge: direction=1
  [11.231117] INFO: Write: size=2, data=E742
  [11.240494] INFO: Write: size=8, data=708F020080000000
  [11.415317] INFO: Read: size=20, data=0000000035004F000C00000037004F0000000000
  [11.415331] ERROR: Unexpected answer byte. [in src/mares_iconhd.c:219 (mares_iconhd_packet)]
  [11.415339] INFO: Sleep: value=100
  [11.515889] INFO: Purge: direction=1
  [11.517474] INFO: Write: size=2, data=E742
  [11.517628] INFO: Write: size=8, data=708F020080000000
  [11.517798] INFO: Read: size=13, data=1300000036004F000A00000037
  [11.517803] ERROR: Unexpected answer byte. [in src/mares_iconhd.c:219 (mares_iconhd_packet)]

That didn't really work, but the interesting part is that we did receive
some data now. We also see the same data appear in the next retry:

  [11.517811] INFO: Sleep: value=100
  [11.618398] INFO: Purge: direction=1
  [11.618760] INFO: Write: size=2, data=E742
  [11.619100] INFO: Write: size=8, data=708F020080000000
  [11.619341] INFO: Read: size=1, data=AA
  [11.619349] INFO: Read: size=20, data=0000000035004F000C00000037004F0000000000
  [11.619355] INFO: Read: size=20, data=37004F001E00000036004F001000000037004F00
  [11.619360] INFO: Read: size=20, data=2C00000037004F001200000034004F0033000000
  [11.619366] INFO: Read: size=20, data=37004F000000000037004F001E00000036004F00
  [11.630104] INFO: Read: size=12, data=1300000036004F000A000000
  [11.630122] INFO: Read: size=20, data=37004F002000000038004F001D00000038004F00
  [11.630131] INFO: Read: size=17, data=2300000039004F000600000037004F00EA

This time, the retry seems to have worked and we move on to the next
request:

  [11.635160] INFO: Write: size=2, data=E742
  [11.635359] INFO: Write: size=8, data=F08E020080000000
  [11.687620] INFO: Read: size=1, data=AA
  [11.708476] INFO: Read: size=20, data=0000000035004F000C00000037004F0000000000
  [11.719214] INFO: Read: size=20, data=37004F001E00000036004F001000000037004F00
  [11.719231] INFO: Read: size=20, data=2C00000037004F001200000034004F0033000000
  [11.719240] INFO: Read: size=20, data=37004F000000000037004F001E00000036004F00
  [11.740569] INFO: Read: size=13, data=1300000036004F000A00000037
  [11.740585] INFO: Read: size=20, data=004F002000000038004F001D00000038004F0023
  [11.740592] INFO: Read: size=20, data=00000039004F000600000037004F00EAAA090010

This appears to have worked, but upon closer inspection you can see that
the very last packet already contains the start of the response to the
next request (AA090010). But we haven't send the next request yet!

That means the response we received here is actually the response to one
of the earlier (failed) request and this start of the next packet is our
real response. So we're getting completely out of sync! Unfortunately
the Mares protocol doesn't use checksums or sequence numbers, so we
can't really detect this problem.
The Halcyon Symbios HUD and Handset support both BLE communication and
USB mass storage mode. In both cases the dives have the same data
format.

Tested-by: Benjamin Kuch <[email protected]>
Mark some variable with the GCC 'unused' attribute to silence (harmless)
compiler warnings (-Wunused-variable and -Wunused-but-set-variable). The
variables are kept because they are valuable as documentation or for
debugging purposes.
Use the common macro defined in the array.h header instead of
duplicating the same macro. The C_ARRAY_ITEMSIZE macro is also moved to
the common header.
The existing dc_descriptor_iterator function is missing a context
parameter, and also doesn't follow the standard naming convention. Fixed
by adding a new dc_descriptor_iterator_new function.

For backwards compatibility, the old function remains present in the
library and a macro is used to automatically redirect to the new
function.
The descriptor functions do not modify the passed descriptor. This is
now made explicit by marking the parameter as const.
The filter function should take into account the transports supported by
the device descriptor. If a transport isn't supported, the filter
function shouldn't indicate a match.
The rfcomm filter function is not only platform dependent (Linux only),
but also difficult to use correctly. It should only be enabled for
devices which support DC_TRANSPORT_SERIAL due to the serial port
emulation layer of the bluetooth Serial Port Profile (SPP/rfcomm), and
not for usb-serial communication. However, some dive computers models
like the OSTC3 have both rfcomm and usb-serial enabled variants. Since
the filter functions are shared by all models, the result isn't always
reliable.

Fixed by simply removing the rfcomm filter. For serial communication,
every string will now be considered a match, which is the same result as
with no filter function present.
Using a bluetooth enabled model (e.g the OSTC 2) as the default choice
is very convenient when using only the --family command-line option to
scan for bluetooth devices or establish a connection. That's because
after commit ce2c3c6, the filter will
no longer result in a match for the non-bluetooth enabled models.
The checksum can help to detect corrupt dives and/or bugs in the
download code.
The model number isn't strictly needed anymore, because libdivecomputer
uses the information in the version packet to the detect the dive
computer model. However, since the internal lookup table is still based
on the model number, having easy access to the model number in the debug
logs is very convenient when adding support for new devices.
The Puck Lite re-uses the same model number as the Puck 4. Only the
bluetooth device name appears to be different.
For the Sirius (and compatible models), the data/time information is
only 4 bytes large instead of the default 10 bytes.
The fingerprint data is valuable information when trying to reproduce
some issues reported by users.
Occasionally there are a few samples with a zero pressure value at the
begin and/or the end of a dive. Those values result in an incorrect
begin/end pressure. Fixed by ignoring the zero pressure values.
After upgrading a Mares Sirius to firmware version 1.6.16, the profile
version changed to v2.0. Surprisingly, despite the change in the major
version number, there appear to be no functional changes in the data
format.

Signed-off-by: rmultan <[email protected]>
The OSTC 5 uses the same firmware as the OSTC 4 and is therefore fully
compatible. The new bluetooth name "OSTC5-XXXXX" is already recognized,
because the filter checks for the generic "OSTC" prefix.
The lower nibble at offset 0x0C contains part of the dive time and only
the higher nibble contains part of the temperature. Since this extra
nibble ended up as the second decimal figure, the error is actually very
small and nobody really noticed the mistake.
The Cressi Edy appears to set the disabled gas mixes to 0xFF. The check
for the magic value 0xF0 doesn't catch this case and therefore the value
0xFF results in a gas mix with 165% O2, which is obviously invalid.

Fixed by checking the high nibble only.
Replace hardcoded constants with a layout descriptor. This reduces the
amount of model specific conditions, and makes it easier to add support
for new models.

The Cressi data format uses nibbles (4 bits) as the smallest unit of
storage. Larger values are stored as one or more nibble, typically with
a BCD (binary coded decimal) encoding applied. To decode such variable
sized numbers, a generic function is added. The offsets in the layout
descriptor are also specified in nibbles instead of bytes.
Reading the payload and the trailer byte separately simplifies the code
in the caller because the destination buffer doesn't need space to store
the extra trailer byte.
The Cressi Archimede protocol is very similar to the existing Edy
protocol, with a few smaller differences:

 - No init3 command and baudrate change
 - Smaller packet size (32 instead of 128 bytes)
 - Modified read command with a 1 byte address

The most curious change is the fact that the nibbles of all bytes are
reversed (little endian). To simplify the processing of the data, the
nibbles are swapped again immediately after downloading.
The Suunto d9/vyper2 protocol supports a command to synchronize the
clock.
The Mares Sirius firmare upgrade to v1.6.16 also changed the header
version to v2.0. Again, there appear to be no functional changes in the
data format.

See also commit 82712ce.
The ppO2 values are stored with a unit of 0.01 bar and not 0.1 bar.
jefdriesen and others added 27 commits May 8, 2025 19:24
The USB matching functions have been moved to the top so that all the
string based matching functions are grouped together.
The prefix based matching functions have been renamed so that their
function names share the same prefix.
The other prefix matching function already use a case-insensitive
comparision. There is no reason for a different behaviour.
The Cressi Nepto with firmware v209 uses format version 4. Since the
exact range isn't known, assume all firmware versions between 200 and
299 use the same format.
The model number in the bluetooth device name appears to be encoded as a
hexadecimal number instead of a decimal number (e.g. a_xxxx vs 10_xxxx
for the Nepto).
The code used the wrong loop variable as the ppO2 sensor index.
The decompression stop depth values are stored with a unit of
centimeters and not 1 meter.
The hardware info contains a 32 bit model number that can be used to
distinguish the different models. There is also a serial number prefix
(at offset 8) which contains a single letter that serves the same
purpose:

  A = Action
  B = Screen
  E = Tablet
Errors are reported by the dive computer with a NAK packet containing an
error code. Detect and handle such packets and log the error code.
Ignoring all received bytes until an START bytes is encountered makes
the re-synchronization on the start of the packet a bit more robust.
The Seac Tablet uses almost the same protocol as the Seac Screen and
Action, but with a few small differences:

 - A slightly different set of commands, but with exactly the same
   functionality.
 - The new variant of the READ command does no longer pad the response
   packet to 2048 bytes.
 - The profile area starts at address 0x0A0000 instead of 0x010000.

The Seac Tablet also support tank pressure transmitters.
The RDBI commands typically have a response with a fixed size, but
apparently some responses can also have a variable size. To support such
responses, an extra output parameter is added to report the actual size.
The latest version of the Perdix 2 firmware is at version 100. Since the
firmware version is reported as the string 'V100 Classic' in the RDBI
response, it now requires a buffer with space for one more digit. The
size of the response is no longer fixed either.
The device field in the CFG_ID_VERSION record is not the device model,
but the device type (Freedom or Libery).
The Symbios stores the date/time value as a UTC timestamp. Since there
is no timezone information present, I incorrectly assumed the timestamp
actually represented local time. Therefore I used the gmtime function to
perform a timezone independent conversion.

Fixed by using the localtime function instead.

Note: this approach makes the conversion dependent on the current
timezone of the host system, but there is no guarantee this timezone is
indeed the correct timezone in which the dive was recorded!
@mikeller mikeller merged commit b2c1487 into subsurface:Subsurface-DS9 Jul 2, 2025
7 of 8 checks passed
@mikeller mikeller deleted the update_libdivecomputer_0_9_0 branch July 2, 2025 11:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants