1410 Commits

Author SHA1 Message Date
Dirk Hohndel
fb6cde0d17 Heinrichs Weikamp OSTC: add extended information parsing
This adds the string field interface to the HW OSTC family, including
the proper serial number handling.

The deco model information was done by Anton Lundin in the original
subsurface branch, and the salinity, serial number, battery voltage and
desat information was added by Dirk Hohndel.  Jan Mulder added the
battery percentage.

[ The sign-offs have been taken from the original commits in that old
  subsurface branch, and I'm marking Dirk as the main author because on
  the whole most of the lines come from him  - Linus ]

Signed-off-by: Anton Lundin <glance@acc.umu.se>
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-05-07 15:05:37 -07:00
Linus Torvalds
025fb5ed1a Add serial number to parser creation for ostc, atom2, shearwater and suunto d9
These backends want the serial number for reporting, and can't get it
any other way.

We really should re-organize this.  It's a nasty source of pointless
changes wrt upstream libdivecomputer, and I'm not convinced it's worth
the pain.

We also don't even have a consistent ordering for the arguments. Oh well.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-05-07 15:05:37 -07:00
Linus Torvalds
704ed3f1e4 Add back Mares BlueLink Pro bluetooth support tweaks
The Mares BlueLink Pro BLE dongle is the beast from hell, and introduces
lots of extra slowdowns into the Mares communication protocol.

In particular, it turns out that we really can't send the command bytes,
then wait for the ACK byte, and then send the command argument data as a
separate packet.  Because of the delays that the dongle adds, the dive
computer will have given up on the command arguments by the time it sees
them.

At the same time we don't want to always pass the command and arguments
as one single packet in all situations, because at least the Mares
Matrix really seems to want that "wait for ACK before sending
arguments".  See commit 59bfb0f3189b ("Add support for the Mares
Matrix") for details.

So introduce a new "splitcommand" flag, which is set by default, but
gets disabled for the BLE transport case.

Also, because bluetooth is slow, we don't want to ask for big packets of
data.  It seems to cause a buffer overflow on the BlueLink Pro when the
serial data from the dive computer arrives faster than the bluetooth
data can be sent to the downloading side.

So when using the BLE transport, we also limit the packet size to 128
bytes in addition to disabling the command splitting.

With this, I can download hundreds of kB of data from the Mares Quad Air
successfully over BLE.  It's *slow*, but it works.

