2044 Commits

Author SHA1 Message Date
Jef Driesen
eb4b082b1b Use a different buffer size for Rx and Tx
The BLE (and USBHID) protocol stores the size of the payload as a single
byte in the packet header. Hence the size of the payload is limited to a
maximum of 255 bytes. For sending packets, there is an additional
command byte present, which reduces the maximum payload size to 254
bytes. For receiving packets, there is no command byte present and thus
the maximum payload size is 255 bytes.

The Scubapro G3 sends BLE packets of 256 bytes, and that caused the
download to fail because the receive buffer was one byte too small.
2024-05-16 16:41:57 +02:00
Jef Driesen
8fe598e1b0 Merge branch 'sirius' 2024-05-03 17:27:39 +02:00
Jef Driesen
1663997111 Add support for the Mares Sirius (and compatible models)
The Mares Sirius uses the same communication protocol as the Genius,
except for the fact that it uses a newer BLE version which supports
larger data packets. The actual MTU is likely negotiated because we see
different sizes like 244 and 182 bytes. We don't have access to this MTU
size because not all BLE implementations can expose this information.

Unfortunately not only the BLE packet size is variable, but also the
size of the higher level data frames (used for downloading the content
of the objects) is no longer fixed. The frame size appears to adapt to
the BLE MTU size. This is most likely done to reduce the overhead and
maximize the throughput.

Although each frame ends with an OxEA byte, we can't rely on this
knowledge to detect the end of the frame. The END byte is not escaped in
the payload, and thus can also appear anywhere in the frame. As a
workaround, we rely on the fact that each frame appears to be send as a
single BLE packet. The only exception is the ACK byte, which gets send
as a separate BLE packet if the command requires parameter data.

Compatible models: Quad Ci, Puck 4 and Puck Air 2
2024-05-03 17:27:25 +02:00
Jef Driesen
f20d9cb972 Refactor the Mares Genius and Horizon parser
The current implementation assumes a fixed order for the different
record types to share some code with the older models. See commits [1]
and [2] for more details. The main disadvantages of this approach are
the extra complexity and the limited flexibility to adapt to future
changes to the data format.

To make the parsing code more future proof, split the code into separate
functions for the Genius/Horizon and the older models.

[1] Commit 8b06f2c31d437d6e067c21e7263b5ccc33539537 (Horizon)
[2] Commit feec939a2924095f07e030aa98d839b40d4cb6cc (Genius)
2024-05-03 17:27:25 +02:00
Jef Driesen
4516842a5a Use a new command to read the serial number
The Mares Genius (and compatible models) uses a new command to download
different types of objects, instead of manually reading and parsing the
flash memory. This command also supports reading device properties like
the serial number.

This change is necessary because newer models like the Sirius no longer
support reading directly from the flash memory.
2024-05-03 17:27:25 +02:00
Jef Driesen
9a603fa8cf Use macros to detect the device type
The macros make the code a bit more compact, and adding support for new
models becomes easier too.
2024-05-03 17:27:25 +02:00
Jef Driesen
89a28427d6 Increase the BLE packet size
Devices supporting BLE 4.2 (or higher) can use data packets with a
payload size of up to 244 bytes. None of the current Mares models
support this at the moment, but increasing the size on the receiving
side already prepares the code for future models and remains fully
backwards compatible.
2024-05-03 17:27:22 +02:00
Jef Driesen
4914f6bff3 Fix the memory layout of the Oceanic Geo
For devices with a newer firmware version (2B) the profile ringbuffer
ends already at 0xFE00, while for devices with an older firmware version
(1D) it runs to the end of the memory.
2024-04-21 22:50:57 +02:00
Jef Driesen
dcf842cd9d Fix the Apeks DSX tank number
Since commit f5f855d4284a84d5249462c46a9c4f6107a12b09, the tank number
should remain one based instead of zero based.
2024-04-01 23:37:37 +02:00
Jef Driesen
8745a3b95a Fix the Mares usb-serial communication
The BLE changes in commit e83732e200620882b13804f1ca54c1ab90a38188 are
causing major problems for some of the usb-serial enabled models, like
the Puck Pro and Quad Air.

