When downloading from a dive computer, stop at mergeable dives
Jef Driesen
jefdriesen at telenet.be
Fri Nov 23 22:52:13 PST 2012
On 2012-11-21 18:09, Dirk Hohndel wrote:
> On Wed, 2012-11-21 at 17:56 +0100, Jef Driesen wrote:
>> On 2012-11-20 02:31, Linus Torvalds wrote:
>> > We do want to have some way of saying "force download of all dives
>> > from today" or something like that, I suspect. Because while I
>> don't
>> > want to re-download *every* dive, I might want to force-merge the
>> > last
>> > <N> dives.
>>
>> Have you considered using the libdivecomputer fingerprint feature
>> for
>> this purpose? It has been explicitly designed for this scenario. It
>> supports multiple devices out-of-the box, without needing any sort
>> of
>> heuristics like matching start times. It will also give you the
>> shortest
>> possible download times, something which is not always possible to
>> achieve with a custom implementation.
>>
>> Anyway, if you want to play with this feature, have a look at the
>> "-c"
>> option of the universal application. In a multi device scenario, you
>> download both devices with the command:
>>
>> ./universal -c <cachedir> -d <xmlfile> -b <backend> <devname>
>>
>> The fingerprint of the most recent dive will get stored in the
>> cachedir. When you run the same command again, it will load this
>> fingerprint again and only download the new dives (if any of
>> course).
>> Because the universal app uses a different fingerprint file per
>> device
>> (based on the device serial number), you get multi device support
>> for
>> free.
>
> How do we use this via the API? As you know, Subsurface doesn't run
> the
> universal app to download dives, it is linked against libdivecomputer
> and uses that API...
Of course it's also available through the api! I referred to the
universal application because it's already implemented there, so you
could give it a try before implementing anything yourself.
It's very simple. The first step is to register a callback function for
DC_EVENT_DEVINFO. When you receive this event, you look-up in your
fingerprint "database" whether you have a fingerprint for that device.
If you do, call the dc_device_set_fingerprint function, and then you're
done. You'll automatically only get those dives that are newer than the
dive corresponding to that fingerprint. The second step is updating the
fingerprint database. When the download has finished successfully, you
store the fingerprint of the most recent dive into your "database". Keep
in mind that because libdivecomputer always returns the dives in reverse
order, the most recent dive is always the first dive you get!
If the download fails, then you should not update the fingerprint
database, or you may not be able to download some dives again. This is
due to downloading in the reverse order. Let's illustrate with an
example. Assume you have 6 dives, where D6 is the oldest, and D1 is the
most recent:
D6 D5 D4 D3 D2 D1
Let's assume you have already download D6 to D4. According the logic
above, the current fingerprint belongs to dive D4. When trying to
download the remaining dives, you'll get dive D1, then D2 and finally
D3. Suppose there is an error downloading D2. Then you'll get the most
recent dive D1 successfully, but not the other two. So if you update
your fingerprint database with D1, then from then on you'll never be
able to get D3 and D2 again. Because due to the fingerprint the download
will already stop at D1.
In case of a failure, you should not update the fingerprint, and then
the user has an opportunity to try again. You may get some duplicates
(e.g. D1 in my example scenario), but never the older dives (D6 to D4).
The duplication detection is something that will have to be done on the
application side. You can still use the fingerprints for this of course,
but then you'll need more than just the fingerprint of the most recent
dive.
Note that the fingerprint look-up should take into account the device
family type and serial number, to be able to uniquely identify each
individual device. For example if you have an ostc and a vyper, then the
family type is already sufficient. But if you have two devices from the
same family (e.g. two vypers, or a vyper and a gekko), then you'll need
the serial number too.
The fingerprint is usually the raw date/time data of each dive, but
that's not guaranteed (there are already backends where it's something
different). Applications should just consider it as an opaque piece of
binary data. This is in fact one of the reasons why relying on the
fingerprints is superior to using some parsed fields like the date/time
value. Fingerprints can't be altered by the application, and thus the
logic will always work, even after significant modifications by the
user.
Jef
More information about the subsurface
mailing list