This is a re-application of commit 5be8c17ea1 ("Mares bluetooth support
tweaks"), with small changes for how the libdivecomputer IO interfaces
have changed in the meantime.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-05-07 15:05:37 -07:00
Linus Torvalds
a1c408e8f4 Make custom iostream read/write wrapper more rebust
The dc_iostream_{read,write}() implementation had multiple issues:

 - it would return DC_STATUS_SUCCESS even if no iostream implementation
   existed.

   Yes, it would also return a zero "actual" bytes, but most backends
   don't even pass an "actual" pointer, so returning success was still
   completely insane.

   This one probably didn't matter, because all iostreams should have
   read and write members, but the return value was completely wrong if
   that ever were to happen.

 - If the user passed in a NULL 'actual' pointer, the wrapper would
   ignore that, and pass in its own pointer instead, in order to know
   how many bytes to print for the debug message.

   But that means that the low-level read/write functions cannot know
   whether the user actually is able to handle a partial read or not.

   This one _definitely_ matters, because some protocols need to have a
   buffer for the whole incoming packet, but packerts may not always be
   full-size. The low-level protocol needs to know whether to wait for
   further packets (in order to fill the buffer) or to just return the
   partial data.

This fixes these issues.  If the user passes in a NULL actual pointer
(indicating that it needs all-or-nothing and is not ready to handle a
partial success), just loop over the IO until the buffer is fully
exhausted.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-05-07 15:05:37 -07:00
Dirk Hohndel
b9657e4545 Atomics Cobalt: use the new DC string fields
Not a lot of fields, but give the serial number in the proper format,
and other version information (Software version and bootloader version).
And the Nofly time that the dive computer reports.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-05-07 15:05:37 -07:00
Linus Torvalds
62057c90bd Use the extended parsing facilities for the Suunto EON Steel backend
This takes advantage of the field cache and string interfaces, and
reports TTS with the new TTS sample.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-05-07 15:05:37 -07:00
Linus Torvalds
41f89f415e Suunto Eon Steel: sort the dive list properly
Instead of assuming that the dive list is presented in a sorted circular
list, sort it properly alphabetically (which also ends up being a
numerical sort for the HEX ascii dive names).

The "search for most recent dive, then splice the list around" case
doesn't work in the general case.  It happens to work if you don't
delete any dives, and dives only disappear as they are being overwritten
by new dives when the storage overflows.

But if you delete dives and then create new ones, the dive list will not
be sorted at all, and we should sort it properly when downloading.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-05-07 15:05:37 -07:00
Linus Torvalds
8594445088 Add support for the Deepblu Cosmiq+ dive computer
Somewhat basic support, but the data the Deepblu Cosmiq+ reports is
pretty basic.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-05-07 15:05:37 -07:00
Linus Torvalds
4e9e94d9f8 Add backend for Garmin Descent Mk1
This uses pretty much all of our new infrastructure: the USB storage
iostream for the actual IO, the field-cache for the divecomputer fields,
and the string interface for the events.

It's also a very fast downloader.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-05-07 15:05:37 -07:00
Linus Torvalds
99c2ca7205 Add 'usbstorage' iostream
This ends up being just a file interface for dive computers that expose
their data as a filesystem that can be mounted.

Right now that's only the Garmin Descent Mk1, although technically the
Uemis Zurich also did that (but oddly, and the backend was never merged
into libdivecomputer).

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-05-07 15:05:37 -07:00
Linus Torvalds
af2249a7c5 Add generic field cache and string field infrastructure
This adds the infrastructure for the "field cache", which is just
various helpers for the dc_get_field() interface.

This includes the 'dc_field_cache_t' structure that a libdivecomputer
backend can just add to its parser data structure, and a few macros to
make it very easy to initialize the fields and then return them in the
'get_field()' callback.

And part of it is the infrastructure support for the 'dc_field_string_t'
type, which adds the support for string fields.  That will be used to
return various string-formatted data from the dive computer, like deco
models, serial numbers, etc.

And no, a serial number is most definitely not a "number". It's a string.

Right now there are no users of this yet, that comes next.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-05-07 15:05:30 -07:00
Linus Torvalds
086b0a799e Clean up 'dc_tankvolume_t' type and make it 'dc_tankinfo_t'
The dc_tankvolume_t type had information about metric vs imperial
volume, but we actually want other things too, like the actual usage of
the cylinder.

So rename it to 'dc_tankinfo_t' and extend the semantics from an
enumeration of volume units, to be a bitmap of information flags.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-05-07 12:36:23 -07:00
Jef Driesen
9e92381be4 Use a more robust command to write flash memory
The S_BLOCK_WRITE (0x30) command sends a stream of bytes to the dive
computer. Because the payload has no fixed length and there is no length
field included, the hwOS firmware detects the end of the stream by means
of a 400ms timeout. The main disadvantage of this approach is that a
short hiccup in the communication will be incorrectly detected as the
end of the stream.  Hence only a part of the data will get written to
the flash memory, and the remainder of the data will get interpreted as
the next commands.

To avoid this problem, the hwOS firmware v3.09 and later supports a new
S_BLOCK_WRITE2 (0x31) command, which uses a fixed size payload of 256
bytes.

Reported-by: Ralph Lembcke <mail@ralph-lembcke.de>
2020-03-24 18:32:13 +01:00
Jef Driesen
dff6d0c514 Read and cache the firmware version information
By reading the firmware version information immediately after entering
download or service mode, we can identify the specific firmware version
and adapt to minor differences in the communication protocol.
2020-03-24 18:32:13 +01:00
Jef Driesen
da4a8a90c7 Add an extra delay after writing to the flash memory
The S_BLOCK_WRITE (0x30) command sends a stream of bytes to the dive
computer. Because the payload has no fixed length and there is no length
field included, the hwOS firmware detects the end of the stream by means
of a 400ms timeout. Therefore the ready byte is always delayed by this
400ms timeout.

The same remark applies to the DISPLAY (0x6E) and CUSTOMTEXT (0x63)
commands. But because libdivecomputer always pad the text with zeros and
sends the maximum payload size, we won't hit the timeout.

Reported-by: Ralph Lembcke <mail@ralph-lembcke.de>
2020-03-24 18:32:13 +01:00
Jef Driesen
7b9b6b4005 Add an extra delay after erasing a flash memory page
Erasing a flash memory page is a relative slow operation and takes a
significant amount of time. Therefore, the ready byte is delayed, and
the standard timeout is no longer sufficient. Estimate the required
delay and wait.

Reported-by: Ralph Lembcke <mail@ralph-lembcke.de>
2020-03-24 18:32:13 +01:00
Jef Driesen
d1b865d192 Send the service init command one byte at a time
The hwOS firmware reads the service init command one byte at a time, and
sends the echo immediately after each byte.

Reported-by: Ralph Lembcke <mail@ralph-lembcke.de>
2020-03-24 18:32:13 +01:00
Ralph Lembcke
94cd864dba Fix some typos in the comments 2020-03-24 18:32:13 +01:00
Jef Driesen
ffa9e0aa3c Ignore excess bytes in the BLE version packet
For the Oceanic Pro Plus X and the Aqualung i770R, downloading over BLE
often fails because the version packet contains one or more unexpected
bytes.

For a successful download, the correct structure for the version packet
is as follows:

    5A 4F4345414E4F43582031432030303032 C6

That's the start byte, the payload "OCEANOCX 1C 0002" and the checksum.
For all the failed packets, there are one or more bytes extra present
between the payload and the checksum:

    5A 4F4345414E4F43582031432030303032 9F02 67
    5A 4F4345414E4F43582031432030303032 3603 FF
    5A 4F4345414E4F43582031432030303032 64   2A
    5A 4F4345414E4F43582031432030303032 9202 5A
    5A 4F4345414E4F43582031432030303032 08   CE
    5A 4F4345414E4F43582031432030303032 2C01 F3

The amount of extra bytes, and their content appears to be pretty
random. The strangest part is that the checksum of the packet is
actually correct and includes those extra bytes!

As workaround, accept extra bytes in the BLE packet, verify the checksum
as usual, and finally strip the excess bytes and only pass the actual
content to the next layer. To avoid false positives, the workaround is
limited to packets with a payload and checksum, and only enabled for the
two affected models.
2020-03-17 14:33:56 +01:00
Jef Driesen
8a1d32d319 Pass infinite NDL values to the application
When the last deco stop is cleared, the dive computer switches to NDL
mode with an infinite time (0x7FFF for APOS4 and 0xFFFF for APOS3). But
because libdivecomputer does not report those infinite values to the
application, detecting the end of the deco phase is not very intuitive.

This issue is fixed by passing those infinite NDL values as-is to the
application, despite the relative large values (respectively 9.1 and
18.2 hours). For reference, the finite NDL values reported by the ratio
dive computers can be large as well, with values up to 0x4000 (4.55
hours).
2020-02-28 00:14:31 +01:00
Jef Driesen
8fb0f1ca94 Clear the buffer if no dives are present
Due to how the Oceanic ringbuffer is implemented, the ringbuffer always
contains at least one entry. If there are no dives recorded yet, the
content of that entry will be empty. Such entries are already ignored
during processing, but instead of returning this empty entry to the
caller, simply clear the logbook buffer, and return no entries at all.
2020-02-24 09:21:33 +01:00
Jef Driesen
39aad6bb52 Report an error for invalid ringbuffer pointers
Previously, invalid ringbuffer pointers were always handled during the
second pass. But that changed after the previous commit. If the invalid
pointer is located in the first logbook entry, this is now handled as
"no dives present". Fixed by returning the correct error code instead.
2020-02-24 09:21:33 +01:00
Jef Driesen
f93b2afcc8 Improve the empty logbook ringbuffer detection
If all the entries in the logbook ringbuffer happen to be empty, the
ringbuffer end pointer will not have a valid value. Creating the
ringbuffer stream will fail, and an error will be returned to the
caller. Fixed by adding an extra check, and exit if there are no dives.
2020-02-24 08:54:44 +01:00
Jef Driesen
1d235daf30 Skip the BLE handshake for the Pro Plus X
The Oceanic Pro Plus X does not seem to understand the BLE handshake
command. It just fails with a NAK byte (0xA5) as response.
2020-02-21 13:48:11 +01:00
Jef Driesen
5dc7e54596 Implement the gas mix sample
The current gas mix index is stored in the 11th bit of the sample value.
2020-02-13 11:07:24 +01:00
Jef Driesen
59d9791446 Limit the depth value to 11 bits
The depth value is encoded with only 11 bits instead of 12 bits. The
extra bit contains the gas mix index. This resulted in wrong depths,
with values larger than 204.8m.
2020-02-13 11:05:25 +01:00
Janice McLaughlin
a01b9bc9b9 Add support for the Scubapro A1 2020-02-04 08:41:55 +01:00
Janice McLaughlin
4a60f89f4a Add support for the Sherwood Wisdom 4 2020-02-04 08:30:33 +01:00
Nick Shore
ba96b3092d Fix the vtpro datetime parsing
For the BCD encoded day field (range 1-31), two bits are sufficient to
represent the upper digit (range 0-3). The purpose of the highest bit is
unknown, but it's certainly not part of the day field, and needs to be
masked off.
2020-01-28 10:59:22 +01:00
Jef Driesen
cfd54ff80e Advertise the BLE support in the device descriptors
The bluetooth device filtering is based on the fact that the format of
the bluetooth device name is something like 'FQ001124', where the two
first letters are the ASCII representation of the model number (e.g.
'FQ' or 0x4651 for the i770R), and the six digits are the serial number.
2020-01-06 23:26:55 +01:00
Jef Driesen
4bc5ee90ef Fix the BLE device detection for the i770R and Pro Plus X
It seems that the BLE communication protocol is somewhat different from
the serial one in the version string: while the serial version tends to
show the memory size, the BLE version string has some other numeric
pattern.

Linus Torvalds reports the BLE pattern for the i770R is normally just
"0001", allthough he once also observed "0090" with the same dive
computer. A communication trace from a Pro Plus X also showed "0001".

We don't have enough information to guess the meaning of the number.
Regardless, for those two dive computers supporting BLE, make the
pattern simply ignore the last four digits, since they clearly vary.

Based-on-code-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-01-06 23:26:55 +01:00
Jef Driesen
4baf140d25 Implement the BLE handshaking
The BLE communication sends a handshake packet containing a passphrase
based on the serial number of the device. Sadly, we can't actually read
the serial number from the device until after this handshake has
successfully completed, which makes it a bit of a chicken-and-egg
problem from a communication standpoint. However, the serial number is
also exposed in the bluetooth device name the device advertizes, which
is the reason for the newly added DC_IOCTL_BLE_GET_NAME ioctl.

Thanks to Janice McLaughlin for pointing out the logic of this magic
handshake.

Based-on-code-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-01-06 23:26:42 +01:00
Jef Driesen
6ba0726a42 Implement the BLE packet sending and receiving
Based-on-code-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-01-06 21:29:24 +01:00
Jef Driesen
4923d3761e Read the entire data packet in a single operation
Refactor the packet receiving code to read the ack byte, the payload
data and the checksum all at once, with just a single read operation.
This is not only a bit more efficient, but will also simplify the BLE
support.
2020-01-06 21:29:24 +01:00
Jef Driesen
437db813d5 Remove the trailing zero byte from all commands
The trailing zero byte is present for historic reasons only. At the time
the Oceanic protocol was implemented, the Oceanic application send this
extra zero byte too, and we simply copied this behaviour. But more
recent versions no longer send it. Probably a small (harmless) bug that
was fixed.
2020-01-06 21:29:24 +01:00
Jef Driesen
4b2156d378 Fix a bug in the ACK/NAK handling
The write command is send as two separate packets. The first packet
contains the B2 command and the page number, and the second packet
contains the payload and checksum. Because the payload can contain
arbitrary data, the first byte of a packet is not necessary a command
byte. But the code to select the correct ack byte is based on this
assumption. Fixed by passing the expected ack byte.
2020-01-06 21:29:24 +01:00
Jef Driesen
91309a3d54 Remove an unnecessary function 2020-01-06 21:29:24 +01:00
Jef Driesen
c205299c02 Re-implement the set_latency function as an ioctl
The set_latency function is the perfect example of a feature that should
be implemented as an ioctl: it's only implemented by a single driver,
and the functionality is also highly platform specific.
2020-01-06 21:24:58 +01:00
Jef Driesen
0359a57fdc Add an ioctl function to the I/O interface
This new ioctl function allows to perform I/O stream specific requests
through a generic interface. This provides an easy way to extend the I/O
interface with some driver specific features, without having to modify
the public api.
2020-01-06 21:21:50 +01:00
Jef Driesen
af5716d685 Integrate the new poll function
Replace the manual polling, implemented using a combination of the
dc_iostream_get_available and dc_iostream_sleep functions, with the new
and more efficient poll function.
2020-01-06 13:44:07 +01:00
Jef Driesen
f6fa2b84bc Add a poll function to the I/O interface
The Linux implementation is very straighforward and just a lightweight
wrapper around the select function. But the Windows implementation is
much more complex, because the Windows event notification mechanism
behaves very different:

The WaitCommEvent function does not support a timeout and is always a
blocking call. The only way to implement a timeout is to use
asynchronous I/O (or overlapped I/O as it's called in the Windows API),
to run the operation in the background. This requires some additional
book keeping to keep track of the pending background operation.

The event mechanism is also edge triggered instead of level triggered,
and reading the event with the WaitCommEvent function clears the pending
event. Therefore, the state of the input buffer needs to be checked with
the ClearCommError function before and after the WaitCommEvent call.

The check before is necessary in case the event is already cleared by a
previous WaitCommEvent call, while there is still data present in the
input buffer. In this case, WaitCommEvent should not be called at all,
because it would wait until more data arrives.

The check afterwards is necessary in case WaitCommEvent reports a
pending event, while the data in the input buffer has already been
consumed. In this case, the current event must be ignored and
WaitCommEvent needs to be called again, to wait for the next event.
2020-01-06 13:44:07 +01:00
Jef Driesen
ef4bd94717 Add support for the Oceanic Veo 4.0 2020-01-06 13:33:33 +01:00
Jef Driesen
018198dc17 Increase the timeout to 3 seconds
The BLE communication is significant slower than usb-serial. The first
BLE data packet of each response often takes longer than one second to
arrive. This causes the first attempt to fail with a timeout. The second
attempt will appear to succeed, because it actually receives the
response of the first attempt. But now the next command will fail,
because it will receive the response of the second attempt of the
previous command.

Increasing the timeout and adding an extra delay before retrying, avoids
this problem.

Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
2019-12-28 10:30:37 +01:00
Jef Driesen
02ae8d3fdb Fix the Aeris Manta memory layout
For the Aeris Manta, the end of the profile ringbuffer appears to depend
on the firmware version. For older firmware versions (1x), the end of
the ringbuffer is at address 0xFFF0, while for the newer versions (2x),
it's 0xFE00.

The code checks for firmware version 2B, because that's the lowest known
version in the 2x range.

Reported-by: Nick Shore <support@mac-dive.com>
2019-12-23 21:57:05 +01:00
Jef Driesen
9f3e0a7026 Add support for the Oceanic Pro Plus 4 2019-12-23 21:56:36 +01:00
Nick Shore
03c8e350dd Fix the Oceanic Geo 4.0 memory layout 2019-12-20 11:04:52 +01:00
Jef Driesen
ae733fd8a8 Ignore all empty logbook entries
The logbook ringbuffer is always updated sequentially. Therefore, emtpy
entries can only be present after the oldest dive. However it appears
that under some special conditions (for example an empty battery during
the dive), the logbook entry is not always stored correctly, which can
result in an empty entry after all.

I suspect that at the start of each dive, the OSTC erases the next
available entry in the logbook ringbuffer and updates the internal write
pointer. Once the dive is finished, the actual content of the erased
logbook is written. Thus, when the OSTC runs out of battery power during
the dive, that last step never happens, and the erased entry remains in
place.

As a workaround, ignore all empty logbook entries instead of assuming we
reached the last dive.
2019-11-29 10:29:43 +01:00
Jef Driesen
b9a3606f37 Add a workaround for the hwOS ppO2 firmware bug
Due to a bug in the hwOS Tech firmware v3.03 to v3.07, and the hwOS
Sport firmware v10.57 to v10.63, the ppO2 divisor is sometimes not
correctly reset to zero when no ppO2 samples are being recorded.

Usually this condition can be detected by the fact that the length of
the extended sample will not have enough space left for the ppO2 sample
(9 bytes). As a workaround, reset the divisor back to zero to manually
disable the ppO2 samples.

In theory this detection method is not 100% reliable. There can still be
other sample types present in the extended sample. If their total size
is larger than 9 bytes, the bug will not be detected at all. Instead,
those bytes will get interpreted as the ppO2 sample, resulting in bogus
ppO2 values. Additionally, one of the other sample types will now run
out of space and cause the parsing to fail with an error. However, in
practice this risk is relative low. Most of the other samples are
relative small (1 or 2 bytes), so you would need many of them. That's
rather unlikely in most configurations. The only exception is the large
deco plan sample (15 bytes).
2019-11-22 22:59:25 +01:00
Jef Driesen
a5ba2f4e41 Use macros to encode the firmware version 2019-11-21 11:07:55 +01:00
Jef Driesen
612011249d Use symbolic constants for the sample types 2019-11-21 11:07:07 +01:00