These models appear to require a small delay of a few milliseconds
between sending the two command bytes and the remainder of the command
payload. I suspect the device is still busy processing those first two
bytes, and thus not ready in time to receive the remaining data. Instead
of manually adding a fixed delay, restore the previous behaviour and
wait for the ack byte again. This has the advantage that the delay is
automatically proportional to the response time of the dive computer.

For the BLE communication nothing changes.
2024-03-26 22:32:48 +01:00
Jef Driesen
a86cb92ed8 Add some more details to the error messages 2024-03-26 22:19:02 +01:00
Jef Driesen
b8c3a09c6f Fix a macro redefinition warning
The C library stdio.h header file already defines the EOF macro. Rename
our macro to avoid the conflict.
2024-03-21 19:18:04 +01:00
Jef Driesen
6903a66cc5 Update the Github actions
All Github actions using Node.js 16 are deprecated [1]. Update the
following actions to a newer version using Node.js 20:

 - actions/checkout
 - actions/upload-artifact
 - microsoft/setup-msbuild

[1] https://github.blog/changelog/2023-09-22-github-actions-transitioning-from-node-16-to-node-20/
2024-03-20 17:31:15 +01:00
Janice McLaughlin
9070da3570 Add support for the Aqualung i330R and Apeks DSX
The Aqualung i330R and Apeks DSX use a completely new communication
protocol. The main (and most problematic) difference is the use of a
proprietary bluetooth pairing mechanism instead of the standard
bluetooth pairing. The data format remains more or less compatible with
the previous models, with only the usual changes to the parser.

The initial code and reverse engineering work was contributed by Janice,
with further improvements and modifications for integration in
libdivecomputer by Jef.

Co-authored-by: Jef Driesen <jef@libdivecomputer.org>
2024-03-20 17:24:59 +01:00
Jef Driesen
8e349d4046 Add ioctl's for the bluetooth authentication
For dive computers which are using an application specific proprietary
pairing mechanism instead of the standard bluetooth pairing, we need to
be able to exchange some additional information with the application.
Therefore, 3 new BLE specific ioctl's are added:

When a device has not been paired yet, libdivecomputer will request the
PIN code from the application with DC_IOCTL_BLE_GET_PINCODE. Once the
device has been paired successfully, the access code is passed back to
the application with DC_IOCTL_BLE_SET_ACCESSCODE. On the next download,
libdivecomputer will request this access code again from the application
with DC_IOCTL_BLE_GET_ACCESSCODE. If no access code is available, the
pairing procedure will start again by requesting the PIN.
2024-03-20 17:24:59 +01:00
Jef Driesen
47f6949db1 Merge branch 'pelagic-refactor' 2024-03-20 17:24:25 +01:00
Jef Driesen
9070b7d035 Log the ringbuffer pointers
Logging the ringbuffer pointers is very useful while investigating
problems and adding support for new models.
2024-03-20 17:23:46 +01:00
Jef Driesen
4cc0bc25ae Support reading the logbook in forward direction
To prepare the code to support reading the logbook ringbuffer in the
forward direction, a new field is added to the layout data structure to
indicate the direction of the ringbuffer, the workaround for handling an
invalid pointer is extended to support both directions, and finally the
correct parameters are passed to the rbstream reader.
2024-03-20 17:23:46 +01:00
Jef Driesen
f49af5208c Separate the error handling from the size calculation 2024-03-20 17:23:46 +01:00
Jef Driesen
b9d7684552 Refactor the code to read the ringbuffer pointers
Move the code to read the ringbuffer pointers into a separate function
that deals with all the quirks internally and simply returns two
begin/end pairs.

To obtain the logbook end pointer, the page size is now added to the
value of the last pointer without taking into account the ringbuffer
boundaries. Therefore the boundary checks in the caller need to be
relaxed to accept the end pointer as a valid value.

The profile begin/end pointers are not used anywhere and are only
retrieved for diagnostics purposes.
2024-03-20 17:23:46 +01:00
Jef Driesen
ae292253ba Refactor the code to read the device info
Move the code to read and emit the device info into a separate function
to reduce some code duplication.

As a side effect, the check for devices without a logbook and profile
ringbuffer needs to be performed earlier now, in order to prevent a
division by zero in the progress events.
2024-03-20 17:23:46 +01:00
Jef Driesen
a91a7dbc38 Refactor the function to get the profile pointers
Refactor the code to retrieve the profile pointers from the logbook
entry into a single function that deals with all the quirks internally
and simply returns a begin/end pair.

