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.
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>
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>
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.
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.
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.
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>
It's exactly the same as the regular i200, but has a new version number
and string.
Tested-by: Tiago Thedim Dias <tiagotsoc@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
It appears that the Aqualung i770R looks almost the same as the Pro Plus
X, but has an additional pO2 field for each gas by the O2 field, which
impacts the offset calculations.
The RTS signal needs to be low before it is raised, and not just set.
This ensures that the PIC inside the Pelagic PC interface is reset and
the initialization sequence always starts cleanly, regardless of the
previous state of the signal.
Reported-By: Bill Perry <bperrybap@opensource.billsworld.billandterrie.com>
The Oceanic Pro Plus X is quite different from the previous models. The
profile data is now stored in a dedicated memory area, and hence there
are a few important differences:
Reading data from the new profile memory area is done with a new F6
command. This new command is very similar to the existing B8 command,
but accesses a completely different memory area. In order to integrate
those two memory areas as transparantly as possible into the existing
infrastructure, a virtual memory space is introduced. The lower part of
the virtual memory is mapped onto the main memory area, while the upper
part is mapped onto the new profile memory area.
The page size of the new profile memory area also increased from 16 to
256 bytes. If the profile size is not an exact multiple of 256 bytes,
the dive computer pads the profile data with 0xFF bytes.
The other changes are the usual Oceanic device specific changes.
Currently the dive computer backends are responsible for opening (and
closing) the underlying I/O stream internally. The consequence is that
each backend is hardwired to a specific transport type (e.g. serial,
irda or usbhid). In order to remove this dependency and support more
than one transport type in the same backend, the opening (and closing)
of the I/O stream is moved to the application.
The dc_device_open() function is modified to accept a pointer to the I/O
stream, instead of a string with the device node (which only makes sense
for serial communication). The dive computer backends only depend on the
common I/O interface.
Being able to synchronize the dive computer clock with the host system
is a very useful feature. Add the infrastructure to support this feature
through the public api.
The second variant of the open or create functions were introduced to
maintain backwards compatibility. But after being removed from the
public api, these functions serve no purpose anymore, and can be removed
completely.
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.
Select the default memory layout for unsupported devices based on the
amount of memory indicated in the version string. This allows to
download a full memory dump.
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 low level serial and IrDA functions are modified to:
- Use the libdivecomputer namespace prefix.
- Return a more detailed status code instead of the zero on success and
negative on error return value. This will allow to return more
fine-grained error codes.
- The read and write functions have an additional output parameter to
return the actual number of bytes transferred. Since these functions
are not atomic, some data might still be transferred successfully if
an error occurs.
The dive computer backends are updated to use the new api.