To enable grouping by trip in the statistics module, split
the get_trip_title() function in a version that appends
a "(n dive(s)" string an one that doesn't. The statistics
module doesn't want that added string, since it displays
the number of dives in a different way.
Also, move the functions to string-format.h, where these
are collected. And rename them to camelCase. Yes, it's
ugly, but consistent with most other C++ code in the code
base.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
When adding a cylinder, it was added at the end of the list.
This would make hidden cylinders visible as the new rule is
to only hide unused cylinders at the end of the list.
Therefore, add the cylinder after the last used cylinder,
i.e. before the first hidden cylinder.
This means that the position where the cylinder is added has
to be hidden in the undo command.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The D in MOD, EAD, END, and EADD stands for "depth" and
as such these should be mm in int rather than double.
The intermediate fn2 and fhe2, however, as intermediate
value should not be rounded to an integer.
The upshot of this is a litle more numerical stability.
It should lead to more stable values in TestProfile
when run on architectures with different floating
point precision.
Signed-off-by: Robert C. Helling <helling@atdotde.de>
CCRs are different. It does not make sense to compute
a depth dependent SAC. You could compute the rate of O2
consumption but even that is likely wrong (as O2 in the
diluent would enter that as well), so simply don't attempt
it.
Signed-off-by: Robert C. Helling <helling@atdotde.de>
And while doing that, have all the cases where we already include
qthelper.h simply use a define in that header file - but keep the two
other instances of the define where the C++ source don't need qthelper.h
otherwise.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Very similar structure to the XML format. Raw data is again saved as a
hex string (which implicitly provides us with its length). The rest of
components are in a more human readable format.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
We always use the global fingerprint table - maybe this should just not
be a parameter of the accessor functions?
The syntax is very simple - the raw data is encoded as a hex string, the
rest of the components are hex numbers.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
In order to not break existing behavior, we still store fingerprints on disk, but
we first check the data in the in-memory table, and we remember the fingerprint data
in the fingerprint table as well (which is then saved as part of the dive log data).
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This just adds the basic structures and the accessor functions needed to
manage a table of fingerprint data. The table is indexed by the hash of
the model name and binary serial number as created by libdivcecomputer.
This way the data is accessible when libdivecomputer fist accesses a
dive computer (which is the point in time when we need to use the
fingerprint.
The table also contains the corresponding device id and dive id so we
can verify that the current dive table still contains that dive.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
In both places in the UI where we show the date of a dive during
download we are actually pressed for space. So let's use the short
version of the date string to save some space.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Most divecomputers download data dive by dive - so we get reasonably
frequent updates during the download (as new dives are found and posted
in the progress text area). But some (like the G2) download all of the
new dives at once and only then start parsing them. As a result the
download can look like it is hung.
As a compromise this shows updates on the data received in 10kB
increments. Which for most cases should never be shown and therefore not
make the user experience any worse - but for cases like the G2 will make
a huge difference.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Qt 6 will drop support for QRegExp.
Use QRegularExpression instead.
Much of this is a simple replacement of one class with the other, but
there are some changes to the way matches are tracked and captures are
created. Also, the exactMatch now needs to be implemented via anchors in
the regular expression itself.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Qt 6 will drop support for QRegExp.
Use QRegularExpression instead.
This is a straight forward replacement without any other code changes.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Fix a pair of warnings, which annoyed me for a long time:
For some reasons prefs.bottompo2 is an integer (mbar)
whereas prefs.modpO2 is a float (bar). This results
in mixed integer/floating point arithmetics when
conditionally using either of them. And ultimately
a warning, when storing a mbar value as an integer.
Fix this by an explicit cast to int after converting
modpO2 to mbar.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Air is a special gas that does not contain oxygen according
to gasmix.o2.fraction. If you want to use the fo2, you
need to use get_o2() to treat this special case correctly.
This fixes a bug when setting the MND of a gas containing
21% oxygen when o2 is considered not narcotic.
Reported-by: Christoph Gruen <gruen.christoph@gmail.com>
Signed-off-by: Robert C. Helling <helling@atdotde.de>
When we found an invalid sensor (referring to a non
existing cylinder) in fixup_dive() the sensor-id was
set to NO_SENSOR.
This led to invalid XML files, because the code decides
to switch into legacy mode. However, there are two
pressure readings, which is invalid in legacy mode.
Therefore, also clear the pressure data.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This tries to make our fingerprinting code work better, by avoiding
using the "deviceid" field that has always been unreliable because we've
calculated it multiple different ways, and even for the same version of
subsurface, it ends up changing in the middle (ie we calculate one value
initially, then re-calculate it when we have a proper serial number
string).
So instead, the fingerprinting code will look up and save the
fingerprint file using purely "stable" information that is available
early during the download:
- the device model name (which is a string with vendor and product name
separated by a space)
- the DC_EVENT_DEVINFO 32-bit 'serial' number (which is not necessarily
a real serial number at all, but hopefully at least a unique number
for the particular product)
but because the model name is not necessarily a good filename (think
slashes and other possibly invalid characters), we hash that model name
and use the resulting hex number in the fingerprint file name.
This way the fingerprint file is unambiguous at load and save time, and
depends purely on libdivecomputer data.
But because we also need to verify that we have the actual _dive_
associated with that fingerprint, we also need to save the final
deviceid and diveid when saving the fingerprint file, so that when we
load it again we can look up the dive and verify that we have it before
we use the fingerprint data.
To do that, the fingerprint file itself contains not just the
fingerprint data from libdivecomputer, but the last 8 bytes of the file
are the (subsurface) deviceid and the diveid of the dive that is
associated with the fingerprint.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Only used in context of acquiring GPS locations with the mobile app, which
we no longer do.
Keep the DiveAndLocation structure around as that's needed by the
ApplyGpsFixes command.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
In commit 4724c88 get_plot_details_new was updated to pass an index
instead of the entry into plot_string. This means we are passing "i" to
plot_string after the final increment of the for loop, instead of
getting the entry[i] within the loop before the final increment. This
means if we are mousing over the far right of the graph, where the time
based break is not hit, we will end up passing an index equal to nr-2
instead of nr-3, which is intended to shave off the final two rows
containing data not useful to the display.
There are a handful of ways to fix this. This commit intends to be
consistent with stylistic choices made elsewhere in the project.
Signed-off-by: Josh Torres <torres.josh.j@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
We want to prevent the user from accidentally deleting a
cylinder with sensor readings. Therefore, we need such a
function.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Due to changes in the handling of sensor-ids, invalid XMLs were
generated. In particular, these contained duplicate attributes
in the sample tags.
Even though these files shouldn't exist, let's try to parse
them anyway. Some data will be lost, but that's better than
not opening the file.
libxml2 can be told to try to recover from such petty(?) errors
by passing the XML_PARSE_RECOVER flag.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
For dives with mixed divemode, one needs to check sample.setpoint
to figure out if the segment is an OC segment and the po2 needs
to be computed from the gasmix and ambient pressure.
This fixes#3310
Signed-off-by: Robert C. Helling <helling@atdotde.de>
We no longer need the remove infrastructure, and the edit nickname function
becomes much more intuitive to use by passing in the dive computer for
which we want to create a nickname instead of the internal index into
the array of devices.
This also removes / simplifies the device list update signals in the
DiveListNotifier.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This makes it much easier to manipulate dc nickname entries. In order
for that to work we can't simply remove entries with empty nickname (but
that isn't needed, anyway, as the code that saves XML or git already
handles that case correctly).
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
... it just causes problems later when we free them, since we don't do
any reference counting.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
When we save the divecomputer data, we never actually save the serial
value as a field. We used to rely on saving the very dodgy 'deviceid',
and then look up the serial number from there. And that never really
worked reliably, but we didn't really notice, because we never really
_used_ the serial number anywhere.
The only place the serial number is actually reliably displayed is in
the "Extra data" tab, which contains the key value pairs, and that's
where the original dive download code got the serial number from.
So just parse that at load time too, the same way we parsed it at dive
download time.
In fact, do the firmware version the same way, and remove the code from
the downloader, since it too can rely on 'add_extra_data()' just picking
up the information directly.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
We have this odd legacy notion of a divecomputer 'device', that was
originally just basically the libdivecomputer 'EVENT_DEVINFO' report
that was associated with each dive. So it had firmware version,
deviceid, and serial number.
It had also gotten extended to do 'nickname' handling, and it was all
confusing, ugly and bad. It was particularly bad because it wasn't
actually a 'per device' thing at all: due to the firmware field, a dive
computer that got a firmware update forced a new 'device'.
To make matters worse, the 'deviceid' was also almost random, because
we've calculated it a couple of different ways, and libdivecomputer
itself has changed how the legacy 32-bit 'serial number' is expressed.
Finally, because of all these issues, we didn't even try to make the
thing unique, so it really ended up being a random snapshot of the state
of the dive computer at the time of a dive, and sometimes we'd pick one,
and sometimes another, since they weren't really well-defined.
So get rid of all this confusion.
The new rules:
- the actual random dive computer state at the time of a dive is kept
in the dive data. So if you want to know the firmware version, it
should be in the 'extra data'
- the only serial number that matters is the string one in the extra
data, because that's the one that actually matches what the dive
computer reports, and isn't some random 32-bit integer with ambiguous
formatting.
- the 'device id' - the thing we match with (together with the model
name, eg "Suunto EON Steel") is purely a hash of the real serial
number.
The device ID that libdivecomputer reports in EVENT_DEVINFO is
ignored, as is the device ID we've saved in the XML or git files. If
we have a serial number, the device ID will be uniquely associated
with that serial number, and if we don't have one, the device ID will
be zero (for 'match anything').
So now 'deviceid' is literally just a shorthand for the serial number
string, and the two are joined at the hip.
- the 'device' managament is _only_ used to track devices that have
serial numbers _and_ nicknames. So no more different device
structures just because one had a nickname and the other didn't etc.
Without a serial number, the device is 'anonymous' and fundamentally
cannot be distinguished from other devices of the same model, so a
nickname is meaningless. And without a nickname, there is no point in
creating a device data structure, since all the data is in the dive
itself and the device structure wouldn't add any value..
These rules mean that we no longer have ambiguous 'device' structures,
and we can never have duplicates that can confuse us.
This does mean that you can't give a nickname to a device that cannot be
uniquely identified with a serial number, but those are happily fairly
rare (and mostly older ones). Dirk said he'd look at what it takes to
give more dive computers proper serial numbers, and I already did it for
the Garmin Descent family yesterday.
(Honesty in advertizing: right now you can't add a nickname to a dive
computer that doesn't already have one, because such a dive computer
will not have a device structure. But that's a UI issue, and I'll sort
that out separately)
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
If we download a first dive computer and add a dive site to the dive (by
setting a location name for example), and then download from another
dive computer that provides us with GPS data, we should keep the
existing dive site information, but add the GPS data from the freshly
downloaded dive computer.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This adds a cleanup function to be called after a divelogs.de upload
finishes (successful or not) to make sure the temporary zip file is
closed and removed.
Signed-off-by: Richard Fuchs <dfx@dfx.at>
On multi-user systems with a shared directory for temporary files, using
a static file name can lead to permissions problems and subsequent
errors due to collisions. Use a random unique file name for each
generated file to avoid these problems.
Note: the temporary file generated from the divelogs.de upload is still
left behind after the upload finishes.
Signed-off-by: Richard Fuchs <dfx@dfx.at>
The intent of the code was to check that there is a string and it has at least
two characters. Since iter is the result of a strchr(iter, '|') call, we
know that if iter isn't NULL, iter[0] is '|', so we only need to check the next
character.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
try_to_xslt_open_csv() re-allocates the memory passed in (not really great as
far as design goes, maybe something that should be reimplemented). Doing
pointer arithmatic with the returned base pointer results in garbage, unless
one gets super lucky and the realloc manages to not move the memory.
It's a wonder this ever worked.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Before making the cylinder-table dynamic, dives always
had at least one cylinger. When such a dive is displayed,
the TabDiveInformation class calls per_cylinder_mean_depth().
If there are no samples, this function generates a "fake
profile" with fake_dc(). Thus, effectively dives always
had samples once the user was displaying them.
When the cylinder-table was made dynamic, dives without
cylinders were supported. This can notably happen, when
importing from CSV (this could actually be a bug).
per_cylinder_mean_depth() exits early in that case and
doesn't create a fake profile. This lead to crashes
of the profile-widget, which were fixed in 6b2e56e513.
Non-sample dives were now shown with the Subsurface-logo.
To restore the previous behavior, genarate a fake profile
for sample-less dives in fixup_dive(), which is called
anytime a dive is loaded or imported. This seems to
have been the intention anyway and this worked only
"by chance". This will make a few fake_dc() calls obsolete,
but so be it.
Since fake profiles are now generated on loading,
the parse-tests need to be fixed to account for that.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
When merging two dives, the higher CNS value was taken. This could
result in inconsistent CNS values if two dives were merged where
one dive's CNS was calculated from a "fake profile", i.e. a dive
without dive-computer profile. In that case, the most conservative
value (all time spent at the bottom) was assumed. The merged dive
then consisted of the dive-computer profile and the conservative
CNS estimate.
This is fixed by setting the CNS value to "0" after merging,
which means "unknown". The correct value will then be recalculated
in "fixup_dive" from the actual sample data.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The data of the membuffer is passed as a data/length pair
to xmlReadMemory(). There is no point in NUL-terminating it.
Moreover, pass the data directly to xmlReadMemory()
instead of via variables. These variables are reused
later with a different meaning, making this super-confusing.
The membuf variable is turned from "const char *" to "char *"
to signal that we own the buffer.
Amazingly, zip_source_buffer() frees the buffer, even though
a "const void *" is passed in. This API is pure madness. Add
a comment.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Thus, the membuffer data is automatically freed when going
out of scope - one thing less to worry about.
This fixes one use-after-free bug in uploadDiveLogsDE.cpp
and one extremely questionable practice in divetooltipitem.cpp:
The membuffer was a shared instance across all instances
of the DiveToolTipItem.
Remves unnecessary #include directives in files that didn't
even use membuffer.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
C-style memory management is a pain and nearly nobody seems to get
it right. Add a C++-version of membuffer that frees the buffer
when it gets out-of-scope. Originally, I was thinking about
conditionally adding a constructor/destructor pair when compiling
with C++. But then decided to create a derived class membufferpp,
because it would be extremely confusing to have behavioral change
when changing a source from from C to C++ or vice-versa.
Also add a comment about the dangers of returned pointer: They
become dangling on changes to the membuffer.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The sensor-id in the sample struct was a uint8_t, with all
the known problems of unsigned integers. In the rest of the
code cylinder ids are signed integers. To avoid confusion,
make it a signed int. int8_t should be enough (max. 127
cylinders). To allow for degenerate cases, use an int16_t.
16k cylinders should be enough for everyone.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The code will happily perform out-of-bound accesses if
pressure-sensors refer to non-existing cylinders. Therefore,
sanitize these values in fixup_dive(), which is called
everytime a dive is loaded or imported.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>