To obtain the end pointer, the page size is now added to the value of
the last pointer without taking into account the ringbuffer boundaries.
The consequence are:

 - The boundary checks in the caller need to be relaxed to accept the
   end pointer as a valid value.
 - The check for the gap between the profiles can no longer compare the
   pointer values directly because the begin/end values are equivalent,
   but not equal.
2024-03-20 17:23:46 +01:00
Jef Driesen
121c7c12fb Swap values 2 and 3 of the pointer mode
Swapping values 2 and 3 of the pointer mode has the advantage that only
the mode with the largest value uses bytes as its unit, while all others
use the page size as their unit.
2024-03-20 17:23:43 +01:00
Jef Driesen
f42449b101 Fix the Aeris 500AI logbook read command
The two bytes in the command to read the logbook index are most likely
not a single 16 bit number, but two 8 bit numbers specifiying a range.
The same pattern can be found in the logbook pointers.
2024-03-15 14:26:25 +01:00
Jef Driesen
aa2dbac509 Log the number of skipped bytes 2024-03-15 14:26:25 +01:00
Jef Driesen
60a9b889de Merge branch 'ringbuffer' 2024-03-14 12:26:52 +01:00
Jef Driesen
4139509238 Use symbolic constants for empty/full ringbuffer 2024-03-14 12:26:24 +01:00
Jef Driesen
1ba7e5cad0 Fix errors in the ringbuffer operations
The ringbuffer calculations contained several flaws:

The ringbuffer_normalize() function doesn't shift the result from the
internal normalize call back to the range [begin,end-1]. The only reason
why this bug didn't cause any issues yet, is because this function isn't
used anywhere.

The ringbuffer_distance() function can return a wrong result whenever
the difference between the two values is an exact multiple of the
ringbuffer size. For example:

  distance(x,x,n)   == 0 or n (depending on the empty/full mode)
  distance(x,x+n,n) == 0
  distance(x+n,x,n) == n

So far this bug didn't cause any problems yet, because in practice this
function is always used with values inside the safe range [begin,end-1].

For input values outside the safe range [begin,end-1], only larger
values are accepted, while smaller values will trigger an assert.

A zero-length ringbuffer (e.g. begin == end) results in a division by
zero.
2024-03-14 12:26:24 +01:00
Jef Driesen
04fe252625 Merge branch 'rbstream' 2024-03-14 12:26:07 +01:00
Jef Driesen
9090f713b4 Add support for reading a ringbuffer forwards
A dive computer typically writes its ringbuffer in the forward
direction. Thus, when downloading the dives in reverse order (newest
first), the ringbuffer needs to be read in the backward direction.

However, some dive computers already re-arrange the data in the correct
order, which means the data needs to be read in the opposite direction.
To support this case without drastic changes in the logic, the rbstream
implementation is extended to also support reading in the forward
direction.
2024-03-14 12:25:37 +01:00
Jef Driesen
00b0169578 Update the internal state in-place
Some of the internal state is cached in local variables at the start of
the function, and is updated only at the end of the function. But the
contents of the packet buffer is never cached. As a result, the two can
go out of sync when an error occurs and the function returns early.
Trying to restore the original state is pointless if the corresponding
data in the packet buffer is no longer available.

Fixed by removing the local variables and always updating the internal
state in-place to reflect the current state.
2024-03-14 12:24:58 +01:00
Jef Driesen
e0cf41a14e Add some extra parameter validation
The ringbuffer boundary addresses (begin/end) should be ordered
correctly, and the packet size should be smaller than the ringbuffer
size, otherwise the code won't work as expected.
2024-03-14 12:24:45 +01:00
Jef Driesen
f5f855d428 Discard pressure samples from invalid tanks
Keeping the one based tank number interally allows to easily discard the
pressure samples from invalid tanks. This avoid returning a huge tank
number (e.g. 0xFFFFFFFF) when the internal tank number happens to be
zero.
2024-03-13 16:52:05 +01:00
Janice McLaughlin
811ae7de82 Add the deco and rbt samples
Add the deco and rbt samples for the Oceanic Pro Plus 4 and Aeris Atmos
AI 2.
2024-03-13 16:51:55 +01:00
Jef Driesen
1d0aeecf65 Fix the React Pro White memory layout 2024-01-18 10:53:08 +01:00
Jef Driesen
de6696bc7f Add support for the Shearwater Tern 2024-01-17 07:48:54 +01:00
Jef Driesen
cfe345aa8e Exclude O2 sensors without calibration data
O2 sensor for which no calibration data is available will always result
in a ppO2 value of zero for all samples, which isn't very useful.
2024-01-12 09:15:12 +01:00
Jef Driesen
d47e1ce02b Add support for the Scubapro G3 and Luna 2.0
The new models appear to be compatible with the previous G2, but with
new model numbers and bluetooth names. The USB VID/PID for the G3 is
still unknown.

Reported-by: Greg McLaughlin <support@moremobilesoftware.com>
2024-01-10 09:01:59 +01:00
Jef Driesen
08d8c3e132 Add support for parsing the compass bearings
When no compass bearing is set on the dive computer, the stored value is
initialized to zero. Since this can also be a valid value, those zero
values are only ignored untill another non-zero value is present.

In later firmware versions, the value will get initialized to 0xFFFF
instead.
2023-11-23 11:42:23 +01:00
Jef Driesen
2d9008aff7 Remove disabled gas mixes
Returning disabled gas mixes to the application mainly results in lots
of unnecessary information. Therefore, remove all disabled gas mixes,
unless they are actively used. Many other dive computers do not even
include disabled gas mixes in the data.

Unlike previously assumed, the on/off state of each gas mix is actually
available in the PNF data format (opening record 4). For the older
Predator data format, this info isn't available and all gas mixes are
manually marked as enabled.
2023-11-15 11:08:21 +01:00
Jef Driesen
e1762fc8bd Skip all non-sample records
The IX3M 2 with the APOS5 firmware supports a new info record containing
the GPS coordinates. To be able to identify this new record type, the
previously reserved field at byte offset 52 is now used to store the
record type: zero for the existing sample record and one for the new
info record.

This also fixes the underlying problem of the zero timestamp in commit
3c50e91a1096332df66b2d33d64e5a8dc9136ab9, because the zero timestamp was
the result of incorrectly interpreting the first info record as a sample
record.
2023-11-02 15:45:24 +01:00
Jef Driesen
3c50e91a10 Allow a zero timestamp for the first sample
Previously the timestamp of the first sample was always a non-zero
value, but the IX3M 2 with the APOS5 firmware now appears to record a
timestamp of zero. This was incorrectly detected as a backwards time
jump because the time is also initialized to zero.
2023-10-29 21:31:40 +01:00
Jef Driesen
cb0164150e Merge branch 'bluelinkpro' 2023-10-19 10:34:26 +02:00
Jef Driesen
e83732e200 Fix the Mares Bluelink Pro communication
Sending the two byte command header and then waiting for the ack byte
before sending the remainder of the command payload causes problems for
some (but not all) users. Most likely the extra roundtrip time due to
waiting for the ack byte results in a delay that sometimes exceeds a
timeout in the dive computer while it's waiting for the payload data.

On the other hand, sending both the command header and the payload data
in one single packet is also not an option, because it causes problems
for some models, like the Mares Matrix. See commit
59bfb0f3189b14ae858650b851539d59e3fefe86 for details.

As an alternative solution, send the packet payload immediately after
the header, without waiting for the ack byte. This eliminates the extra
roundtrip time, while still sending out two separate bluetooth packets.
2023-09-27 10:10:40 +02:00
Jef Driesen
a7e7439cab Setup the 2 byte command header internally
Instead of setting up the two byte command header in every function,
move this logic to a central place.
2023-09-15 09:23:58 +02:00
Jef Driesen
072f0d4242 Fix a potential buffer overflow 2023-09-08 16:10:45 +02:00
Jef Driesen
baa1c494c1 Use a symbolic constant for the header size 2023-09-08 16:10:45 +02:00
Jef Driesen
330cb88952 Use plain ascii text in the code comments 2023-09-08 16:10:38 +02:00
Jef Driesen
37421a1b9a Merge branch 'filter-function' 2023-08-24 17:18:46 +02:00
Jef Driesen
fe9b47f4bd Document the device descriptor functions 2023-08-24 17:18:24 +02:00