core: turn divecomputer list into std::vector<>

Since struct divecomputer is now fully C++ (i.e. cleans up
after itself), we can simply turn the list of divecomputers
into an std::vector<>. This makes the code quite a bit simpler,
because the first divecomputer was actually a subobject.

Yes, this makes the common case of a single divecomputer a
little bit less efficient, but it really shouldn't matter.
If it does, we can still write a special std::vector<>-
like container that keeps the first element inline.

This change makes pointers-to-divecomputers not stable.
So always access the divecomputer via its index. As
far as I can tell, most of the code already does this.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2024-05-27 17:09:48 +02:00 committed by bstoeger
parent e237f29fb2
commit 284582d2e8
54 changed files with 738 additions and 893 deletions

View file

@ -10,7 +10,7 @@ ColumnLimit: 0
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
ForEachMacros: [ 'for_each_dc', 'for_each_relevant_dc', 'for_each_dive', 'for_each_line' ]
ForEachMacros: [ 'for_each_dive', 'for_each_line' ]
IndentFunctionDeclarationAfterType: false #personal taste, good for long methods
IndentWidth: 8
MaxEmptyLinesToKeep: 2

View file

@ -179,7 +179,7 @@ void export_TeX(const char *filename, bool selected_only, bool plain, ExportCall
put_format(&buf, "\\def\\%ssitename{%s}\n", ssrf, site ? site->name.c_str() : "");
site ? put_format(&buf, "\\def\\%sgpslat{%f}\n", ssrf, site->location.lat.udeg / 1000000.0) : put_format(&buf, "\\def\\%sgpslat{}\n", ssrf);
site ? put_format(&buf, "\\def\\%sgpslon{%f}\n", ssrf, site->location.lon.udeg / 1000000.0) : put_format(&buf, "\\def\\gpslon{}\n");
put_format(&buf, "\\def\\%scomputer{%s}\n", ssrf, dive->dc.model.c_str());
put_format(&buf, "\\def\\%scomputer{%s}\n", ssrf, dive->dcs[0].model.c_str());
put_format(&buf, "\\def\\%scountry{%s}\n", ssrf, country.c_str());
put_format(&buf, "\\def\\%stime{%u:%02u}\n", ssrf, FRACTION_TUPLE(dive->duration.seconds, 60));
@ -287,7 +287,7 @@ void export_depths(const char *filename, bool selected_only)
FOR_EACH_PICTURE (dive) {
depth_t depth;
for (auto &s: dive->dc.samples) {
for (auto &s: dive->dcs[0].samples) {
if ((int32_t)s.time.seconds > picture->offset.seconds)
break;
depth = s.depth;

View file

@ -404,7 +404,7 @@ AddDive::AddDive(dive *d, bool autogroup, bool newNumber)
setText(Command::Base::tr("add dive"));
// By convention, d is a pointer to "displayed dive" or a temporary variable and can be overwritten.
d->maxdepth.mm = 0;
d->dc.maxdepth.mm = 0;
d->dcs[0].maxdepth.mm = 0;
fixup_dive(d);
// this only matters if undoit were called before redoit
@ -883,7 +883,7 @@ static std::array<dive *, 2> splitDiveComputer(const dive *d, int dc_num)
{
// Refuse to do anything if the dive has only one dive computer.
// Yes, this should have been checked by the UI, but let's just make sure.
if (!d->dc.next)
if (d->dcs.size() <= 1)
return { nullptr, nullptr};
dive *new1, *new2;

View file

@ -306,11 +306,11 @@ QString EditAtmPress::fieldName() const
// ***** Duration *****
void EditDuration::set(struct dive *d, int value) const
{
d->dc.duration.seconds = value;
d->duration = d->dc.duration;
d->dc.meandepth.mm = 0;
d->dc.samples.clear();
fake_dc(&d->dc);
d->dcs[0].duration.seconds = value;
d->duration = d->dcs[0].duration;
d->dcs[0].meandepth.mm = 0;
d->dcs[0].samples.clear();
fake_dc(&d->dcs[0]);
}
int EditDuration::data(struct dive *d) const
@ -326,11 +326,11 @@ QString EditDuration::fieldName() const
// ***** Depth *****
void EditDepth::set(struct dive *d, int value) const
{
d->dc.maxdepth.mm = value;
d->maxdepth = d->dc.maxdepth;
d->dc.meandepth.mm = 0;
d->dc.samples.clear();
fake_dc(&d->dc);
d->dcs[0].maxdepth.mm = value;
d->maxdepth = d->dcs[0].maxdepth;
d->dcs[0].meandepth.mm = 0;
d->dcs[0].samples.clear();
fake_dc(&d->dcs[0]);
}
int EditDepth::data(struct dive *d) const
@ -808,7 +808,7 @@ ReplanDive::ReplanDive(dive *source) : d(current_dive),
return;
// Fix source. Things might be inconsistent after modifying the profile.
source->maxdepth.mm = source->dc.maxdepth.mm = 0;
source->maxdepth.mm = source->dcs[0].maxdepth.mm = 0;
fixup_dive(source);
when = source->when;
@ -821,7 +821,7 @@ ReplanDive::ReplanDive(dive *source) : d(current_dive),
// This resets the dive computers and cylinders of the source dive, avoiding deep copies.
std::swap(source->cylinders, cylinders);
std::swap(source->dc, dc);
std::swap(source->dcs[0], dc);
setText(Command::Base::tr("Replan dive"));
}
@ -829,7 +829,6 @@ ReplanDive::ReplanDive(dive *source) : d(current_dive),
ReplanDive::~ReplanDive()
{
clear_cylinder_table(&cylinders);
free_dive_dcs(&dc);
free(notes);
}
@ -844,7 +843,7 @@ void ReplanDive::undo()
std::swap(d->maxdepth, maxdepth);
std::swap(d->meandepth, meandepth);
std::swap(d->cylinders, cylinders);
std::swap(d->dc, dc);
std::swap(d->dcs[0], dc);
std::swap(d->notes, notes);
std::swap(d->surface_pressure, surface_pressure);
std::swap(d->duration, duration);
@ -887,7 +886,7 @@ EditProfile::EditProfile(const dive *source, int dcNr, EditProfileType type, int
dcmaxdepth({0}),
duration({0})
{
const struct divecomputer *sdc = get_dive_dc_const(source, dcNr);
const struct divecomputer *sdc = get_dive_dc(source, dcNr);
if (!sdc)
d = nullptr; // Signal that we refuse to do anything.
if (!d)
@ -906,7 +905,6 @@ EditProfile::EditProfile(const dive *source, int dcNr, EditProfileType type, int
EditProfile::~EditProfile()
{
free_dive_dcs(&dc);
}
bool EditProfile::workToBeDone()
@ -1423,7 +1421,7 @@ EditDive::EditDive(dive *oldDiveIn, dive *newDiveIn, dive_site *createDs, dive_s
changedFields |= DiveField::SUIT;
if (taglist_get_tagstring(oldDive->tag_list) != taglist_get_tagstring(newDive->tag_list)) // This is cheating. Do we have a taglist comparison function?
changedFields |= DiveField::TAGS;
if (oldDive->dc.divemode != newDive->dc.divemode)
if (oldDive->dcs[0].divemode != newDive->dcs[0].divemode)
changedFields |= DiveField::MODE;
if (!same_string(oldDive->notes, newDive->notes))
changedFields |= DiveField::NOTES;

View file

@ -444,7 +444,7 @@ static void cochran_parse_samples(struct dive *dive, const unsigned char *log,
unsigned int ndl = 0;
unsigned int in_deco = 0, deco_ceiling = 0, deco_time = 0;
struct divecomputer *dc = &dive->dc;
struct divecomputer *dc = &dive->dcs[0];
struct sample *sample;
// Initialize stat variables
@ -664,7 +664,7 @@ static void cochran_parse_dive(const unsigned char *decode, unsigned mod,
#endif
auto dive = std::make_unique<struct dive>();
dc = &dive->dc;
dc = &dive->dcs[0];
unsigned char *log = (buf + 0x4914);

View file

@ -191,7 +191,7 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
* Next, Time in minutes since 00:00
*/
read_bytes(2);
dt_dive->dc.when = dt_dive->when = (timestamp_t)date_time_to_ssrfc(tmp_4bytes, tmp_2bytes);
dt_dive->dcs[0].when = dt_dive->when = (timestamp_t)date_time_to_ssrfc(tmp_4bytes, tmp_2bytes);
/*
* Now, Locality, 1st byte is long of string, rest is string
@ -239,19 +239,19 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
read_bytes(1);
switch (tmp_1byte) {
case 1:
dt_dive->dc.surface_pressure.mbar = 1013;
dt_dive->dcs[0].surface_pressure.mbar = 1013;
break;
case 2:
dt_dive->dc.surface_pressure.mbar = 932;
dt_dive->dcs[0].surface_pressure.mbar = 932;
break;
case 3:
dt_dive->dc.surface_pressure.mbar = 828;
dt_dive->dcs[0].surface_pressure.mbar = 828;
break;
case 4:
dt_dive->dc.surface_pressure.mbar = 735;
dt_dive->dcs[0].surface_pressure.mbar = 735;
break;
default:
dt_dive->dc.surface_pressure.mbar = 1013;
dt_dive->dcs[0].surface_pressure.mbar = 1013;
}
/*
@ -259,7 +259,7 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
*/
read_bytes(2);
if (tmp_2bytes != 0x7FFF)
dt_dive->dc.surfacetime.seconds = (uint32_t) tmp_2bytes * 60;
dt_dive->dcs[0].surfacetime.seconds = (uint32_t) tmp_2bytes * 60;
/*
* Weather, values table, 0 to 6
@ -296,7 +296,7 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
*/
read_bytes(2);
if (tmp_2bytes != 0x7FFF)
dt_dive->dc.airtemp.mkelvin = C_to_mkelvin((double)(tmp_2bytes / 100));
dt_dive->dcs[0].airtemp.mkelvin = C_to_mkelvin((double)(tmp_2bytes / 100));
/*
* Dive suit, values table, 0 to 6
@ -349,14 +349,14 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
*/
read_bytes(2);
if (tmp_2bytes != 0x7FFF)
dt_dive->maxdepth.mm = dt_dive->dc.maxdepth.mm = (int32_t)tmp_2bytes * 10;
dt_dive->maxdepth.mm = dt_dive->dcs[0].maxdepth.mm = (int32_t)tmp_2bytes * 10;
/*
* Dive time in minutes.
*/
read_bytes(2);
if (tmp_2bytes != 0x7FFF)
dt_dive->duration.seconds = dt_dive->dc.duration.seconds = (uint32_t)tmp_2bytes * 60;
dt_dive->duration.seconds = dt_dive->dcs[0].duration.seconds = (uint32_t)tmp_2bytes * 60;
/*
* Minimum water temperature in C*100. If unknown, set it to 0K which
@ -364,7 +364,7 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
*/
read_bytes(2);
if (tmp_2bytes != 0x7fff)
dt_dive->watertemp.mkelvin = dt_dive->dc.watertemp.mkelvin = C_to_mkelvin((double)(tmp_2bytes / 100));
dt_dive->watertemp.mkelvin = dt_dive->dcs[0].watertemp.mkelvin = C_to_mkelvin((double)(tmp_2bytes / 100));
else
dt_dive->watertemp.mkelvin = 0;
@ -404,7 +404,7 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
if (bit_set(tmp_1byte, 1)) {
taglist_add_tag(&dt_dive->tag_list, strdup("rebreather"));
is_SCR = 1;
dt_dive->dc.divemode = PSCR;
dt_dive->dcs[0].divemode = PSCR;
}
/*
@ -519,7 +519,7 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
libdc_model = dtrak_prepare_data(tmp_1byte, devdata);
if (!libdc_model)
report_error(translate("gettextFromC", "[Warning] Manual dive # %d\n"), dt_dive->number);
dt_dive->dc.model = copy_string(devdata.model.c_str());
dt_dive->dcs[0].model = copy_string(devdata.model.c_str());
/*
* Air usage, unknown use. Probably allows or deny manually entering gas
@ -561,10 +561,9 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
* Initialize some dive data not supported by Datatrak/WLog
*/
if (!libdc_model)
dt_dive->dc.deviceid = 0;
dt_dive->dcs[0].deviceid = 0;
else
dt_dive->dc.deviceid = 0xffffffff;
dt_dive->dc.next = NULL;
dt_dive->dcs[0].deviceid = 0xffffffff;
if (!is_SCR && dt_dive->cylinders.nr > 0) {
get_cylinder(dt_dive, 0)->end.mbar = get_cylinder(dt_dive, 0)->start.mbar -
((get_cylinder(dt_dive, 0)->gas_used.mliter / get_cylinder(dt_dive, 0)->type.size.mliter) * 1000);

View file

@ -124,9 +124,8 @@ void clear_device_table(struct device_table *device_table)
bool device_used_by_selected_dive(const struct device *dev)
{
for (dive *d: getDiveSelection()) {
struct divecomputer *dc;
for_each_dc (d, dc) {
if (dc->deviceid == dev->deviceId)
for (auto &dc: d->dcs) {
if (dc.deviceid == dev->deviceId)
return true;
}
}

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,7 @@
#include "picture.h" // TODO: remove
#include <string>
#include <vector>
extern int last_xml_version;
@ -22,6 +23,7 @@ struct dive_trip;
struct full_text_cache;
struct event;
struct trip_table;
struct dive {
struct dive_trip *divetrip = nullptr;
timestamp_t when = 0;
@ -45,7 +47,7 @@ struct dive {
int user_salinity = 0; // water density reflecting a user-specified type
struct tag_entry *tag_list = nullptr;
struct divecomputer dc;
std::vector<divecomputer> dcs; // Attn: pointers to divecomputers are not stable!
int id = 0; // unique ID for this dive
struct picture_table pictures = { };
unsigned char git_id[20] = {};
@ -117,8 +119,10 @@ extern std::string get_dive_country(const struct dive *dive);
extern std::string get_dive_location(const struct dive *dive);
extern unsigned int number_of_computers(const struct dive *dive);
extern struct divecomputer *get_dive_dc(struct dive *dive, int nr);
extern const struct divecomputer *get_dive_dc_const(const struct dive *dive, int nr);
extern const struct divecomputer *get_dive_dc(const struct dive *dive, int nr);
extern timestamp_t dive_endtime(const struct dive *dive);
extern temperature_t dc_airtemp(const struct dive *dive);
extern temperature_t dc_watertemp(const struct dive *dive);
extern void set_git_prefs(const char *prefs);
@ -136,12 +140,6 @@ void split_divecomputer(const struct dive *src, int num, struct dive **out1, str
#define for_each_dive(_i, _x) \
for ((_i) = 0; ((_x) = get_dive(_i)) != NULL; (_i)++)
#define for_each_dc(_dive, _dc) \
for (_dc = &_dive->dc; _dc; _dc = _dc->next)
#define for_each_relevant_dc(_dive, _dc) \
for (_dc = &_dive->dc; _dc; _dc = _dc->next) if (!is_logged(_dive) || !is_dc_planner(_dc))
extern struct dive *get_dive_by_uniq_id(int id);
extern int get_idx_by_uniq_id(int id);
extern bool dive_site_has_gps_location(const struct dive_site *ds);

View file

@ -14,6 +14,7 @@
divecomputer::divecomputer() = default;
divecomputer::~divecomputer() = default;
divecomputer::divecomputer(const divecomputer &) = default;
divecomputer::divecomputer(divecomputer &&) = default;
divecomputer &divecomputer::operator=(const divecomputer &) = default;
@ -229,18 +230,6 @@ int get_depth_at_time(const struct divecomputer *dc, unsigned int time)
return depth;
}
static void free_dc(struct divecomputer *dc)
{
delete dc;
}
/* The first divecomputer is embedded in the dive structure. Ignore it.
* For all remainding dcs in the list, free data and structures. */
void free_dive_dcs(struct divecomputer *dc)
{
STRUCTURED_LIST_FREE(struct divecomputer, dc->next, free_dc);
}
struct sample *prepare_sample(struct divecomputer *dc)
{
if (dc) {
@ -274,12 +263,12 @@ void append_sample(const struct sample &sample, struct divecomputer *dc)
*
* This ignores any surface time in the middle of the dive.
*/
void fixup_dc_duration(struct divecomputer *dc)
void fixup_dc_duration(struct divecomputer &dc)
{
int duration = 0;
int lasttime = 0, lastdepth = 0, depthtime = 0;
for (const auto &sample: dc->samples) {
for (const auto &sample: dc.samples) {
int time = sample.time.seconds;
int depth = sample.depth.mm;
@ -292,48 +281,11 @@ void fixup_dc_duration(struct divecomputer *dc)
lasttime = time;
}
if (duration) {
dc->duration.seconds = duration;
dc->meandepth.mm = (depthtime + duration / 2) / duration;
dc.duration.seconds = duration;
dc.meandepth.mm = (depthtime + duration / 2) / duration;
}
}
/*
* What do the dive computers say the water temperature is?
* (not in the samples, but as dc property for dcs that support that)
*/
unsigned int dc_watertemp(const struct divecomputer *dc)
{
int sum = 0, nr = 0;
do {
if (dc->watertemp.mkelvin) {
sum += dc->watertemp.mkelvin;
nr++;
}
} while ((dc = dc->next) != NULL);
if (!nr)
return 0;
return (sum + nr / 2) / nr;
}
/*
* What do the dive computers say the air temperature is?
*/
unsigned int dc_airtemp(const struct divecomputer *dc)
{
int sum = 0, nr = 0;
do {
if (dc->airtemp.mkelvin) {
sum += dc->airtemp.mkelvin;
nr++;
}
} while ((dc = dc->next) != NULL);
if (!nr)
return 0;
return (sum + nr / 2) / nr;
}
static bool operator<(const event &ev1, const event &ev2)
{
if (ev1.time.seconds < ev2.time.seconds)
@ -399,27 +351,27 @@ void add_extra_data(struct divecomputer *dc, const std::string &key, const std::
* positive for "same dive" and negative for "definitely
* not the same dive"
*/
int match_one_dc(const struct divecomputer *a, const struct divecomputer *b)
int match_one_dc(const struct divecomputer &a, const struct divecomputer &b)
{
/* Not same model? Don't know if matching.. */
if (a->model.empty() || b->model.empty())
if (a.model.empty() || b.model.empty())
return 0;
if (strcasecmp(a->model.c_str(), b->model.c_str()))
if (strcasecmp(a.model.c_str(), b.model.c_str()))
return 0;
/* Different device ID's? Don't know */
if (a->deviceid != b->deviceid)
if (a.deviceid != b.deviceid)
return 0;
/* Do we have dive IDs? */
if (!a->diveid || !b->diveid)
if (!a.diveid || !b.diveid)
return 0;
/*
* If they have different dive ID's on the same
* dive computer, that's a definite "same or not"
*/
return a->diveid == b->diveid && a->when == b->when ? 1 : -1;
return a.diveid == b.diveid && a.when == b.when ? 1 : -1;
}
static const char *planner_dc_name = "planned dive";

View file

@ -43,10 +43,10 @@ struct divecomputer {
std::vector<struct sample> samples;
std::vector<struct event> events;
std::vector<struct extra_data> extra_data;
struct divecomputer *next = nullptr;
divecomputer();
~divecomputer();
divecomputer(const divecomputer &);
divecomputer(divecomputer &&);
divecomputer &operator=(const divecomputer &);
};
@ -54,10 +54,9 @@ struct divecomputer {
extern void fake_dc(struct divecomputer *dc);
extern void free_dc_contents(struct divecomputer *dc);
extern int get_depth_at_time(const struct divecomputer *dc, unsigned int time);
extern void free_dive_dcs(struct divecomputer *dc);
extern struct sample *prepare_sample(struct divecomputer *dc);
extern void append_sample(const struct sample &sample, struct divecomputer *dc);
extern void fixup_dc_duration(struct divecomputer *dc);
extern void fixup_dc_duration(struct divecomputer &dc);
extern unsigned int dc_airtemp(const struct divecomputer *dc);
extern unsigned int dc_watertemp(const struct divecomputer *dc);
extern int add_event_to_dc(struct divecomputer *dc, struct event ev); // event structure is consumed, returns index of inserted event
@ -73,6 +72,6 @@ extern bool is_dc_manually_added_dive(const struct divecomputer *dc);
extern void make_manually_added_dive_dc(struct divecomputer *dc);
/* Check if two dive computer entries are the exact same dive (-1=no/0=maybe/1=yes) */
extern int match_one_dc(const struct divecomputer *a, const struct divecomputer *b);
extern int match_one_dc(const struct divecomputer &a, const struct divecomputer &b);
#endif

View file

@ -118,7 +118,7 @@ static int get_sample_o2(const struct dive *dive, const struct divecomputer *dc,
static int calculate_otu(const struct dive *dive)
{
double otu = 0.0;
const struct divecomputer *dc = &dive->dc;
const struct divecomputer *dc = &dive->dcs[0];
for (auto [psample, sample]: pairwise_range(dc->samples)) {
int t;
int po2i, po2f;
@ -179,7 +179,7 @@ static int calculate_otu(const struct dive *dive)
to the end of the segment, assuming a constant rate of change in po2 (i.e. depth) with time. */
static double calculate_cns_dive(const struct dive *dive)
{
const struct divecomputer *dc = &dive->dc;
const struct divecomputer *dc = &dive->dcs[0];
double cns = 0.0;
double rate;
/* Calculate the CNS for each sample in this dive and sum them */
@ -334,7 +334,7 @@ static double calculate_airuse(const struct dive *dive)
int airuse = 0;
// SAC for a CCR dive does not make sense.
if (dive->dc.divemode == CCR)
if (dive->dcs[0].divemode == CCR)
return 0.0;
for (int i = 0; i < dive->cylinders.nr; i++) {
@ -362,7 +362,7 @@ static double calculate_airuse(const struct dive *dive)
/* this only uses the first divecomputer to calculate the SAC rate */
static int calculate_sac(const struct dive *dive)
{
const struct divecomputer *dc = &dive->dc;
const struct divecomputer *dc = &dive->dcs[0];
double airuse, pressure, sac;
int duration, meandepth;
@ -389,10 +389,10 @@ static int calculate_sac(const struct dive *dive)
/* for now we do this based on the first divecomputer */
static void add_dive_to_deco(struct deco_state *ds, struct dive *dive, bool in_planner)
{
struct divecomputer *dc = &dive->dc;
struct divecomputer *dc = &dive->dcs[0];
gasmix_loop loop(*dive, dive->dc);
divemode_loop loop_d(dive->dc);
gasmix_loop loop(*dive, dive->dcs[0]);
divemode_loop loop_d(dive->dcs[0]);
for (auto [psample, sample]: pairwise_range(dc->samples)) {
int t0 = psample.time.seconds;
int t1 = sample.time.seconds;
@ -601,19 +601,21 @@ void update_cylinder_related_info(struct dive *dive)
}
}
/* Compare a list of dive computers by model name */
static int comp_dc(const struct divecomputer *dc1, const struct divecomputer *dc2)
/* Compare list of dive computers by model name */
static int comp_dc(const struct dive *d1, const struct dive *d2)
{
int cmp;
while (dc1 || dc2) {
if (!dc1)
auto it1 = d1->dcs.begin();
auto it2 = d2->dcs.begin();
while (it1 != d1->dcs.end() || it2 != d2->dcs.end()) {
if (it1 == d1->dcs.end())
return -1;
if (!dc2)
if (it2 == d2->dcs.end())
return 1;
if ((cmp = dc1->model.compare(dc2->model)) != 0)
int cmp = it1->model.compare(it2->model);
if (cmp != 0)
return cmp;
dc1 = dc1->next;
dc2 = dc2->next;
++it1;
++it2;
}
return 0;
}
@ -656,7 +658,7 @@ int comp_dives(const struct dive *a, const struct dive *b)
return -1;
if (a->number > b->number)
return 1;
if ((cmp = comp_dc(&a->dc, &b->dc)) != 0)
if ((cmp = comp_dc(a, b)) != 0)
return cmp;
if (a->id < b->id)
return -1;
@ -1375,15 +1377,13 @@ bool has_dive(unsigned int deviceid, unsigned int diveid)
struct dive *dive;
for_each_dive (i, dive) {
struct divecomputer *dc;
for_each_dc (dive, dc) {
if (dc->deviceid != deviceid)
continue;
if (dc->diveid != diveid)
continue;
return 1;
}
}
return 0;
for (auto &dc: dive->dcs) {
if (dc.deviceid != deviceid)
continue;
if (dc.diveid != diveid)
continue;
return 1;
}
}
return 0;
}

View file

@ -1077,7 +1077,7 @@ bool filter_constraint_match_dive(const filter_constraint &c, const struct dive
case FILTER_CONSTRAINT_PLANNED:
return is_planned(d) != c.negate;
case FILTER_CONSTRAINT_DIVE_MODE:
return check_multiple_choice(c, (int)d->dc.divemode); // should we be smarter and check all DCs?
return check_multiple_choice(c, (int)d->dcs[0].divemode); // should we be smarter and check all DCs?
case FILTER_CONSTRAINT_TAGS:
return has_tags(c, d);
case FILTER_CONSTRAINT_PEOPLE:

View file

@ -118,13 +118,13 @@ static int cobalt_dive(void *param, int, char **data, char **)
/* Cobalt stores the pressures, not the depth */
if (data[6])
state->cur_dive->dc.maxdepth.mm = atoi(data[6]);
state->cur_dive->dcs[0].maxdepth.mm = atoi(data[6]);
if (data[7])
state->cur_dive->dc.duration.seconds = atoi(data[7]);
state->cur_dive->dcs[0].duration.seconds = atoi(data[7]);
if (data[8])
state->cur_dive->dc.surface_pressure.mbar = atoi(data[8]);
state->cur_dive->dcs[0].surface_pressure.mbar = atoi(data[8]);
/*
* TODO: the deviceid hash should be calculated here.
*/
@ -140,8 +140,8 @@ static int cobalt_dive(void *param, int, char **data, char **)
settings_end(state);
if (data[9]) {
state->cur_dive->dc.deviceid = atoi(data[9]);
state->cur_dive->dc.model = "Cobalt import";
state->cur_dive->dcs[0].deviceid = atoi(data[9]);
state->cur_dive->dcs[0].model = "Cobalt import";
}
snprintf(get_buffer, sizeof(get_buffer) - 1, get_cylinder_template, state->cur_dive->number);

View file

@ -418,7 +418,7 @@ int try_to_open_csv(std::string &mem, enum csv_format type, struct divelog *log)
auto dive = std::make_unique<struct dive>();
dive->when = date;
dive->number = atoi(header[1]);
dc = &dive->dc;
dc = &dive->dcs[0];
time = 0;
for (;;) {
@ -511,11 +511,11 @@ int parse_txt_file(const char *filename, const char *csv, struct divelog *log)
auto dive = std::make_unique<struct dive>();
dive->when = utc_mktime(&cur_tm);;
dive->dc.model = "Poseidon MkVI Discovery";
dive->dcs[0].model = "Poseidon MkVI Discovery";
value = parse_mkvi_value(memtxt.data(), "Rig Serial number");
dive->dc.deviceid = atoi(value.c_str());
dive->dc.divemode = CCR;
dive->dc.no_o2sensors = 2;
dive->dcs[0].deviceid = atoi(value.c_str());
dive->dcs[0].divemode = CCR;
dive->dcs[0].no_o2sensors = 2;
cyl.cylinder_use = OXYGEN;
cyl.type.size.mliter = 3000;
@ -547,9 +547,9 @@ int parse_txt_file(const char *filename, const char *csv, struct divelog *log)
std::string value = parse_mkvi_value(lineptr, key.c_str());
if (value.empty())
break;
add_extra_data(&dive->dc, key, value);
add_extra_data(&dive->dcs[0], key, value);
}
dc = &dive->dc;
dc = &dive->dcs[0];
/*
* Read samples from the CSV file. A sample contains all the lines with same timestamp. The CSV file has

View file

@ -212,8 +212,8 @@ static int divinglog_profile(void *param, int, char **data, char **)
* Count the number of o2 sensors
*/
if (!state->cur_dive->dc.no_o2sensors && (state->cur_sample->o2sensor[0].mbar || state->cur_sample->o2sensor[1].mbar || state->cur_sample->o2sensor[2].mbar)) {
state->cur_dive->dc.no_o2sensors = state->cur_sample->o2sensor[0].mbar ? 1 : 0 +
if (!state->cur_dive->dcs[0].no_o2sensors && (state->cur_sample->o2sensor[0].mbar || state->cur_sample->o2sensor[1].mbar || state->cur_sample->o2sensor[2].mbar)) {
state->cur_dive->dcs[0].no_o2sensors = state->cur_sample->o2sensor[0].mbar ? 1 : 0 +
state->cur_sample->o2sensor[1].mbar ? 1 : 0 +
state->cur_sample->o2sensor[2].mbar ? 1 : 0;
}
@ -285,10 +285,10 @@ static int divinglog_dive(void *param, int, char **data, char **)
utf8_string(data[4], &state->cur_dive->notes);
if (data[5])
state->cur_dive->dc.maxdepth.mm = lrint(permissive_strtod(data[5], NULL) * 1000);
state->cur_dive->dcs[0].maxdepth.mm = lrint(permissive_strtod(data[5], NULL) * 1000);
if (data[6])
state->cur_dive->dc.duration.seconds = atoi(data[6]) * 60;
state->cur_dive->dcs[0].duration.seconds = atoi(data[6]) * 60;
if (data[7])
utf8_string(data[7], &state->cur_dive->diveguide);
@ -330,7 +330,7 @@ static int divinglog_dive(void *param, int, char **data, char **)
dc_settings_start(state);
if (data[12]) {
state->cur_dive->dc.model = data[12];
state->cur_dive->dcs[0].model = data[12];
} else {
state->cur_settings.dc.model = "Divinglog import";
}
@ -355,10 +355,10 @@ static int divinglog_dive(void *param, int, char **data, char **)
case '0':
break;
case '1':
state->cur_dive->dc.divemode = PSCR;
state->cur_dive->dcs[0].divemode = PSCR;
break;
case '2':
state->cur_dive->dc.divemode = CCR;
state->cur_dive->dcs[0].divemode = CCR;
break;
}
}
@ -367,9 +367,9 @@ static int divinglog_dive(void *param, int, char **data, char **)
settings_end(state);
if (data[12]) {
state->cur_dive->dc.model = data[12];
state->cur_dive->dcs[0].model = data[12];
} else {
state->cur_dive->dc.model = "Divinglog import";
state->cur_dive->dcs[0].model = "Divinglog import";
}
snprintf(get_buffer, sizeof(get_buffer) - 1, get_profile_template, diveid);

View file

@ -132,14 +132,14 @@ static int seac_dive(void *param, int, char **data, char **)
if (data[6]) {
switch (atoi(data[6])) {
case 1:
state->cur_dive->dc.divemode = OC;
state->cur_dive->dcs[0].divemode = OC;
break;
// Gauge Mode
case 2:
state->cur_dive->dc.divemode = UNDEF_COMP_TYPE;
state->cur_dive->dcs[0].divemode = UNDEF_COMP_TYPE;
break;
case 3:
state->cur_dive->dc.divemode = FREEDIVE;
state->cur_dive->dcs[0].divemode = FREEDIVE;
break;
default:
if (verbose) {
@ -155,7 +155,7 @@ static int seac_dive(void *param, int, char **data, char **)
// 10 = dive duration
if (data[10]) {
state->cur_dive->dc.duration.seconds = atoi(data[10]);
state->cur_dive->dcs[0].duration.seconds = atoi(data[10]);
}
// 8 = water_type
@ -181,7 +181,7 @@ static int seac_dive(void *param, int, char **data, char **)
if (data[11]) {
state->cur_dive->dc.maxdepth.mm = 10 * atoi(data[11]);
state->cur_dive->dcs[0].maxdepth.mm = 10 * atoi(data[11]);
}
// Create sql_stmt type to query DB
@ -205,20 +205,20 @@ static int seac_dive(void *param, int, char **data, char **)
settings_start(state);
dc_settings_start(state);
utf8_string_std(data[1], &state->cur_dive->dc.serial);
utf8_string_std(data[12],&state->cur_dive->dc.fw_version);
state->cur_dive->dc.model = strdup("Seac Action");
utf8_string_std(data[1], &state->cur_dive->dcs[0].serial);
utf8_string_std(data[12],&state->cur_dive->dcs[0].fw_version);
state->cur_dive->dcs[0].model = "Seac Action";
state->cur_dive->dc.deviceid = calculate_string_hash(data[1]);
state->cur_dive->dcs[0].deviceid = calculate_string_hash(data[1]);
add_extra_data(&state->cur_dive->dc, "GF-Lo", (const char*)sqlite3_column_text(sqlstmt, 9));
add_extra_data(&state->cur_dive->dc, "GF-Hi", (const char*)sqlite3_column_text(sqlstmt, 10));
add_extra_data(&state->cur_dive->dcs[0], "GF-Lo", (const char*)sqlite3_column_text(sqlstmt, 9));
add_extra_data(&state->cur_dive->dcs[0], "GF-Hi", (const char*)sqlite3_column_text(sqlstmt, 10));
dc_settings_end(state);
settings_end(state);
if (data[11]) {
state->cur_dive->dc.maxdepth.mm = 10 * atoi(data[11]);
state->cur_dive->dcs[0].maxdepth.mm = 10 * atoi(data[11]);
}
curcyl->gasmix.o2.permille = 10 * sqlite3_column_int(sqlstmt, 4);

View file

@ -214,7 +214,7 @@ static int shearwater_mode(void *param, int, char **data, char **)
struct parser_state *state = (struct parser_state *)param;
if (data[0])
state->cur_dive->dc.divemode = atoi(data[0]) == 0 ? CCR : OC;
state->cur_dive->dcs[0].divemode = atoi(data[0]) == 0 ? CCR : OC;
return 0;
}
@ -249,13 +249,13 @@ static int shearwater_dive(void *param, int, char **data, char **)
/* TODO: verify that metric calculation is correct */
if (data[6])
state->cur_dive->dc.maxdepth.mm = state->metric ? lrint(permissive_strtod(data[6], NULL) * 1000) : feet_to_mm(permissive_strtod(data[6], NULL));
state->cur_dive->dcs[0].maxdepth.mm = state->metric ? lrint(permissive_strtod(data[6], NULL) * 1000) : feet_to_mm(permissive_strtod(data[6], NULL));
if (data[7])
state->cur_dive->dc.duration.seconds = atoi(data[7]) * 60;
state->cur_dive->dcs[0].duration.seconds = atoi(data[7]) * 60;
if (data[8])
state->cur_dive->dc.surface_pressure.mbar = atoi(data[8]);
state->cur_dive->dcs[0].surface_pressure.mbar = atoi(data[8]);
/*
* TODO: the deviceid hash should be calculated here.
*/
@ -285,13 +285,13 @@ static int shearwater_dive(void *param, int, char **data, char **)
if (data[10]) {
switch (atoi(data[10])) {
case 2:
state->cur_dive->dc.model = "Shearwater Petrel/Perdix";
state->cur_dive->dcs[0].model = "Shearwater Petrel/Perdix";
break;
case 4:
state->cur_dive->dc.model = "Shearwater Predator";
state->cur_dive->dcs[0].model = "Shearwater Predator";
break;
default:
state->cur_dive->dc.model = "Shearwater import";
state->cur_dive->dcs[0].model = "Shearwater import";
break;
}
}
@ -379,13 +379,13 @@ static int shearwater_cloud_dive(void *param, int, char **data, char **)
/* TODO: verify that metric calculation is correct */
if (data[6])
state->cur_dive->dc.maxdepth.mm = state->metric ? lrint(permissive_strtod(data[6], NULL) * 1000) : feet_to_mm(permissive_strtod(data[6], NULL));
state->cur_dive->dcs[0].maxdepth.mm = state->metric ? lrint(permissive_strtod(data[6], NULL) * 1000) : feet_to_mm(permissive_strtod(data[6], NULL));
if (data[7])
state->cur_dive->dc.duration.seconds = atoi(data[7]);
state->cur_dive->dcs[0].duration.seconds = atoi(data[7]);
if (data[8])
state->cur_dive->dc.surface_pressure.mbar = atoi(data[8]);
state->cur_dive->dcs[0].surface_pressure.mbar = atoi(data[8]);
/*
* TODO: the deviceid hash should be calculated here.
*/
@ -415,13 +415,13 @@ static int shearwater_cloud_dive(void *param, int, char **data, char **)
if (data[10]) {
switch (atoi(data[10])) {
case 2:
state->cur_dive->dc.model = "Shearwater Petrel/Perdix";
state->cur_dive->dcs[0].model = "Shearwater Petrel/Perdix";
break;
case 4:
state->cur_dive->dc.model = "Shearwater Predator";
state->cur_dive->dcs[0].model = "Shearwater Predator";
break;
default:
state->cur_dive->dc.model = "Shearwater import";
state->cur_dive->dcs[0].model = "Shearwater import";
break;
}
}

View file

@ -191,7 +191,7 @@ static int dm4_dive(void *param, int, char **data, char **)
if (data[3])
state->cur_dive->duration.seconds = atoi(data[3]);
if (data[15])
state->cur_dive->dc.duration.seconds = atoi(data[15]);
state->cur_dive->dcs[0].duration.seconds = atoi(data[15]);
/*
* TODO: the deviceid hash should be calculated here.
@ -208,11 +208,11 @@ static int dm4_dive(void *param, int, char **data, char **)
settings_end(state);
if (data[6])
state->cur_dive->dc.maxdepth.mm = lrint(permissive_strtod(data[6], NULL) * 1000);
state->cur_dive->dcs[0].maxdepth.mm = lrint(permissive_strtod(data[6], NULL) * 1000);
if (data[8])
state->cur_dive->dc.airtemp.mkelvin = C_to_mkelvin(atoi(data[8]));
state->cur_dive->dcs[0].airtemp.mkelvin = C_to_mkelvin(atoi(data[8]));
if (data[9])
state->cur_dive->dc.watertemp.mkelvin = C_to_mkelvin(atoi(data[9]));
state->cur_dive->dcs[0].watertemp.mkelvin = C_to_mkelvin(atoi(data[9]));
/*
* TODO: handle multiple cylinders
@ -237,7 +237,7 @@ static int dm4_dive(void *param, int, char **data, char **)
cylinder_end(state);
if (data[14])
state->cur_dive->dc.surface_pressure.mbar = (atoi(data[14]) * 1000);
state->cur_dive->dcs[0].surface_pressure.mbar = (atoi(data[14]) * 1000);
interval = data[16] ? atoi(data[16]) : 0;
profileBlob = (float *)data[17];
@ -249,7 +249,7 @@ static int dm4_dive(void *param, int, char **data, char **)
if (profileBlob)
state->cur_sample->depth.mm = lrintf(profileBlob[i] * 1000.0f);
else
state->cur_sample->depth.mm = state->cur_dive->dc.maxdepth.mm;
state->cur_sample->depth.mm = state->cur_dive->dcs[0].maxdepth.mm;
if (data[18] && data[18][0])
state->cur_sample->temperature.mkelvin = C_to_mkelvin(tempBlob[i]);
@ -372,7 +372,7 @@ static int dm5_dive(void *param, int, char **data, char **)
if (data[3])
state->cur_dive->duration.seconds = atoi(data[3]);
if (data[15])
state->cur_dive->dc.duration.seconds = atoi(data[15]);
state->cur_dive->dcs[0].duration.seconds = atoi(data[15]);
/*
* TODO: the deviceid hash should be calculated here.
@ -390,28 +390,28 @@ static int dm5_dive(void *param, int, char **data, char **)
settings_end(state);
if (data[6])
state->cur_dive->dc.maxdepth.mm = lrint(permissive_strtod(data[6], NULL) * 1000);
state->cur_dive->dcs[0].maxdepth.mm = lrint(permissive_strtod(data[6], NULL) * 1000);
if (data[8])
state->cur_dive->dc.airtemp.mkelvin = C_to_mkelvin(atoi(data[8]));
state->cur_dive->dcs[0].airtemp.mkelvin = C_to_mkelvin(atoi(data[8]));
if (data[9])
state->cur_dive->dc.watertemp.mkelvin = C_to_mkelvin(atoi(data[9]));
state->cur_dive->dcs[0].watertemp.mkelvin = C_to_mkelvin(atoi(data[9]));
if (data[4]) {
state->cur_dive->dc.deviceid = atoi(data[4]);
state->cur_dive->dcs[0].deviceid = atoi(data[4]);
}
if (data[5])
utf8_string_std(data[5], &state->cur_dive->dc.model);
utf8_string_std(data[5], &state->cur_dive->dcs[0].model);
if (data[25]) {
switch(atoi(data[25])) {
case 1:
state->cur_dive->dc.divemode = OC;
state->cur_dive->dcs[0].divemode = OC;
break;
case 5:
state->cur_dive->dc.divemode = CCR;
state->cur_dive->dcs[0].divemode = CCR;
break;
default:
state->cur_dive->dc.divemode = OC;
state->cur_dive->dcs[0].divemode = OC;
break;
}
}
@ -424,7 +424,7 @@ static int dm5_dive(void *param, int, char **data, char **)
}
if (data[14])
state->cur_dive->dc.surface_pressure.mbar = (atoi(data[14]) / 100);
state->cur_dive->dcs[0].surface_pressure.mbar = (atoi(data[14]) / 100);
interval = data[16] ? atoi(data[16]) : 0;
@ -512,7 +512,7 @@ static int dm5_dive(void *param, int, char **data, char **)
if (profileBlob)
state->cur_sample->depth.mm = lrintf(profileBlob[i] * 1000.0f);
else
state->cur_sample->depth.mm = state->cur_dive->dc.maxdepth.mm;
state->cur_sample->depth.mm = state->cur_dive->dcs[0].maxdepth.mm;
if (data[18] && data[18][0])
state->cur_sample->temperature.mkelvin = C_to_mkelvin(tempBlob[i]);

View file

@ -212,7 +212,7 @@ static dc_status_t parse_gasmixes(device_data_t *devdata, struct dive *dive, dc_
break;
default:
if (dive->dc.divemode == CCR)
if (dive->dcs[0].divemode == CCR)
cyl.cylinder_use = DILUENT;
else
cyl.cylinder_use = OC_GAS;
@ -526,49 +526,43 @@ static dc_status_t parse_samples(device_data_t *, struct divecomputer *dc, dc_pa
return dc_parser_samples_foreach(parser, sample_cb, dc);
}
static int might_be_same_dc(struct divecomputer *a, struct divecomputer *b)
static int might_be_same_dc(const struct divecomputer &a, const struct divecomputer &b)
{
if (a->model.empty() || b->model.empty())
if (a.model.empty() || b.model.empty())
return 1;
if (strcasecmp(a->model.c_str(), b->model.c_str()))
if (strcasecmp(a.model.c_str(), b.model.c_str()))
return 0;
if (!a->deviceid || !b->deviceid)
if (!a.deviceid || !b.deviceid)
return 1;
return a->deviceid == b->deviceid;
return a.deviceid == b.deviceid;
}
static int match_one_dive(struct divecomputer *a, struct dive *dive)
static bool match_one_dive(const struct divecomputer &a, struct dive *dive)
{
struct divecomputer *b = &dive->dc;
/*
* Walk the existing dive computer data,
* see if we have a match (or an anti-match:
* the same dive computer but a different
* dive ID).
*/
do {
int match = match_one_dc(a, b);
if (match)
return match > 0;
b = b->next;
} while (b);
for (auto &b: dive->dcs) {
if (match_one_dc(a, b) > 0)
return true;
}
/* Ok, no exact dive computer match. Does the date match? */
b = &dive->dc;
do {
if (a->when == b->when && might_be_same_dc(a, b))
return 1;
b = b->next;
} while (b);
for (auto &b: dive->dcs) {
if (a.when == b.when && might_be_same_dc(a, b))
return true;
}
return 0;
return false;
}
/*
* Check if this dive already existed before the import
*/
static int find_dive(struct divecomputer *match)
static int find_dive(const struct divecomputer &match)
{
int i;
@ -604,13 +598,13 @@ static void parse_string_field(device_data_t *devdata, struct dive *dive, dc_fie
{
// Our dive ID is the string hash of the "Dive ID" string
if (!strcmp(str->desc, "Dive ID")) {
if (!dive->dc.diveid)
dive->dc.diveid = calculate_string_hash(str->value);
if (!dive->dcs[0].diveid)
dive->dcs[0].diveid = calculate_string_hash(str->value);
return;
}
// This will pick up serial number and firmware data
add_extra_data(&dive->dc, str->desc, str->value);
add_extra_data(&dive->dcs[0], str->desc, str->value);
/* GPS data? */
if (!strncmp(str->desc, "GPS", 3)) {
@ -648,7 +642,7 @@ static dc_status_t libdc_header_parser(dc_parser_t *parser, device_data_t *devda
}
// Our deviceid is the hash of the serial number
dive->dc.deviceid = 0;
dive->dcs[0].deviceid = 0;
if (rc == DC_STATUS_SUCCESS) {
tm.tm_year = dt.year;
@ -657,7 +651,7 @@ static dc_status_t libdc_header_parser(dc_parser_t *parser, device_data_t *devda
tm.tm_hour = dt.hour;
tm.tm_min = dt.minute;
tm.tm_sec = dt.second;
dive->when = dive->dc.when = utc_mktime(&tm);
dive->when = dive->dcs[0].when = utc_mktime(&tm);
}
// Parse the divetime.
@ -671,7 +665,7 @@ static dc_status_t libdc_header_parser(dc_parser_t *parser, device_data_t *devda
return rc;
}
if (rc == DC_STATUS_SUCCESS)
dive->dc.duration.seconds = divetime;
dive->dcs[0].duration.seconds = divetime;
// Parse the maxdepth.
double maxdepth = 0.0;
@ -681,7 +675,7 @@ static dc_status_t libdc_header_parser(dc_parser_t *parser, device_data_t *devda
return rc;
}
if (rc == DC_STATUS_SUCCESS)
dive->dc.maxdepth.mm = lrint(maxdepth * 1000);
dive->dcs[0].maxdepth.mm = lrint(maxdepth * 1000);
// Parse temperatures
double temperature;
@ -697,11 +691,11 @@ static dc_status_t libdc_header_parser(dc_parser_t *parser, device_data_t *devda
if (rc == DC_STATUS_SUCCESS)
switch(i) {
case 0:
dive->dc.airtemp.mkelvin = C_to_mkelvin(temperature);
dive->dcs[0].airtemp.mkelvin = C_to_mkelvin(temperature);
break;
case 1: // we don't distinguish min and max water temp here, so take min if given, max otherwise
case 2:
dive->dc.watertemp.mkelvin = C_to_mkelvin(temperature);
dive->dcs[0].watertemp.mkelvin = C_to_mkelvin(temperature);
break;
}
}
@ -725,16 +719,16 @@ static dc_status_t libdc_header_parser(dc_parser_t *parser, device_data_t *devda
return rc;
}
if (rc == DC_STATUS_SUCCESS) {
dive->dc.salinity = lrint(salinity.density * 10.0);
if (dive->dc.salinity == 0) {
dive->dcs[0].salinity = lrint(salinity.density * 10.0);
if (dive->dcs[0].salinity == 0) {
// sometimes libdivecomputer gives us density values, sometimes just
// a water type and a density of zero; let's make this work as best as we can
switch (salinity.type) {
case DC_WATER_FRESH:
dive->dc.salinity = FRESHWATER_SALINITY;
dive->dcs[0].salinity = FRESHWATER_SALINITY;
break;
default:
dive->dc.salinity = SEAWATER_SALINITY;
dive->dcs[0].salinity = SEAWATER_SALINITY;
break;
}
}
@ -747,7 +741,7 @@ static dc_status_t libdc_header_parser(dc_parser_t *parser, device_data_t *devda
return rc;
}
if (rc == DC_STATUS_SUCCESS)
dive->dc.surface_pressure.mbar = lrint(surface_pressure * 1000.0);
dive->dcs[0].surface_pressure.mbar = lrint(surface_pressure * 1000.0);
// The dive parsing may give us more device information
int idx;
@ -771,17 +765,17 @@ static dc_status_t libdc_header_parser(dc_parser_t *parser, device_data_t *devda
if (rc == DC_STATUS_SUCCESS)
switch(divemode) {
case DC_DIVEMODE_FREEDIVE:
dive->dc.divemode = FREEDIVE;
dive->dcs[0].divemode = FREEDIVE;
break;
case DC_DIVEMODE_GAUGE:
case DC_DIVEMODE_OC: /* Open circuit */
dive->dc.divemode = OC;
dive->dcs[0].divemode = OC;
break;
case DC_DIVEMODE_CCR: /* Closed circuit rebreather*/
dive->dc.divemode = CCR;
dive->dcs[0].divemode = CCR;
break;
case DC_DIVEMODE_SCR: /* Semi-closed circuit rebreather */
dive->dc.divemode = PSCR;
dive->dcs[0].divemode = PSCR;
break;
}
@ -821,8 +815,8 @@ static int dive_cb(const unsigned char *data, unsigned int size,
auto dive = std::make_unique<struct dive>();
// Fill in basic fields
dive->dc.model = devdata->model;
dive->dc.diveid = calculate_diveid(fingerprint, fsize);
dive->dcs[0].model = devdata->model;
dive->dcs[0].diveid = calculate_diveid(fingerprint, fsize);
// Parse the dive's header data
rc = libdc_header_parser (parser, devdata, dive.get());
@ -832,7 +826,7 @@ static int dive_cb(const unsigned char *data, unsigned int size,
}
// Initialize the sample data.
rc = parse_samples(devdata, &dive->dc, parser);
rc = parse_samples(devdata, &dive->dcs[0], parser);
if (rc != DC_STATUS_SUCCESS) {
download_error(translate("gettextFromC", "Error parsing the samples: %s"), errmsg(rc));
goto error_exit;
@ -850,32 +844,32 @@ static int dive_cb(const unsigned char *data, unsigned int size,
devdata->fingerprint = (unsigned char *)calloc(fsize, 1);
if (devdata->fingerprint) {
devdata->fsize = fsize;
devdata->fdeviceid = dive->dc.deviceid;
devdata->fdiveid = dive->dc.diveid;
devdata->fdeviceid = dive->dcs[0].deviceid;
devdata->fdiveid = dive->dcs[0].diveid;
memcpy(devdata->fingerprint, fingerprint, fsize);
}
}
/* If we already saw this dive, abort. */
if (!devdata->force_download && find_dive(&dive->dc)) {
if (!devdata->force_download && find_dive(dive->dcs[0])) {
std::string date_string = get_dive_date_c_string(dive->when);
dev_info(devdata, translate("gettextFromC", "Already downloaded dive at %s"), date_string.c_str());
return false;
}
/* Various libdivecomputer interface fixups */
if (dive->dc.airtemp.mkelvin == 0 && first_temp_is_air && !dive->dc.samples.empty()) {
dive->dc.airtemp = dive->dc.samples[0].temperature;
dive->dc.samples[0].temperature.mkelvin = 0;
if (dive->dcs[0].airtemp.mkelvin == 0 && first_temp_is_air && !dive->dcs[0].samples.empty()) {
dive->dcs[0].airtemp = dive->dcs[0].samples[0].temperature;
dive->dcs[0].samples[0].temperature.mkelvin = 0;
}
/* special case for bug in Tecdiving DiveComputer.eu
* often the first sample has a water temperature of 0C, followed by the correct
* temperature in the next sample */
if (dive->dc.model == "Tecdiving DiveComputer.eu" && !dive->dc.samples.empty() &&
dive->dc.samples[0].temperature.mkelvin == ZERO_C_IN_MKELVIN &&
dive->dc.samples[1].temperature.mkelvin > dive->dc.samples[0].temperature.mkelvin)
dive->dc.samples[0].temperature.mkelvin = dive->dc.samples[1].temperature.mkelvin;
if (dive->dcs[0].model == "Tecdiving DiveComputer.eu" && !dive->dcs[0].samples.empty() &&
dive->dcs[0].samples[0].temperature.mkelvin == ZERO_C_IN_MKELVIN &&
dive->dcs[0].samples[1].temperature.mkelvin > dive->dcs[0].samples[0].temperature.mkelvin)
dive->dcs[0].samples[0].temperature.mkelvin = dive->dcs[0].samples[1].temperature.mkelvin;
record_dive_to_table(dive.release(), devdata->log->dives.get());
return true;
@ -1593,7 +1587,7 @@ dc_status_t libdc_buffer_parser(struct dive *dive, device_data_t *data, unsigned
report_error("Error parsing the dive header data. Dive # %d: %s", dive->number, errmsg(rc));
}
}
rc = dc_parser_samples_foreach (parser, sample_cb, &dive->dc);
rc = dc_parser_samples_foreach (parser, sample_cb, &dive->dcs[0]);
if (rc != DC_STATUS_SUCCESS) {
report_error("Error parsing the sample data. Dive # %d: %s", dive->number, errmsg(rc));
dc_parser_destroy (parser);

View file

@ -143,7 +143,7 @@ static void parse_dives(int log_version, const unsigned char *buf, unsigned int
int i;
auto dive = std::make_unique<struct dive>();
memset(&sensor_ids, 0, sizeof(sensor_ids));
dc = &dive->dc;
dc = &dive->dcs[0];
/* Just the main cylinder until we can handle the buddy cylinder porperly */
for (i = 0; i < 1; i++) {

View file

@ -1643,15 +1643,12 @@ static git_blob *git_tree_entry_blob(git_repository *repo, const git_tree_entry
static struct divecomputer *create_new_dc(struct dive *dive)
{
struct divecomputer *dc = &dive->dc;
struct divecomputer *dc = &dive->dcs.back();
while (dc->next)
dc = dc->next;
/* Did we already fill that in? */
if (!dc->samples.empty() || !dc->model.empty() || dc->when) {
struct divecomputer *newdc = new divecomputer;
dc->next = newdc;
dc = newdc;
dive->dcs.emplace_back();
dc = &dive->dcs.back();
}
dc->when = dive->when;
dc->duration = dive->duration;

View file

@ -152,7 +152,7 @@ void ostctools_import(const char *file, struct divelog *log)
return;
}
std::string tmp = devdata.vendor + " " + devdata.model + " (Imported from OSTCTools)";
ostcdive->dc.model = tmp.c_str();
ostcdive->dcs[0].model = tmp;
// Parse the dive data
rc = libdc_buffer_parser(ostcdive.get(), &devdata, buffer.data(), i + 1);
@ -161,14 +161,14 @@ void ostctools_import(const char *file, struct divelog *log)
// Serial number is not part of the header nor the profile, so libdc won't
// catch it. If Serial is part of the extra_data, and set to zero, replace it.
ostcdive->dc.serial = std::to_string(serial);
ostcdive->dcs[0].serial = std::to_string(serial);
auto it = find_if(ostcdive->dc.extra_data.begin(), ostcdive->dc.extra_data.end(),
auto it = find_if(ostcdive->dcs[0].extra_data.begin(), ostcdive->dcs[0].extra_data.end(),
[](auto &ed) { return ed.key == "Serial"; });
if (it != ostcdive->dc.extra_data.end() && it->value == "0")
it->value = ostcdive->dc.serial.c_str();
else if (it == ostcdive->dc.extra_data.end())
add_extra_data(&ostcdive->dc, "Serial", ostcdive->dc.serial);
if (it != ostcdive->dcs[0].extra_data.end() && it->value == "0")
it->value = ostcdive->dcs[0].serial.c_str();
else if (it == ostcdive->dcs[0].extra_data.end())
add_extra_data(&ostcdive->dcs[0], "Serial", ostcdive->dcs[0].serial);
record_dive_to_table(ostcdive.release(), log->dives.get());
sort_dive_table(log->dives.get());

View file

@ -1014,9 +1014,9 @@ static int divinglog_dive_match(struct dive *dive, const char *name, char *buf,
}
return MATCH_STATE("divedate", divedate, &dive->when) ||
MATCH_STATE("entrytime", divetime, &dive->when) ||
MATCH("divetime", duration, &dive->dc.duration) ||
MATCH_STATE("depth", depth, &dive->dc.maxdepth) ||
MATCH_STATE("depthavg", depth, &dive->dc.meandepth) ||
MATCH("divetime", duration, &dive->dcs[0].duration) ||
MATCH_STATE("depth", depth, &dive->dcs[0].maxdepth) ||
MATCH_STATE("depthavg", depth, &dive->dcs[0].meandepth) ||
MATCH("comments", utf8_string, &dive->notes) ||
MATCH("names.buddy", utf8_string, &dive->buddy) ||
MATCH("name.country", utf8_string_std, &state->country) ||
@ -1082,8 +1082,8 @@ uddf_datedata(min, 0)
static int uddf_dive_match(struct dive *dive, const char *name, char *buf, struct parser_state *state)
{
return MATCH_STATE("datetime", uddf_datetime, &dive->when) ||
MATCH("diveduration", duration, &dive->dc.duration) ||
MATCH_STATE("greatestdepth", depth, &dive->dc.maxdepth) ||
MATCH("diveduration", duration, &dive->dcs[0].duration) ||
MATCH_STATE("greatestdepth", depth, &dive->dcs[0].maxdepth) ||
MATCH_STATE("year.date", uddf_year, &dive->when) ||
MATCH_STATE("month.date", uddf_mon, &dive->when) ||
MATCH_STATE("day.date", uddf_mday, &dive->when) ||
@ -1269,7 +1269,7 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf, str
* Legacy format note: per-dive depths and duration get saved
* in the first dive computer entry
*/
if (match_dc_data_fields(&dive->dc, name, buf, state))
if (match_dc_data_fields(&dive->dcs[0], name, buf, state))
return;
if (MATCH("filename.picture", utf8_string, &state->cur_picture.filename))

View file

@ -34,7 +34,7 @@ parser_state::~parser_state()
*/
struct divecomputer *get_dc(struct parser_state *state)
{
return state->cur_dc ?: &state->cur_dive->dc;
return state->cur_dc ?: &state->cur_dive->dcs[0];
}
/*
@ -118,7 +118,7 @@ void event_end(struct parser_state *state)
bool is_dive(struct parser_state *state)
{
return state->cur_dive &&
(state->cur_dive->dive_site || state->cur_dive->when || !state->cur_dive->dc.samples.empty());
(state->cur_dive->dive_site || state->cur_dive->when || !state->cur_dive->dcs[0].samples.empty());
}
void reset_dc_info(struct divecomputer *, struct parser_state *state)
@ -264,7 +264,7 @@ void dive_start(struct parser_state *state)
if (state->cur_dive)
return;
state->cur_dive = std::make_unique<dive>();
reset_dc_info(&state->cur_dive->dc, state);
reset_dc_info(&state->cur_dive->dcs[0], state);
memset(&state->cur_tm, 0, sizeof(state->cur_tm));
state->o2pressure_sensor = 1;
}
@ -383,20 +383,12 @@ void sample_end(struct parser_state *state)
void divecomputer_start(struct parser_state *state)
{
struct divecomputer *dc;
/* Start from the previous dive computer */
dc = &state->cur_dive->dc;
while (dc->next)
dc = dc->next;
struct divecomputer *dc = &state->cur_dive->dcs.back();
/* Did we already fill that in? */
if (!dc->samples.empty() || !dc->model.empty() || dc->when) {
struct divecomputer *newdc = new divecomputer;
if (newdc) {
dc->next = newdc;
dc = newdc;
}
state->cur_dive->dcs.emplace_back();
dc = &state->cur_dive->dcs.back();
}
/* .. this is the one we'll use */

View file

@ -128,7 +128,7 @@ static int tissue_at_end(struct deco_state *ds, struct dive *dive, const struct
return 0;
const struct sample *psample = nullptr;
divemode_loop loop(dive->dc);
divemode_loop loop(*dc);
for (auto &sample: dc->samples) {
o2pressure_t setpoint = psample ? psample->setpoint
: sample.setpoint;
@ -809,7 +809,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
plan_add_segment(diveplan, clock - previous_point_time, 0, current_cylinder, po2, false, divemode);
create_dive_from_plan(diveplan, dive, dc, is_planner);
add_plan_to_notes(diveplan, dive, show_disclaimer, error);
fixup_dc_duration(dc);
fixup_dc_duration(*dc);
return false;
}
@ -1091,7 +1091,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
}
create_dive_from_plan(diveplan, dive, dc, is_planner);
add_plan_to_notes(diveplan, dive, show_disclaimer, error);
fixup_dc_duration(dc);
fixup_dc_duration(*dc);
return decodive;
}

View file

@ -452,7 +452,7 @@ void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_d
/* Print the gas consumption next.*/
std::string temp;
if (dive->dc.divemode == CCR)
if (dive->dcs[0].divemode == CCR)
temp = translate("gettextFromC", "Gas consumption (CCR legs excluded):");
else
temp = casprintf_loc("%s %.*f|%.*f%s/min):", translate("gettextFromC", "Gas consumption (based on SAC"),
@ -497,7 +497,7 @@ void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_d
/* not for recreational mode and if no other warning was set before. */
else
if (lastbottomdp && gasidx == lastbottomdp->cylinderid
&& dive->dc.divemode == OC && decoMode(true) != RECREATIONAL) {
&& dive->dcs[0].divemode == OC && decoMode(true) != RECREATIONAL) {
/* Calculate minimum gas volume. */
volume_t mingasv;
mingasv.mliter = lrint(prefs.sacfactor / 100.0 * prefs.problemsolvingtime * prefs.bottomsac
@ -573,8 +573,8 @@ void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_d
bool o2warning_exist = false;
double amb;
divemode_loop loop(dive->dc);
if (dive->dc.divemode != CCR) {
divemode_loop loop(dive->dcs[0]);
if (dive->dcs[0].divemode != CCR) {
while (dp) {
if (dp->time != 0) {
std::string temp;

View file

@ -251,7 +251,6 @@ static void check_setpoint_events(const struct dive *, const struct divecomputer
static void calculate_max_limits_new(const struct dive *dive, const struct divecomputer *given_dc, struct plot_info &pi, bool in_planner)
{
const struct divecomputer *dc = &(dive->dc);
bool seen = false;
bool found_sample_beyond_last_event = false;
int maxdepth = dive->maxdepth.mm;
@ -272,17 +271,14 @@ static void calculate_max_limits_new(const struct dive *dive, const struct divec
minpressure = mbar_end;
}
/* Then do all the samples from all the dive computers */
do {
if (dc == given_dc)
seen = true;
auto process_dc = [&] (const divecomputer &dc) {
int lastdepth = 0;
/* Make sure we can fit all events */
if (!dc->events.empty())
maxtime = std::max(maxtime, dc->events.back().time.seconds);
if (!dc.events.empty())
maxtime = std::max(maxtime, dc.events.back().time.seconds);
for (auto &s: dc->samples) {
for (auto &s: dc.samples) {
int depth = s.depth.mm;
int temperature = s.temperature.mkelvin;
int heartbeat = s.heartbeat;
@ -317,13 +313,16 @@ static void calculate_max_limits_new(const struct dive *dive, const struct divec
}
lastdepth = depth;
}
};
dc = dc->next;
if (dc == NULL && !seen) {
dc = given_dc;
/* Then do all the samples from all the dive computers */
for (auto &dc: dive->dcs) {
if (&dc == given_dc)
seen = true;
}
} while (dc != NULL);
process_dc(dc);
}
if (!seen)
process_dc(*given_dc);
if (minpressure > maxpressure)
minpressure = 0;
@ -659,7 +658,7 @@ static void calculate_sac(const struct dive *dive, const struct divecomputer *dc
}
}
static void populate_secondary_sensor_data(const struct divecomputer *dc, struct plot_info &pi)
static void populate_secondary_sensor_data(const struct divecomputer &dc, struct plot_info &pi)
{
std::vector<int> seen(pi.nr_cylinders, 0);
for (int idx = 0; idx < pi.nr; ++idx)
@ -668,7 +667,7 @@ static void populate_secondary_sensor_data(const struct divecomputer *dc, struct
++seen[c]; // Count instances so we can differentiate a real sensor from just start and end pressure
int idx = 0;
/* We should try to see if it has interesting pressure data here */
for (const auto &sample: dc->samples) {
for (const auto &sample: dc.samples) {
if (idx >= pi.nr)
break;
for (; idx < pi.nr; ++idx) {
@ -708,7 +707,6 @@ static void setup_gas_sensor_pressure(const struct dive *dive, const struct dive
std::vector<int> seen(num_cyl, 0);
std::vector<int> first(num_cyl, 0);
std::vector<int> last(num_cyl, INT_MAX);
const struct divecomputer *secondary;
int prev = explicit_first_cylinder(dive, dc);
prev = prev >= 0 ? prev : 0;
@ -761,8 +759,8 @@ static void setup_gas_sensor_pressure(const struct dive *dive, const struct dive
continue;
/* If it's only mentioned by other dc's, ignore it */
for_each_dc(dive, secondary) {
if (has_gaschange_event(dive, secondary, i)) {
for (auto &secondary: dive->dcs) {
if (has_gaschange_event(dive, &secondary, i)) {
seen[i] = -1;
break;
}
@ -783,12 +781,11 @@ static void setup_gas_sensor_pressure(const struct dive *dive, const struct dive
* and try to see if they have sensor data different from the
* current dive computer (dc).
*/
secondary = &dive->dc;
do {
if (secondary == dc)
for (auto &secondary: dive->dcs) {
if (&secondary == dc)
continue;
populate_secondary_sensor_data(secondary, pi);
} while ((secondary = secondary->next) != NULL);
}
}
/* calculate DECO STOP / TTS / NDL */
@ -1001,7 +998,7 @@ static void calculate_deco_information(struct deco_state *ds, const struct deco_
if (in_planner && !pi.waypoint_above_ceiling &&
entry.depth < max_ceiling - 100 && entry.sec > 0) {
struct dive *non_const_dive = (struct dive *)dive; // cast away const!
add_event(&non_const_dive->dc, entry.sec, SAMPLE_EVENT_CEILING, -1, max_ceiling / 1000,
add_event(&non_const_dive->dcs[0], entry.sec, SAMPLE_EVENT_CEILING, -1, max_ceiling / 1000,
translate("gettextFromC", "planned waypoint above ceiling"));
pi.waypoint_above_ceiling = true;
}
@ -1292,7 +1289,7 @@ struct plot_info create_plot_info_new(const struct dive *dive, const struct dive
debug_print_profiledata(pi);
#endif
pi.meandepth = dive->dc.meandepth.mm;
pi.meandepth = dive->dcs[0].meandepth.mm;
analyze_plot_info(pi);
return pi;
}

View file

@ -119,9 +119,9 @@ static void save_tags(struct membuffer *b, struct tag_entry *tags)
put_string(b, "\n");
}
static void save_extra_data(struct membuffer *b, const struct divecomputer *dc)
static void save_extra_data(struct membuffer *b, const struct divecomputer &dc)
{
for (const auto &ed: dc->extra_data) {
for (const auto &ed: dc.extra_data) {
if (!ed.key.empty() && !ed.value.empty())
put_format(b, "keyvalue \"%s\" \"%s\"\n", ed.key.c_str(), ed.value.c_str());
}
@ -186,34 +186,34 @@ static void save_weightsystem_info(struct membuffer *b, struct dive *dive)
static void save_dive_temperature(struct membuffer *b, struct dive *dive)
{
if (dive->airtemp.mkelvin != dc_airtemp(&dive->dc))
if (dive->airtemp.mkelvin != dc_airtemp(dive).mkelvin)
put_temperature(b, dive->airtemp, "airtemp ", "°C\n");
if (dive->watertemp.mkelvin != dc_watertemp(&dive->dc))
if (dive->watertemp.mkelvin != dc_watertemp(dive).mkelvin)
put_temperature(b, dive->watertemp, "watertemp ", "°C\n");
}
static void save_depths(struct membuffer *b, struct divecomputer *dc)
static void save_depths(struct membuffer *b, const struct divecomputer &dc)
{
put_depth(b, dc->maxdepth, "maxdepth ", "m\n");
put_depth(b, dc->meandepth, "meandepth ", "m\n");
put_depth(b, dc.maxdepth, "maxdepth ", "m\n");
put_depth(b, dc.meandepth, "meandepth ", "m\n");
}
static void save_temperatures(struct membuffer *b, struct divecomputer *dc)
static void save_temperatures(struct membuffer *b, const struct divecomputer &dc)
{
put_temperature(b, dc->airtemp, "airtemp ", "°C\n");
put_temperature(b, dc->watertemp, "watertemp ", "°C\n");
put_temperature(b, dc.airtemp, "airtemp ", "°C\n");
put_temperature(b, dc.watertemp, "watertemp ", "°C\n");
}
static void save_airpressure(struct membuffer *b, struct divecomputer *dc)
static void save_airpressure(struct membuffer *b, const struct divecomputer &dc)
{
put_pressure(b, dc->surface_pressure, "surfacepressure ", "bar\n");
put_pressure(b, dc.surface_pressure, "surfacepressure ", "bar\n");
}
static void save_salinity(struct membuffer *b, struct divecomputer *dc)
static void save_salinity(struct membuffer *b, const struct divecomputer &dc)
{
if (!dc->salinity)
if (!dc.salinity)
return;
put_salinity(b, dc->salinity, "salinity ", "g/l\n");
put_salinity(b, dc.salinity, "salinity ", "g/l\n");
}
static void show_date(struct membuffer *b, timestamp_t when)
@ -367,19 +367,19 @@ static void save_sample(struct membuffer *b, const struct sample &sample, struct
put_format(b, "\n");
}
static void save_samples(struct membuffer *b, struct dive *dive, struct divecomputer *dc)
static void save_samples(struct membuffer *b, struct dive *dive, const struct divecomputer &dc)
{
int o2sensor;
struct sample dummy;
/* Is this a CCR dive with the old-style "o2pressure" sensor? */
o2sensor = legacy_format_o2pressures(dive, dc);
o2sensor = legacy_format_o2pressures(dive, &dc);
if (o2sensor >= 0) {
dummy.sensor[0] = !o2sensor;
dummy.sensor[1] = o2sensor;
}
for (const auto &s: dc->samples)
for (const auto &s: dc.samples)
save_sample(b, s, dummy, o2sensor);
}
@ -403,35 +403,35 @@ static void save_one_event(struct membuffer *b, struct dive *dive, const struct
put_string(b, "\n");
}
static void save_events(struct membuffer *b, struct dive *dive, const struct divecomputer *dc)
static void save_events(struct membuffer *b, struct dive *dive, const struct divecomputer &dc)
{
for (auto &ev: dc->events)
for (auto &ev: dc.events)
save_one_event(b, dive, ev);
}
static void save_dc(struct membuffer *b, struct dive *dive, struct divecomputer *dc)
static void save_dc(struct membuffer *b, struct dive *dive, const struct divecomputer &dc)
{
show_utf8(b, "model ", dc->model.c_str(), "\n");
if (dc->last_manual_time.seconds)
put_duration(b, dc->last_manual_time, "lastmanualtime ", "min\n");
if (dc->deviceid)
put_format(b, "deviceid %08x\n", dc->deviceid);
if (dc->diveid)
put_format(b, "diveid %08x\n", dc->diveid);
if (dc->when && dc->when != dive->when)
show_date(b, dc->when);
if (dc->duration.seconds && dc->duration.seconds != dive->dc.duration.seconds)
put_duration(b, dc->duration, "duration ", "min\n");
if (dc->divemode != OC) {
put_format(b, "dctype %s\n", divemode_text[dc->divemode]);
put_format(b, "numberofoxygensensors %d\n",dc->no_o2sensors);
show_utf8(b, "model ", dc.model.c_str(), "\n");
if (dc.last_manual_time.seconds)
put_duration(b, dc.last_manual_time, "lastmanualtime ", "min\n");
if (dc.deviceid)
put_format(b, "deviceid %08x\n", dc.deviceid);
if (dc.diveid)
put_format(b, "diveid %08x\n", dc.diveid);
if (dc.when && dc.when != dive->when)
show_date(b, dc.when);
if (dc.duration.seconds && dc.duration.seconds != dive->dcs[0].duration.seconds)
put_duration(b, dc.duration, "duration ", "min\n");
if (dc.divemode != OC) {
put_format(b, "dctype %s\n", divemode_text[dc.divemode]);
put_format(b, "numberofoxygensensors %d\n", dc.no_o2sensors);
}
save_depths(b, dc);
save_temperatures(b, dc);
save_airpressure(b, dc);
save_salinity(b, dc);
put_duration(b, dc->surfacetime, "surfacetime ", "min\n");
put_duration(b, dc.surfacetime, "surfacetime ", "min\n");
save_extra_data(b, dc);
save_events(b, dive, dc);
@ -445,8 +445,8 @@ static void save_dc(struct membuffer *b, struct dive *dive, struct divecomputer
static void create_dive_buffer(struct dive *dive, struct membuffer *b)
{
pressure_t surface_pressure = un_fixup_surface_pressure(dive);
if (dive->dc.duration.seconds > 0)
put_format(b, "duration %u:%02u min\n", FRACTION_TUPLE(dive->dc.duration.seconds, 60));
if (dive->dcs[0].duration.seconds > 0)
put_format(b, "duration %u:%02u min\n", FRACTION_TUPLE(dive->dcs[0].duration.seconds, 60));
SAVE("rating", rating);
SAVE("visibility", visibility);
SAVE("wavesize", wavesize);
@ -611,7 +611,7 @@ static int blob_insert(git_repository *repo, struct dir *tree, struct membuffer
return ret;
}
static int save_one_divecomputer(git_repository *repo, struct dir *tree, struct dive *dive, struct divecomputer *dc, int idx)
static int save_one_divecomputer(git_repository *repo, struct dir *tree, struct dive *dive, const struct divecomputer &dc, int idx)
{
int ret;
membuffer buf;
@ -659,7 +659,6 @@ static int save_pictures(git_repository *repo, struct dir *dir, struct dive *div
static int save_one_dive(git_repository *repo, struct dir *tree, struct dive *dive, struct tm *tm, bool cached_ok)
{
struct divecomputer *dc;
membuffer buf, name;
struct dir *subdir;
int ret, nr;
@ -696,12 +695,9 @@ static int save_one_dive(git_repository *repo, struct dir *tree, struct dive *di
* computer, use index 0 for that (which disables the index
* generation when naming it).
*/
dc = &dive->dc;
nr = dc->next ? 1 : 0;
do {
nr = dive->dcs.size() > 1 ? 1 : 0;
for (auto &dc: dive->dcs)
save_one_divecomputer(repo, subdir, dive, dc, nr++);
dc = dc->next;
} while (dc);
/* Save the picture data, if any */
save_pictures(repo, subdir, dive);
@ -1132,7 +1128,6 @@ static void create_commit_message(struct membuffer *msg, bool create_empty)
std::string location = get_dive_location(dive);
if (location.empty())
location = "no location";
struct divecomputer *dc = &dive->dc;
const char *sep = "\n";
if (dive->number)
@ -1142,12 +1137,12 @@ static void create_commit_message(struct membuffer *msg, bool create_empty)
if (trip && !empty_string(trip->location) && location != trip->location)
put_format(msg, " (%s)", trip->location);
put_format(msg, "\n");
do {
if (!dc->model.empty()) {
put_format(msg, "%s%s", sep, dc->model.c_str());
for (auto &dc: dive->dcs) {
if (!dc.model.empty()) {
put_format(msg, "%s%s", sep, dc.model.c_str());
sep = ", ";
}
} while ((dc = dc->next) != NULL);
}
put_format(msg, "\n");
}
put_format(msg, "Created by %s\n", subsurface_user_agent().c_str());

View file

@ -52,19 +52,18 @@ static void save_photos(struct membuffer *b, const char *photos_dir, const struc
static void write_divecomputers(struct membuffer *b, const struct dive *dive)
{
put_string(b, "\"divecomputers\":[");
const struct divecomputer *dc;
const char *separator = "";
for_each_dc (dive, dc) {
for (auto &dc: dive->dcs) {
put_string(b, separator);
separator = ", ";
put_format(b, "{");
write_attribute(b, "model", dc->model.c_str(), ", ");
if (dc->deviceid)
put_format(b, "\"deviceid\":\"%08x\", ", dc->deviceid);
write_attribute(b, "model", dc.model.c_str(), ", ");
if (dc.deviceid)
put_format(b, "\"deviceid\":\"%08x\", ", dc.deviceid);
else
put_string(b, "\"deviceid\":\"--\", ");
if (dc->diveid)
put_format(b, "\"diveid\":\"%08x\" ", dc->diveid);
if (dc.diveid)
put_format(b, "\"diveid\":\"%08x\" ", dc.diveid);
else
put_string(b, "\"diveid\":\"--\" ");
put_format(b, "}");
@ -82,7 +81,7 @@ static void write_dive_status(struct membuffer *b, const struct dive *dive)
static void put_HTML_bookmarks(struct membuffer *b, const struct dive *dive)
{
const char *separator = "\"events\":[";
for (const auto &ev: dive->dc.events) {
for (const auto &ev: dive->dcs[0].events) {
put_string(b, separator);
separator = ", ";
put_string(b, "{\"name\":\"");
@ -172,14 +171,14 @@ static void put_cylinder_HTML(struct membuffer *b, const struct dive *dive)
static void put_HTML_samples(struct membuffer *b, const struct dive *dive)
{
put_format(b, "\"maxdepth\":%d,", dive->dc.maxdepth.mm);
put_format(b, "\"duration\":%d,", dive->dc.duration.seconds);
put_format(b, "\"maxdepth\":%d,", dive->dcs[0].maxdepth.mm);
put_format(b, "\"duration\":%d,", dive->dcs[0].duration.seconds);
if (dive->dc.samples.empty())
if (dive->dcs[0].samples.empty())
return;
const char *separator = "\"samples\":[";
for (auto &s: dive->dc.samples) {
for (auto &s: dive->dcs[0].samples) {
put_format(b, "%s[%d,%d,%d,%d]", separator, s.time.seconds, s.depth.mm, s.pressure[0].mbar, s.temperature.mkelvin);
separator = ", ";
}

View file

@ -210,7 +210,7 @@ static void save_profiles_buffer(struct membuffer *b, bool select_only)
for_each_dive(i, dive) {
if (select_only && !dive->selected)
continue;
plot_info pi = create_plot_info_new(dive, &dive->dc, planner_deco_state);
plot_info pi = create_plot_info_new(dive, &dive->dcs[0], planner_deco_state);
put_headers(b, pi.nr_cylinders);
for (int i = 0; i < pi.nr; i++)
@ -223,7 +223,7 @@ void save_subtitles_buffer(struct membuffer *b, struct dive *dive, int offset, i
{
struct deco_state *planner_deco_state = NULL;
plot_info pi = create_plot_info_new(dive, &dive->dc, planner_deco_state);
plot_info pi = create_plot_info_new(dive, &dive->dcs[0], planner_deco_state);
put_format(b, "[Script Info]\n");
put_format(b, "; Script generated by Subsurface %s\n", subsurface_canonical_version());

View file

@ -116,13 +116,13 @@ static void save_dive_temperature(struct membuffer *b, struct dive *dive)
{
if (!dive->airtemp.mkelvin && !dive->watertemp.mkelvin)
return;
if (dive->airtemp.mkelvin == dc_airtemp(&dive->dc) && dive->watertemp.mkelvin == dc_watertemp(&dive->dc))
if (dive->airtemp.mkelvin == dc_airtemp(dive).mkelvin && dive->watertemp.mkelvin == dc_watertemp(dive).mkelvin)
return;
put_string(b, " <divetemperature");
if (dive->airtemp.mkelvin != dc_airtemp(&dive->dc))
if (dive->airtemp.mkelvin != dc_airtemp(dive).mkelvin)
put_temperature(b, dive->airtemp, " air='", " C'");
if (dive->watertemp.mkelvin != dc_watertemp(&dive->dc))
if (dive->watertemp.mkelvin != dc_watertemp(dive).mkelvin)
put_temperature(b, dive->watertemp, " water='", " C'");
put_string(b, "/>\n");
}
@ -447,7 +447,7 @@ static void save_dc(struct membuffer *b, struct dive *dive, struct divecomputer
put_format(b, " diveid='%08x'", dc->diveid);
if (dc->when && dc->when != dive->when)
show_date(b, dc->when);
if (dc->duration.seconds && dc->duration.seconds != dive->dc.duration.seconds)
if (dc->duration.seconds && dc->duration.seconds != dive->dcs[0].duration.seconds)
put_duration(b, dc->duration, " duration='", " min'");
if (dc->divemode != OC) {
int i = (int)dc->divemode;
@ -490,7 +490,6 @@ static void save_picture(struct membuffer *b, struct picture *pic)
void save_one_dive_to_mb(struct membuffer *b, struct dive *dive, bool anonymize)
{
struct divecomputer *dc;
pressure_t surface_pressure = un_fixup_surface_pressure(dive);
put_string(b, "<dive");
@ -530,9 +529,9 @@ void save_one_dive_to_mb(struct membuffer *b, struct dive *dive, bool anonymize)
show_date(b, dive->when);
if (surface_pressure.mbar)
put_pressure(b, surface_pressure, " airpressure='", " bar'");
if (dive->dc.duration.seconds > 0)
if (dive->dcs[0].duration.seconds > 0)
put_format(b, " duration='%u:%02u min'>\n",
FRACTION_TUPLE(dive->dc.duration.seconds, 60));
FRACTION_TUPLE(dive->dcs[0].duration.seconds, 60));
else
put_format(b, ">\n");
save_overview(b, dive, anonymize);
@ -540,8 +539,8 @@ void save_one_dive_to_mb(struct membuffer *b, struct dive *dive, bool anonymize)
save_weightsystem_info(b, dive);
save_dive_temperature(b, dive);
/* Save the dive computer data */
for_each_dc(dive, dc)
save_dc(b, dive, dc);
for (auto &dc: dive->dcs)
save_dc(b, dive, &dc);
FOR_EACH_PICTURE(dive)
save_picture(b, picture);
put_format(b, "</dive>\n");

View file

@ -151,8 +151,8 @@ stats_summary calculate_stats_summary(bool selected_only)
out.stats_by_type[0].selection_size++;
process_dive(dp, out.stats_by_type[0]);
process_dive(dp, out.stats_by_type[dp->dc.divemode + 1]);
out.stats_by_type[dp->dc.divemode + 1].selection_size++;
process_dive(dp, out.stats_by_type[dp->dcs[0].divemode + 1]);
out.stats_by_type[dp->dcs[0].divemode + 1].selection_size++;
/* stats_by_depth[0] is all the dives combined */
out.stats_by_depth[0].selection_size++;
@ -273,7 +273,6 @@ bool has_gaschange_event(const struct dive *dive, const struct divecomputer *dc,
bool is_cylinder_used(const struct dive *dive, int idx)
{
const struct divecomputer *dc;
cylinder_t *cyl;
if (idx < 0 || idx >= dive->cylinders.nr)
return false;
@ -285,10 +284,10 @@ bool is_cylinder_used(const struct dive *dive, int idx)
if ((cyl->sample_start.mbar - cyl->sample_end.mbar) > SOME_GAS)
return true;
for_each_dc(dive, dc) {
if (has_gaschange_event(dive, dc, idx))
for (auto &dc: dive->dcs) {
if (has_gaschange_event(dive, &dc, idx))
return true;
else if (dc->divemode == CCR && idx == get_cylinder_idx_by_use(dive, OXYGEN))
else if (dc.divemode == CCR && idx == get_cylinder_idx_by_use(dive, OXYGEN))
return true;
}
return false;
@ -296,15 +295,12 @@ bool is_cylinder_used(const struct dive *dive, int idx)
bool is_cylinder_prot(const struct dive *dive, int idx)
{
const struct divecomputer *dc;
if (idx < 0 || idx >= dive->cylinders.nr)
return false;
for_each_dc(dive, dc) {
if (has_gaschange_event(dive, dc, idx))
return true;
}
return false;
return std::any_of(dive->dcs.begin(), dive->dcs.end(),
[dive, idx](auto &dc)
{ return has_gaschange_event(dive, &dc, idx); });
}
/* Returns a vector with dive->cylinders.nr entries */

View file

@ -45,7 +45,7 @@ QString formatSac(const dive *d)
QString formatNotes(const dive *d)
{
QString tmp = d->notes ? QString::fromUtf8(d->notes) : QString();
if (is_dc_planner(&d->dc)) {
if (is_dc_planner(&d->dcs[0])) {
QTextDocument notes;
#define _NOTES_BR "&#92n"
tmp.replace("<thead>", "<thead>" _NOTES_BR)

View file

@ -188,15 +188,15 @@ static void uemis_get_weight(std::string_view buffer, weightsystem_t &weight, in
static std::unique_ptr<dive> uemis_start_dive(uint32_t deviceid)
{
auto dive = std::make_unique<struct dive>();
dive->dc.model = "Uemis Zurich";
dive->dc.deviceid = deviceid;
dive->dcs[0].model = "Uemis Zurich";
dive->dcs[0].deviceid = deviceid;
return dive;
}
static struct dive *get_dive_by_uemis_diveid(device_data_t *devdata, uint32_t object_id)
{
for (int i = 0; i < devdata->log->dives->nr; i++) {
if (object_id == devdata->log->dives->dives[i]->dc.diveid)
if (object_id == devdata->log->dives->dives[i]->dcs[0].diveid)
return devdata->log->dives->dives[i];
}
return NULL;
@ -732,21 +732,21 @@ static void parse_tag(struct dive *dive, std::string_view tag, std::string_view
* with the binary data and would just get overwritten */
#if UEMIS_DEBUG & 4
if (tag == "file_content")
report_info("Adding to dive %d : %s = %s\n", dive->dc.diveid, std::string(tag).c_str(), std::string(val).c_str());
report_info("Adding to dive %d : %s = %s\n", dive->dcs[0].diveid, std::string(tag).c_str(), std::string(val).c_str());
#endif
if (tag == "date") {
dive->when = uemis_ts(val);
} else if (tag == "duration") {
uemis_duration(val, dive->dc.duration);
uemis_duration(val, dive->dcs[0].duration);
} else if (tag == "depth") {
uemis_depth(val, dive->dc.maxdepth);
uemis_depth(val, dive->dcs[0].maxdepth);
} else if (tag == "file_content") {
uemis_obj.parse_divelog_binary(val, dive);
} else if (tag == "altitude") {
uemis_get_index(val, dive->dc.surface_pressure.mbar);
uemis_get_index(val, dive->dcs[0].surface_pressure.mbar);
} else if (tag == "f32Weight") {
weightsystem_t ws = empty_weightsystem;
uemis_get_weight(val, ws, dive->dc.diveid);
uemis_get_weight(val, ws, dive->dcs[0].diveid);
add_cloned_weightsystem(&dive->weightsystems, ws);
} else if (tag == "notes") {
uemis_add_string(val, &dive->notes, " ");
@ -774,12 +774,12 @@ static bool uemis_delete_dive(device_data_t *devdata, uint32_t diveid)
{
struct dive *dive = NULL;
if (devdata->log->dives->dives[devdata->log->dives->nr - 1]->dc.diveid == diveid) {
if (devdata->log->dives->dives[devdata->log->dives->nr - 1]->dcs[0].diveid == diveid) {
/* we hit the last one in the array */
dive = devdata->log->dives->dives[devdata->log->dives->nr - 1];
} else {
for (int i = 0; i < devdata->log->dives->nr - 1; i++) {
if (devdata->log->dives->dives[i]->dc.diveid == diveid) {
if (devdata->log->dives->dives[i]->dcs[0].diveid == diveid) {
dive = devdata->log->dives->dives[i];
for (int x = i; x < devdata->log->dives->nr - 1; x++)
devdata->log->dives->dives[i] = devdata->log->dives->dives[x + 1];
@ -902,7 +902,7 @@ static bool process_raw_buffer(device_data_t *devdata, uint32_t deviceid, std::s
// Is log
if (tag == "object_id") {
from_chars(val, max_divenr);
owned_dive->dc.diveid = max_divenr;
owned_dive->dcs[0].diveid = max_divenr;
#if UEMIS_DEBUG % 2
report_info("Adding new dive from log with object_id %d.\n", max_divenr);
#endif
@ -940,10 +940,10 @@ static bool process_raw_buffer(device_data_t *devdata, uint32_t deviceid, std::s
struct dive_site *ds = devdata->log->sites->create("from Uemis"s);
unregister_dive_from_dive_site(non_owned_dive);
ds->add_dive(non_owned_dive);
uemis_obj.mark_divelocation(non_owned_dive->dc.diveid, divespot_id, ds);
uemis_obj.mark_divelocation(non_owned_dive->dcs[0].diveid, divespot_id, ds);
}
#if UEMIS_DEBUG & 2
report_info("Created divesite %d for diveid : %d\n", non_owned_dive->dive_site->uuid, non_owned_dive->dc.diveid);
report_info("Created divesite %d for diveid : %d\n", non_owned_dive->dive_site->uuid, non_owned_dive->dcs[0].diveid);
#endif
} else if (non_owned_dive) {
parse_tag(non_owned_dive, tag, val);
@ -951,7 +951,7 @@ static bool process_raw_buffer(device_data_t *devdata, uint32_t deviceid, std::s
}
}
if (is_log) {
if (owned_dive->dc.diveid)
if (owned_dive->dcs[0].diveid)
record_dive_to_table(owned_dive.release(), devdata->log->dives.get());
else /* partial dive */
return false;
@ -981,16 +981,15 @@ static std::pair<uint32_t, uint32_t> uemis_get_divenr(uint32_t deviceid, struct
for (i = 0; i < table->nr; i++) {
struct dive *d = table->dives[i];
struct divecomputer *dc;
if (!d)
continue;
for_each_dc (d, dc) {
if (dc->model == "Uemis Zurich" &&
(dc->deviceid == 0 || dc->deviceid == 0x7fffffff || dc->deviceid == deviceid)) {
if (dc->diveid > maxdiveid)
maxdiveid = dc->diveid;
if (dc->diveid < mindiveid)
mindiveid = dc->diveid;
for (auto &dc: d->dcs) {
if (dc.model == "Uemis Zurich" &&
(dc.deviceid == 0 || dc.deviceid == 0x7fffffff || dc.deviceid == deviceid)) {
if (dc.diveid > maxdiveid)
maxdiveid = dc.diveid;
if (dc.diveid < mindiveid)
mindiveid = dc.diveid;
}
}
}
@ -1144,9 +1143,9 @@ static bool get_matching_dive(int idx, int &newmax, uemis_mem_status &mem_status
int deleted_files = 0;
int fail_count = 0;
snprintf(log_file_no_to_find, sizeof(log_file_no_to_find), "logfilenr{int{%d", dive->dc.diveid);
snprintf(log_file_no_to_find, sizeof(log_file_no_to_find), "logfilenr{int{%d", dive->dcs[0].diveid);
#if UEMIS_DEBUG & 2
report_info("Looking for dive details to go with dive log id %d\n", dive->dc.diveid);
report_info("Looking for dive details to go with dive log id %d\n", dive->dcs[0].diveid);
#endif
while (!found) {
if (import_thread_cancelled)
@ -1176,9 +1175,9 @@ static bool get_matching_dive(int idx, int &newmax, uemis_mem_status &mem_status
* UEMIS unfortunately deletes dives by deleting the dive details and not the logs. */
#if UEMIS_DEBUG & 2
d_time = get_dive_date_c_string(dive->when);
report_info("Matching dive log id %d from %s with dive details %d\n", dive->dc.diveid, d_time.c_str(), dive_to_read);
report_info("Matching dive log id %d from %s with dive details %d\n", dive->dcs[0].diveid, d_time.c_str(), dive_to_read);
#endif
int divespot_id = uemis_obj.get_divespot_id_by_diveid(dive->dc.diveid);
int divespot_id = uemis_obj.get_divespot_id_by_diveid(dive->dcs[0].diveid);
if (divespot_id >= 0)
get_uemis_divespot(data, mountpath, divespot_id, dive);
@ -1186,13 +1185,13 @@ static bool get_matching_dive(int idx, int &newmax, uemis_mem_status &mem_status
/* in this case we found a deleted file, so let's increment */
#if UEMIS_DEBUG & 2
d_time = get_dive_date_c_string(dive->when);
report_info("TRY matching dive log id %d from %s with dive details %d but details are deleted\n", dive->dc.diveid, d_time.c_str(), dive_to_read);
report_info("TRY matching dive log id %d from %s with dive details %d but details are deleted\n", dive->dcs[0].diveid, d_time.c_str(), dive_to_read);
#endif
deleted_files++;
/* mark this log entry as deleted and cleanup later, otherwise we mess up our array */
dive->hidden_by_filter = true;
#if UEMIS_DEBUG & 2
report_info("Deleted dive from %s, with id %d from table -- newmax is %d\n", d_time.c_str(), dive->dc.diveid, newmax);
report_info("Deleted dive from %s, with id %d from table -- newmax is %d\n", d_time.c_str(), dive->dcs[0].diveid, newmax);
#endif
}
} else {
@ -1200,7 +1199,7 @@ static bool get_matching_dive(int idx, int &newmax, uemis_mem_status &mem_status
size_t pos = mbuf.find("logfilenr");
if (pos != std::string::npos && mbuf.find("act{") != std::string::npos) {
sscanf(mbuf.c_str() + pos, "logfilenr{int{%u", &nr_found);
if (nr_found >= dive->dc.diveid || nr_found == 0) {
if (nr_found >= dive->dcs[0].diveid || nr_found == 0) {
found_above = true;
dive_to_read = dive_to_read - 2;
} else {
@ -1433,7 +1432,7 @@ std::string do_uemis_import(device_data_t *data)
* to see if we have to clean some dead bodies from our download table */
for (int next_table_index = 0; next_table_index < data->log->dives->nr; ) {
if (data->log->dives->dives[next_table_index]->hidden_by_filter)
uemis_delete_dive(data, data->log->dives->dives[next_table_index]->dc.diveid);
uemis_delete_dive(data, data->log->dives->dives[next_table_index]->dcs[0].diveid);
else
next_table_index++;
}

View file

@ -271,7 +271,7 @@ void uemis::event(struct dive *dive, struct divecomputer *dc, struct sample *sam
}
#if UEMIS_DEBUG & 32
printf("%dm:%ds: p_amb_tol:%d surface:%d holdtime:%d holddepth:%d/%d ---> stopdepth:%d stoptime:%d ndl:%d\n",
sample->time.seconds / 60, sample->time.seconds % 60, u_sample->p_amb_tol, dive->dc.surface_pressure.mbar,
sample->time.seconds / 60, sample->time.seconds % 60, u_sample->p_amb_tol, dive->dcs[0].surface_pressure.mbar,
u_sample->hold_time, u_sample->hold_depth, stopdepth, sample->stopdepth.mm, sample->stoptime.seconds, sample->ndl.seconds);
#endif
}
@ -283,17 +283,17 @@ void uemis::parse_divelog_binary(std::string_view base64, struct dive *dive)
{
struct sample *sample = NULL;
uemis_sample *u_sample;
struct divecomputer *dc = &dive->dc;
struct divecomputer *dc = &dive->dcs[0];
int dive_template, gasoffset;
uint8_t active = 0;
auto data = convert_base64(base64);
dive->dc.airtemp.mkelvin = C_to_mkelvin((*(uint16_t *)(data.data() + 45)) / 10.0);
dive->dc.surface_pressure.mbar = *(uint16_t *)(data.data() + 43);
dive->dcs[0].airtemp.mkelvin = C_to_mkelvin((*(uint16_t *)(data.data() + 45)) / 10.0);
dive->dcs[0].surface_pressure.mbar = *(uint16_t *)(data.data() + 43);
if (*(uint8_t *)(data.data() + 19))
dive->dc.salinity = SEAWATER_SALINITY; /* avg grams per 10l sea water */
dive->dcs[0].salinity = SEAWATER_SALINITY; /* avg grams per 10l sea water */
else
dive->dc.salinity = FRESHWATER_SALINITY; /* grams per 10l fresh water */
dive->dcs[0].salinity = FRESHWATER_SALINITY; /* grams per 10l fresh water */
/* this will allow us to find the last dive read so far from this computer */
dc->model = "Uemis Zurich";
@ -353,7 +353,7 @@ void uemis::parse_divelog_binary(std::string_view base64, struct dive *dive)
u_sample++;
}
if (sample)
dive->dc.duration.seconds = sample->time.seconds - 1;
dive->dcs[0].duration.seconds = sample->time.seconds - 1;
/* get data from the footer */
add_extra_data(dc, "FW Version",

View file

@ -563,7 +563,7 @@ int PlannerWidgets::getDcNr()
divemode_t PlannerWidgets::getRebreatherMode() const
{
return get_dive_dc_const(planned_dive.get(), dcNr)->divemode;
return get_dive_dc(planned_dive.get(), dcNr)->divemode;
}
void PlannerWidgets::preparePlanDive(const dive *currentDive, int currentDcNr)
@ -575,8 +575,8 @@ void PlannerWidgets::preparePlanDive(const dive *currentDive, int currentDcNr)
// plan the dive in the same mode as the currently selected one
if (currentDive) {
plannerSettingsWidget.setDiveMode(get_dive_dc_const(currentDive, currentDcNr)->divemode);
plannerSettingsWidget.setBailoutVisibility(get_dive_dc_const(currentDive, currentDcNr)->divemode);
plannerSettingsWidget.setDiveMode(get_dive_dc(currentDive, currentDcNr)->divemode);
plannerSettingsWidget.setBailoutVisibility(get_dive_dc(currentDive, currentDcNr)->divemode);
if (currentDive->salinity)
plannerWidget.setSalinity(currentDive->salinity);
else // No salinity means salt water

View file

@ -705,11 +705,11 @@ void MainWindow::on_actionAddDive_triggered()
struct dive d;
d.id = dive_getUniqID();
d.when = QDateTime::currentMSecsSinceEpoch() / 1000L + gettimezoneoffset() + 3600;
d.dc.duration.seconds = 40 * 60;
d.dc.maxdepth.mm = M_OR_FT(15, 45);
d.dc.meandepth.mm = M_OR_FT(13, 39); // this creates a resonable looking safety stop
make_manually_added_dive_dc(&d.dc);
fake_dc(&d.dc);
d.dcs[0].duration.seconds = 40 * 60;
d.dcs[0].maxdepth.mm = M_OR_FT(15, 45);
d.dcs[0].meandepth.mm = M_OR_FT(13, 39); // this creates a resonable looking safety stop
make_manually_added_dive_dc(&d.dcs[0]);
fake_dc(&d.dcs[0]);
add_default_cylinder(&d);
fixup_dive(&d);

View file

@ -167,7 +167,7 @@ void ProfileWidget::setDive(const struct dive *d, int dcNr)
{
stack->setCurrentIndex(1); // show profile
bool freeDiveMode = get_dive_dc_const(d, dcNr)->divemode == FREEDIVE;
bool freeDiveMode = get_dive_dc(d, dcNr)->divemode == FREEDIVE;
ui.profCalcCeiling->setDisabled(freeDiveMode);
ui.profCalcCeiling->setDisabled(freeDiveMode);
ui.profCalcAllTissues ->setDisabled(freeDiveMode);

View file

@ -152,9 +152,9 @@ void TabDiveInformation::updateProfile()
ui->oxygenHeliumText->setText(gaslist);
ui->diveTimeText->setText(get_dive_duration_string(currentDive->duration.seconds, tr("h"), tr("min"), tr("sec"),
" ", currentDive->dc.divemode == FREEDIVE));
" ", currentDive->dcs[0].divemode == FREEDIVE));
ui->sacText->setText(currentDive->cylinders.nr > 0 && mean[0] && currentDive->dc.divemode != CCR ? std::move(SACs) : QString());
ui->sacText->setText(currentDive->cylinders.nr > 0 && mean[0] && currentDive->dcs[0].divemode != CCR ? std::move(SACs) : QString());
if (currentDive->surface_pressure.mbar == 0) {
ui->atmPressVal->clear(); // If no atm pressure for dive then clear text box

View file

@ -254,7 +254,7 @@ void TabDiveNotes::updateData(const std::vector<dive *> &, dive *currentDive, in
ui.LocationLabel->setText(tr("Location"));
ui.NotesLabel->setText(tr("Notes"));
ui.tagWidget->setText(QString::fromStdString(taglist_get_tagstring(currentDive->tag_list)));
bool isManual = is_dc_manually_added_dive(&currentDive->dc);
bool isManual = is_dc_manually_added_dive(&currentDive->dcs[0]);
ui.depth->setVisible(isManual);
ui.depthLabel->setVisible(isManual);
ui.duration->setVisible(isManual);

View file

@ -108,7 +108,7 @@ void TabDiveStatistics::updateData(const std::vector<dive *> &, dive *currentDiv
}
bool is_freedive = currentDive && currentDive->dc.divemode == FREEDIVE;
bool is_freedive = currentDive && currentDive->dcs[0].divemode == FREEDIVE;
ui->divesAllText->setText(QString::number(stats_selection.selection_size));
ui->totalTimeAllText->setText(get_dive_duration_string(stats_selection.total_time.seconds, tr("h"), tr("min"), tr("sec"), " ", is_freedive));

View file

@ -534,11 +534,11 @@ QVariant TemplateLayout::getValue(QString list, QString property, const State &s
} else if (property == "duration") {
return formatDiveDuration(d);
} else if (property == "noDive") {
return d->duration.seconds == 0 && d->dc.duration.seconds == 0;
return d->duration.seconds == 0 && d->dcs[0].duration.seconds == 0;
} else if (property == "depth") {
return get_depth_string(d->dc.maxdepth.mm, true, true);
return get_depth_string(d->dcs[0].maxdepth.mm, true, true);
} else if (property == "meandepth") {
return get_depth_string(d->dc.meandepth.mm, true, true);
return get_depth_string(d->dcs[0].meandepth.mm, true, true);
} else if (property == "divemaster") {
return d->diveguide;
} else if (property == "diveguide") {

View file

@ -1056,7 +1056,7 @@ parsed:
// add a hundred years.
if (newDate.addYears(100) < QDateTime::currentDateTime().addYears(1))
newDate = newDate.addYears(100);
d->dc.when = d->when = dateTimeToTimestamp(newDate);
d->dcs[0].when = d->when = dateTimeToTimestamp(newDate);
return true;
}
appendTextToLog("none of our parsing attempts worked for the date string");
@ -1134,9 +1134,9 @@ bool QMLManager::checkDuration(struct dive *d, QString duration)
} else if (m6.hasMatch()) {
m = m6.captured(1).toInt();
}
d->dc.duration.seconds = d->duration.seconds = h * 3600 + m * 60 + s;
if (is_dc_manually_added_dive(&d->dc))
d->dc.samples.clear();
d->dcs[0].duration.seconds = d->duration.seconds = h * 3600 + m * 60 + s;
if (is_dc_manually_added_dive(&d->dcs[0]))
d->dcs[0].samples.clear();
else
appendTextToLog("Cannot change the duration on a dive that wasn't manually added");
return true;
@ -1146,16 +1146,16 @@ bool QMLManager::checkDuration(struct dive *d, QString duration)
bool QMLManager::checkDepth(dive *d, QString depth)
{
if (get_depth_string(d->dc.maxdepth.mm, true, true) != depth) {
if (get_depth_string(d->dcs[0].maxdepth.mm, true, true) != depth) {
int depthValue = parseLengthToMm(depth);
// the QML code should stop negative depth, but massively huge depth can make
// the profile extremely slow or even run out of memory and crash, so keep
// the depth <= 500m
if (0 <= depthValue && depthValue <= 500000) {
d->maxdepth.mm = depthValue;
if (is_dc_manually_added_dive(&d->dc)) {
d->dc.maxdepth.mm = d->maxdepth.mm;
d->dc.samples.clear();
if (is_dc_manually_added_dive(&d->dcs[0])) {
d->dcs[0].maxdepth.mm = d->maxdepth.mm;
d->dcs[0].samples.clear();
}
return true;
}
@ -1356,16 +1356,16 @@ void QMLManager::commitChanges(QString diveId, QString number, QString date, QSt
// now that we have it all figured out, let's see what we need
// to update
if (diveChanged) {
if (d->maxdepth.mm == d->dc.maxdepth.mm &&
if (d->maxdepth.mm == d->dcs[0].maxdepth.mm &&
d->maxdepth.mm > 0 &&
is_dc_manually_added_dive(&d->dc) &&
d->dc.samples.empty()) {
is_dc_manually_added_dive(&d->dcs[0]) &&
d->dcs[0].samples.empty()) {
// so we have depth > 0, a manually added dive and no samples
// let's create an actual profile so the desktop version can work it
// first clear out the mean depth (or the fake_dc() function tries
// to be too clever)
d->meandepth.mm = d->dc.meandepth.mm = 0;
fake_dc(&d->dc);
d->meandepth.mm = d->dcs[0].meandepth.mm = 0;
fake_dc(&d->dcs[0]);
}
fixup_dive(d);
Command::editDive(orig, d_ptr.release(), dsChange.createdDs.release(), dsChange.editDs, dsChange.location); // With release() we're giving up ownership
@ -1732,11 +1732,11 @@ int QMLManager::addDive()
struct dive d;
int diveId = d.id = dive_getUniqID();
d.when = QDateTime::currentMSecsSinceEpoch() / 1000L + gettimezoneoffset() + 3600;
d.dc.duration.seconds = 40 * 60;
d.dc.maxdepth.mm = M_OR_FT(15, 45);
d.dc.meandepth.mm = M_OR_FT(13, 39); // this creates a resonable looking safety stop
make_manually_added_dive_dc(&d.dc);
fake_dc(&d.dc);
d.dcs[0].duration.seconds = 40 * 60;
d.dcs[0].maxdepth.mm = M_OR_FT(15, 45);
d.dcs[0].meandepth.mm = M_OR_FT(13, 39); // this creates a resonable looking safety stop
make_manually_added_dive_dc(&d.dcs[0]);
fake_dc(&d.dcs[0]);
fixup_dive(&d);
// addDive takes over the dive and clears out the structure passed in

View file

@ -213,7 +213,7 @@ static bool ppGraphsEnabled(const struct divecomputer *dc, bool simplified)
// Update visibility of non-interactive chart features according to preferences
void ProfileScene::updateVisibility(bool diveHasHeartBeat, bool simplified)
{
const struct divecomputer *currentdc = get_dive_dc_const(d, dc);
const struct divecomputer *currentdc = get_dive_dc(d, dc);
if (!currentdc)
return;
bool ppGraphs = ppGraphsEnabled(currentdc, simplified);
@ -291,7 +291,7 @@ struct VerticalAxisLayout {
void ProfileScene::updateAxes(bool diveHasHeartBeat, bool simplified)
{
const struct divecomputer *currentdc = get_dive_dc_const(d, dc);
const struct divecomputer *currentdc = get_dive_dc(d, dc);
if (!currentdc)
return;
@ -428,7 +428,7 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsM
decoModelParameters->set(QString("GF %1/%2").arg(diveplan.gflow).arg(diveplan.gfhigh), getColor(PRESSURE_TEXT));
}
const struct divecomputer *currentdc = get_dive_dc_const(d, dc);
const struct divecomputer *currentdc = get_dive_dc(d, dc);
if (!currentdc || currentdc->samples.empty()) {
clear();
return;

View file

@ -534,7 +534,7 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
// figure out if we are ontop of the dive computer name in the profile
QGraphicsItem *sceneItem = itemAt(mapFromGlobal(event->globalPos()));
if (isDiveTextItem(sceneItem, profileScene->diveComputerText)) {
const struct divecomputer *currentdc = get_dive_dc_const(d, dc);
const struct divecomputer *currentdc = get_dive_dc(d, dc);
if (!currentdc->deviceid && dc == 0 && number_of_computers(d) == 1)
// nothing to do, can't rename, delete or reorder
return;
@ -580,7 +580,7 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
m.addAction(tr("Add bookmark"), [this, seconds]() { addBookmark(seconds); });
m.addAction(tr("Split dive into two"), [this, seconds]() { splitDive(seconds); });
divemode_loop loop(*get_dive_dc_const(d, dc));
divemode_loop loop(*get_dive_dc(d, dc));
divemode_t divemode = loop.next(seconds);
QMenu *changeMode = m.addMenu(tr("Change divemode"));
if (divemode != OC)
@ -648,7 +648,7 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
}
m2->addAction(tr("All event types"), this, &ProfileWidget2::unhideEventTypes);
}
const struct divecomputer *currentdc = get_dive_dc_const(d, dc);
const struct divecomputer *currentdc = get_dive_dc(d, dc);
if (currentdc && std::any_of(currentdc->events.begin(), currentdc->events.end(),
[] (auto &ev) { return ev.hidden; }))
m.addAction(tr("Unhide individually hidden events of this dive"), this, &ProfileWidget2::unhideEvents);

View file

@ -401,7 +401,7 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
if (get_o2(cyl.gasmix) + get_he(cyl.gasmix) > 1000)
cyl.gasmix.he.permille = 1000 - get_o2(cyl.gasmix);
pressure_t modpO2;
if (d->dc.divemode == PSCR)
if (d->dcs[0].divemode == PSCR)
modpO2.mbar = prefs.decopo2 + (1000 - get_o2(cyl.gasmix)) * SURFACE_PRESSURE *
prefs.o2consumption / prefs.decosac / prefs.pscr_ratio;
else

View file

@ -70,7 +70,7 @@ void DivePlannerPointsModel::createSimpleDive(struct dive *dIn)
clear_dive(d);
d->id = dive_getUniqID();
d->when = QDateTime::currentMSecsSinceEpoch() / 1000L + gettimezoneoffset() + 3600;
make_planner_dc(&d->dc);
make_planner_dc(&d->dcs[0]);
clear();
removeDeco();
@ -818,7 +818,7 @@ int DivePlannerPointsModel::addStop(int milimeters, int seconds, int cylinderid_
}
}
if (divemode == UNDEF_COMP_TYPE)
divemode = get_dive_dc_const(d, dcNr)->divemode;
divemode = get_dive_dc(d, dcNr)->divemode;
// add the new stop
beginInsertRows(QModelIndex(), row, row);

View file

@ -116,7 +116,7 @@ Stats::Stats() :
static void calculateDive(struct dive *dive, Stats &stats)
{
if (is_dc_planner(&dive->dc)) {
if (is_dc_planner(&dive->dcs[0])) {
stats.diveplans++;
return;
}

View file

@ -162,9 +162,9 @@ static int countPhotos(const struct dive *d)
static QString displayDuration(const struct dive *d)
{
if (prefs.units.show_units_table)
return get_dive_duration_string(d->duration.seconds, gettextFromC::tr("h"), gettextFromC::tr("min"), "", ":", d->dc.divemode == FREEDIVE);
return get_dive_duration_string(d->duration.seconds, gettextFromC::tr("h"), gettextFromC::tr("min"), "", ":", d->dcs[0].divemode == FREEDIVE);
else
return get_dive_duration_string(d->duration.seconds, "", "", "", ":", d->dc.divemode == FREEDIVE);
return get_dive_duration_string(d->duration.seconds, "", "", "", ":", d->dcs[0].divemode == FREEDIVE);
}
static QString displayTemperature(const struct dive *d, bool units)
@ -281,9 +281,9 @@ QVariant DiveTripModelBase::diveData(const struct dive *d, int column, int role)
case MobileListModel::IdRole: return d->id;
case MobileListModel::NumberRole: return d->number;
case MobileListModel::LocationRole: return QString::fromStdString(get_dive_location(d));
case MobileListModel::DepthRole: return get_depth_string(d->dc.maxdepth.mm, true, true);
case MobileListModel::DepthRole: return get_depth_string(d->dcs[0].maxdepth.mm, true, true);
case MobileListModel::DurationRole: return formatDiveDuration(d);
case MobileListModel::DepthDurationRole: return QStringLiteral("%1 / %2").arg(get_depth_string(d->dc.maxdepth.mm, true, true),
case MobileListModel::DepthDurationRole: return QStringLiteral("%1 / %2").arg(get_depth_string(d->dcs[0].maxdepth.mm, true, true),
formatDiveDuration(d));
case MobileListModel::RatingRole: return d->rating;
case MobileListModel::VizRole: return d->visibility;
@ -298,7 +298,7 @@ QVariant DiveTripModelBase::diveData(const struct dive *d, int column, int role)
case MobileListModel::NotesRole: return formatNotes(d);
case MobileListModel::GpsRole: return formatDiveGPS(d);
case MobileListModel::GpsDecimalRole: return format_gps_decimal(d);
case MobileListModel::NoDiveRole: return d->duration.seconds == 0 && d->dc.duration.seconds == 0;
case MobileListModel::NoDiveRole: return d->duration.seconds == 0 && d->dcs[0].duration.seconds == 0;
case MobileListModel::DiveSiteRole: return QVariant::fromValue(d->dive_site);
case MobileListModel::CylinderRole: return formatGetCylinder(d).join(", ");
case MobileListModel::GetCylinderRole: return formatGetCylinder(d);
@ -363,7 +363,7 @@ QVariant DiveTripModelBase::diveData(const struct dive *d, int column, int role)
case NOTES:
return QString(d->notes);
case DIVEMODE:
return QString(divemode_text_ui[(int)d->dc.divemode]);
return QString(divemode_text_ui[(int)d->dcs[0].divemode]);
}
break;
case Qt::DecorationRole:
@ -1780,6 +1780,6 @@ bool DiveTripModelList::lessThan(const QModelIndex &i1, const QModelIndex &i2) c
case NOTES:
return lessThanHelper(strCmp(d1->notes, d2->notes), row_diff);
case DIVEMODE:
return lessThanHelper((int)d1->dc.divemode - (int)d2->dc.divemode, row_diff);
return lessThanHelper((int)d1->dcs[0].divemode - (int)d2->dcs[0].divemode, row_diff);
}
}

View file

@ -696,9 +696,9 @@ static void smtk_parse_relations(MdbHandle *mdb, struct dive *dive, char *dive_i
else
concat(tmp, ", ", str);
if (str.find("SCR") != std::string::npos)
dive->dc.divemode = PSCR;
dive->dcs[0].divemode = PSCR;
else if (str.find("CCR") != std::string::npos)
dive->dc.divemode = CCR;
dive->dcs[0].divemode = CCR;
}
if (!tmp.empty())
concat(&dive->notes, "\n", format_string_std("Smartrak %s: %s", table_name, tmp.c_str()));
@ -759,11 +759,11 @@ static void smtk_parse_bookmarks(MdbHandle *mdb, struct dive *d, char *dive_idx)
if (same_string(table.get_data(0), dive_idx)) {
time = lrint(strtod(table.get_data(4), NULL) * 60);
const char *tmp = table.get_data(2);
ev = find_bookmark(d->dc, time);
ev = find_bookmark(d->dcs[0], time);
if (ev)
ev->name = tmp;
else
if (!add_event(&d->dc, time, SAMPLE_EVENT_BOOKMARK, 0, 0, tmp))
if (!add_event(&d->dcs[0], time, SAMPLE_EVENT_BOOKMARK, 0, 0, tmp))
report_error("[smtk-import] Error - Couldn't add bookmark, dive %d, Name = %s",
d->number, tmp);
}
@ -941,7 +941,7 @@ void smartrak_import(const char *file, struct divelog *log)
dc_fam = DC_FAMILY_UWATEC_ALADIN;
}
rc = prepare_data(dc_model, (char *)col[coln(DCNUMBER)]->bind_ptr, dc_fam, devdata);
smtkdive->dc.model = devdata.model;
smtkdive->dcs[0].model = devdata.model;
if (rc == DC_STATUS_SUCCESS && mdb_table.get_len(coln(PROFILE))) {
prf_buffer = static_cast<unsigned char *>(mdb_ole_read_full(mdb, col[coln(PROFILE)], &prf_length));
if (prf_length > 0) {
@ -959,16 +959,16 @@ void smartrak_import(const char *file, struct divelog *log)
} else {
/* Dives without profile samples (usual in older aladin series) */
report_error("[Warning][smartrak_import]\t No profile for dive %d", smtkdive->number);
smtkdive->dc.duration.seconds = smtkdive->duration.seconds = smtk_time_to_secs((char *)col[coln(DURATION)]->bind_ptr);
smtkdive->dc.maxdepth.mm = smtkdive->maxdepth.mm = lrint(strtod((char *)col[coln(MAXDEPTH)]->bind_ptr, NULL) * 1000);
smtkdive->dcs[0].duration.seconds = smtkdive->duration.seconds = smtk_time_to_secs((char *)col[coln(DURATION)]->bind_ptr);
smtkdive->dcs[0].maxdepth.mm = smtkdive->maxdepth.mm = lrint(strtod((char *)col[coln(MAXDEPTH)]->bind_ptr, NULL) * 1000);
}
free(hdr_buffer);
free(prf_buffer);
} else {
/* Manual dives or unknown DCs */
report_error("[Warning][smartrak_import]\t Manual or unknown dive computer for dive %d", smtkdive->number);
smtkdive->dc.duration.seconds = smtkdive->duration.seconds = smtk_time_to_secs((char *)col[coln(DURATION)]->bind_ptr);
smtkdive->dc.maxdepth.mm = smtkdive->maxdepth.mm = lrint(strtod((char *)col[coln(MAXDEPTH)]->bind_ptr, NULL) * 1000);
smtkdive->dcs[0].duration.seconds = smtkdive->duration.seconds = smtk_time_to_secs((char *)col[coln(DURATION)]->bind_ptr);
smtkdive->dcs[0].maxdepth.mm = smtkdive->maxdepth.mm = lrint(strtod((char *)col[coln(MAXDEPTH)]->bind_ptr, NULL) * 1000);
}
/*
* Cylinder and gasmixes completion.
@ -1009,8 +1009,8 @@ void smartrak_import(const char *file, struct divelog *log)
/* Date issues with libdc parser - Take date time from mdb */
smtk_date_to_tm((char *)col[coln(_DATE)]->bind_ptr, &tm_date);
smtk_time_to_tm((char *)col[coln(INTIME)]->bind_ptr, &tm_date);
smtkdive->dc.when = smtkdive->when = smtk_timegm(&tm_date);
smtkdive->dc.surfacetime.seconds = smtk_time_to_secs((char *)col[coln(INTVAL)]->bind_ptr);
smtkdive->dcs[0].when = smtkdive->when = smtk_timegm(&tm_date);
smtkdive->dcs[0].surfacetime.seconds = smtk_time_to_secs((char *)col[coln(INTVAL)]->bind_ptr);
/* Data that user may have registered manually if not supported by DC, or not parsed */
if (!smtkdive->airtemp.mkelvin)

View file

@ -1402,7 +1402,7 @@ struct DiveModeBinner : public SimpleBinner<DiveModeBinner, IntBin> {
return QString(divemode_text_ui[derived_bin(bin).value]);
}
int to_bin_value(const dive *d) const {
int res = (int)d->dc.divemode;
int res = (int)d->dcs[0].divemode;
return res >= 0 && res < NUM_DIVEMODE ? res : OC;
}
};
@ -1413,7 +1413,7 @@ struct DiveModeVariable : public StatsVariableTemplate<StatsVariable::Type::Disc
return StatsTranslations::tr("Dive mode");
}
QString diveCategories(const dive *d) const override {
int mode = (int)d->dc.divemode;
int mode = (int)d->dcs[0].divemode;
return mode >= 0 && mode < NUM_DIVEMODE ?
QString(divemode_text_ui[mode]) : QString();
}

View file

@ -195,7 +195,7 @@ void TestParse::testParseHUDC()
if (divelog.dives->nr > 0) {
struct dive *dive = divelog.dives->dives[divelog.dives->nr - 1];
dive->when = 1255152761;
dive->dc.when = 1255152761;
dive->dcs[0].when = 1255152761;
}
sort_dive_table(divelog.dives);

View file

@ -496,20 +496,20 @@ void TestPlan::testMetric()
while (!dp->minimum_gas.mbar && dp->next)
dp = dp->next;
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 148l);
QVERIFY(dive.dc.events.size() >= 2);
QVERIFY(dive.dcs[0].events.size() >= 2);
// check first gas change to EAN36 at 33m
struct event *ev = &dive.dc.events[0];
struct event *ev = &dive.dcs[0].events[0];
QCOMPARE(ev->gas.index, 1);
QCOMPARE(ev->value, 36);
QCOMPARE(get_depth_at_time(&dive.dc, ev->time.seconds), 33000);
QCOMPARE(get_depth_at_time(&dive.dcs[0], ev->time.seconds), 33000);
// check second gas change to Oxygen at 6m
ev = &dive.dc.events[1];
ev = &dive.dcs[0].events[1];
QVERIFY(ev != NULL);
QCOMPARE(ev->gas.index, 2);
QCOMPARE(ev->value, 100);
QCOMPARE(get_depth_at_time(&dive.dc, ev->time.seconds), 6000);
QCOMPARE(get_depth_at_time(&dive.dcs[0], ev->time.seconds), 6000);
// check expected run time of 109 minutes
QVERIFY(compareDecoTime(dive.dc.duration.seconds, 109u * 60u, 109u * 60u));
QVERIFY(compareDecoTime(dive.dcs[0].duration.seconds, 109u * 60u, 109u * 60u));
}
void TestPlan::testImperial()
@ -537,21 +537,20 @@ void TestPlan::testImperial()
while (!dp->minimum_gas.mbar && dp->next)
dp = dp->next;
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 155l);
QVERIFY(dive.dc.events.size() >= 2);
QVERIFY(dive.dcs[0].events.size() >= 2);
// check first gas change to EAN36 at 33m
struct event *ev = &dive.dc.events[0];
QVERIFY(ev != NULL);
struct event *ev = &dive.dcs[0].events[0];
QCOMPARE(ev->gas.index, 1);
QCOMPARE(ev->value, 36);
QCOMPARE(get_depth_at_time(&dive.dc, ev->time.seconds), 33528);
QCOMPARE(get_depth_at_time(&dive.dcs[0], ev->time.seconds), 33528);
// check second gas change to Oxygen at 6m
ev = &dive.dc.events[1];
ev = &dive.dcs[0].events[1];
QVERIFY(ev != NULL);
QCOMPARE(ev->gas.index, 2);
QCOMPARE(ev->value, 100);
QCOMPARE(get_depth_at_time(&dive.dc, ev->time.seconds), 6096);
QCOMPARE(get_depth_at_time(&dive.dcs[0], ev->time.seconds), 6096);
// check expected run time of 111 minutes
QVERIFY(compareDecoTime(dive.dc.duration.seconds, 111u * 60u - 2u, 111u * 60u - 2u));
QVERIFY(compareDecoTime(dive.dcs[0].duration.seconds, 111u * 60u - 2u, 111u * 60u - 2u));
}
void TestPlan::testVpmbMetric45m30minTx()
@ -581,7 +580,7 @@ void TestPlan::testVpmbMetric45m30minTx()
// print first ceiling
printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &dive) * 0.001));
// check benchmark run time of 141 minutes, and known Subsurface runtime of 139 minutes
//QVERIFY(compareDecoTime(dive.dc.duration.seconds, 141u * 60u + 20u, 139u * 60u + 20u));
//QVERIFY(compareDecoTime(dive.dcs[0].duration.seconds, 141u * 60u + 20u, 139u * 60u + 20u));
}
void TestPlan::testVpmbMetric60m10minTx()
@ -611,7 +610,7 @@ void TestPlan::testVpmbMetric60m10minTx()
// print first ceiling
printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &dive) * 0.001));
// check benchmark run time of 141 minutes, and known Subsurface runtime of 139 minutes
//QVERIFY(compareDecoTime(dive.dc.duration.seconds, 141u * 60u + 20u, 139u * 60u + 20u));
//QVERIFY(compareDecoTime(dive.dcs[0].duration.seconds, 141u * 60u + 20u, 139u * 60u + 20u));
}
void TestPlan::testVpmbMetric60m30minAir()
@ -641,7 +640,7 @@ void TestPlan::testVpmbMetric60m30minAir()
// print first ceiling
printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &dive) * 0.001));
// check benchmark run time of 141 minutes, and known Subsurface runtime of 139 minutes
QVERIFY(compareDecoTime(dive.dc.duration.seconds, 141u * 60u + 20u, 139u * 60u + 20u));
QVERIFY(compareDecoTime(dive.dcs[0].duration.seconds, 141u * 60u + 20u, 139u * 60u + 20u));
}
void TestPlan::testVpmbMetric60m30minEan50()
@ -670,15 +669,14 @@ void TestPlan::testVpmbMetric60m30minEan50()
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 155l);
// print first ceiling
printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &dive) * 0.001));
QVERIFY(dive.dc.events.size() >= 1);
QVERIFY(dive.dcs[0].events.size() >= 1);
// check first gas change to EAN50 at 21m
struct event *ev = &dive.dc.events[0];
QVERIFY(ev != NULL);
struct event *ev = &dive.dcs[0].events[0];
QCOMPARE(ev->gas.index, 1);
QCOMPARE(ev->value, 50);
QCOMPARE(get_depth_at_time(&dive.dc, ev->time.seconds), 21000);
QCOMPARE(get_depth_at_time(&dive.dcs[0], ev->time.seconds), 21000);
// check benchmark run time of 95 minutes, and known Subsurface runtime of 96 minutes
QVERIFY(compareDecoTime(dive.dc.duration.seconds, 95u * 60u + 20u, 96u * 60u + 20u));
QVERIFY(compareDecoTime(dive.dcs[0].duration.seconds, 95u * 60u + 20u, 96u * 60u + 20u));
}
void TestPlan::testVpmbMetric60m30minTx()
@ -708,14 +706,13 @@ void TestPlan::testVpmbMetric60m30minTx()
// print first ceiling
printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &dive) * 0.001));
// check first gas change to EAN50 at 21m
QVERIFY(dive.dc.events.size() >= 1);
struct event *ev = &dive.dc.events[0];
QVERIFY(ev != NULL);
QVERIFY(dive.dcs[0].events.size() >= 1);
struct event *ev = &dive.dcs[0].events[0];
QCOMPARE(ev->gas.index, 1);
QCOMPARE(ev->value, 50);
QCOMPARE(get_depth_at_time(&dive.dc, ev->time.seconds), 21000);
QCOMPARE(get_depth_at_time(&dive.dcs[0], ev->time.seconds), 21000);
// check benchmark run time of 89 minutes, and known Subsurface runtime of 89 minutes
QVERIFY(compareDecoTime(dive.dc.duration.seconds, 89u * 60u + 20u, 89u * 60u + 20u));
QVERIFY(compareDecoTime(dive.dcs[0].duration.seconds, 89u * 60u + 20u, 89u * 60u + 20u));
}
void TestPlan::testVpmbMetric100m60min()
@ -744,21 +741,20 @@ void TestPlan::testVpmbMetric100m60min()
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 157l);
// print first ceiling
printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &dive) * 0.001));
QVERIFY(dive.dc.events.size() >= 2);
QVERIFY(dive.dcs[0].events.size() >= 2);
// check first gas change to EAN50 at 21m
struct event *ev = &dive.dc.events[0];
QVERIFY(ev != NULL);
struct event *ev = &dive.dcs[0].events[0];
QCOMPARE(ev->gas.index, 1);
QCOMPARE(ev->value, 50);
QCOMPARE(get_depth_at_time(&dive.dc, ev->time.seconds), 21000);
QCOMPARE(get_depth_at_time(&dive.dcs[0], ev->time.seconds), 21000);
// check second gas change to Oxygen at 6m
ev = &dive.dc.events[1];
ev = &dive.dcs[0].events[1];
QVERIFY(ev != NULL);
QCOMPARE(ev->gas.index, 2);
QCOMPARE(ev->value, 100);
QCOMPARE(get_depth_at_time(&dive.dc, ev->time.seconds), 6000);
QCOMPARE(get_depth_at_time(&dive.dcs[0], ev->time.seconds), 6000);
// check benchmark run time of 311 minutes, and known Subsurface runtime of 314 minutes
QVERIFY(compareDecoTime(dive.dc.duration.seconds, 311u * 60u + 20u, 315u * 60u + 20u));
QVERIFY(compareDecoTime(dive.dcs[0].duration.seconds, 311u * 60u + 20u, 315u * 60u + 20u));
}
void TestPlan::testMultipleGases()
@ -782,9 +778,9 @@ void TestPlan::testMultipleGases()
#endif
gasmix gas;
gas = get_gasmix_at_time(dive, dive.dc, {20 * 60 + 1});
gas = get_gasmix_at_time(dive, dive.dcs[0], {20 * 60 + 1});
QCOMPARE(get_o2(gas), 110);
QVERIFY(compareDecoTime(dive.dc.duration.seconds, 2480u, 2480u));
QVERIFY(compareDecoTime(dive.dcs[0].duration.seconds, 2480u, 2480u));
}
void TestPlan::testVpmbMetricMultiLevelAir()
@ -814,7 +810,7 @@ void TestPlan::testVpmbMetricMultiLevelAir()
// print first ceiling
printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &dive) * 0.001));
// check benchmark run time of 167 minutes, and known Subsurface runtime of 169 minutes
QVERIFY(compareDecoTime(dive.dc.duration.seconds, 167u * 60u + 20u, 169u * 60u + 20u));
QVERIFY(compareDecoTime(dive.dcs[0].duration.seconds, 167u * 60u + 20u, 169u * 60u + 20u));
}
void TestPlan::testVpmbMetric100m10min()
@ -843,21 +839,21 @@ void TestPlan::testVpmbMetric100m10min()
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 175l);
// print first ceiling
printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &dive) * 0.001));
QVERIFY(dive.dc.events.size() >= 2);
QVERIFY(dive.dcs[0].events.size() >= 2);
// check first gas change to EAN50 at 21m
struct event *ev = &dive.dc.events[0];
struct event *ev = &dive.dcs[0].events[0];
QVERIFY(ev != NULL);
QCOMPARE(ev->gas.index, 1);
QCOMPARE(ev->value, 50);
QCOMPARE(get_depth_at_time(&dive.dc, ev->time.seconds), 21000);
QCOMPARE(get_depth_at_time(&dive.dcs[0], ev->time.seconds), 21000);
// check second gas change to Oxygen at 6m
ev = &dive.dc.events[1];
ev = &dive.dcs[0].events[1];
QVERIFY(ev != NULL);
QCOMPARE(ev->gas.index, 2);
QCOMPARE(ev->value, 100);
QCOMPARE(get_depth_at_time(&dive.dc, ev->time.seconds), 6000);
QCOMPARE(get_depth_at_time(&dive.dcs[0], ev->time.seconds), 6000);
// check benchmark run time of 58 minutes, and known Subsurface runtime of 57 minutes
QVERIFY(compareDecoTime(dive.dc.duration.seconds, 58u * 60u + 20u, 57u * 60u + 20u));
QVERIFY(compareDecoTime(dive.dcs[0].duration.seconds, 58u * 60u + 20u, 57u * 60u + 20u));
}
/* This tests that a previously calculated plan isn't affecting the calculations of the next plan.
@ -891,9 +887,9 @@ void TestPlan::testVpmbMetricRepeat()
// print first ceiling
printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &dive) * 0.001));
// check benchmark run time of 27 minutes, and known Subsurface runtime of 28 minutes
QVERIFY(compareDecoTime(dive.dc.duration.seconds, 27u * 60u + 20u, 27u * 60u + 20u));
QVERIFY(compareDecoTime(dive.dcs[0].duration.seconds, 27u * 60u + 20u, 27u * 60u + 20u));
int firstDiveRunTimeSeconds = dive.dc.duration.seconds;
int firstDiveRunTimeSeconds = dive.dcs[0].duration.seconds;
setupPlanVpmb100mTo70m30min(&testPlan);
plan(&test_deco_state, &testPlan, &dive, 0, 60, stoptable, cache, 1, 0);
@ -911,27 +907,27 @@ void TestPlan::testVpmbMetricRepeat()
QCOMPARE(lrint(dp->minimum_gas.mbar / 1000.0), 80l);
// print first ceiling
printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &dive) * 0.001));
QVERIFY(dive.dc.events.size() >= 3);
QVERIFY(dive.dcs[0].events.size() >= 3);
// check first gas change to 21/35 at 66m
struct event *ev = &dive.dc.events[0];
struct event *ev = &dive.dcs[0].events[0];
QVERIFY(ev != NULL);
QCOMPARE(ev->gas.index, 1);
QCOMPARE(ev->gas.mix.o2.permille, 210);
QCOMPARE(ev->gas.mix.he.permille, 350);
QCOMPARE(get_depth_at_time(&dive.dc, ev->time.seconds), 66000);
QCOMPARE(get_depth_at_time(&dive.dcs[0], ev->time.seconds), 66000);
// check second gas change to EAN50 at 21m
ev = &dive.dc.events[1];
ev = &dive.dcs[0].events[1];
QCOMPARE(ev->gas.index, 2);
QCOMPARE(ev->value, 50);
QCOMPARE(get_depth_at_time(&dive.dc, ev->time.seconds), 21000);
QCOMPARE(get_depth_at_time(&dive.dcs[0], ev->time.seconds), 21000);
// check third gas change to Oxygen at 6m
ev = &dive.dc.events[2];
ev = &dive.dcs[0].events[2];
QVERIFY(ev != NULL);
QCOMPARE(ev->gas.index, 3);
QCOMPARE(ev->value, 100);
QCOMPARE(get_depth_at_time(&dive.dc, ev->time.seconds), 6000);
QCOMPARE(get_depth_at_time(&dive.dcs[0], ev->time.seconds), 6000);
// we don't have a benchmark, known Subsurface runtime is 126 minutes
QVERIFY(compareDecoTime(dive.dc.duration.seconds, 127u * 60u + 20u, 127u * 60u + 20u));
QVERIFY(compareDecoTime(dive.dcs[0].duration.seconds, 127u * 60u + 20u, 127u * 60u + 20u));
setupPlanVpmb30m20min(&testPlan);
plan(&test_deco_state, &testPlan, &dive, 0, 60, stoptable, cache, 1, 0);
@ -951,7 +947,7 @@ void TestPlan::testVpmbMetricRepeat()
printf("First ceiling %.1f m\n", (mbar_to_depth(test_deco_state.first_ceiling_pressure.mbar, &dive) * 0.001));
// check runtime is exactly the same as the first time
int finalDiveRunTimeSeconds = dive.dc.duration.seconds;
int finalDiveRunTimeSeconds = dive.dcs[0].duration.seconds;
QCOMPARE(finalDiveRunTimeSeconds, firstDiveRunTimeSeconds);
}
@ -967,7 +963,7 @@ void TestPlan::testCcrBailoutGasSelection()
prefs.unit_system = METRIC;
prefs.units.length = units::METERS;
prefs.planner_deco_mode = BUEHLMANN;
dive.dc.divemode = CCR;
dive.dcs[0].divemode = CCR;
prefs.dobailout = true;
struct diveplan testPlan = {};
@ -982,22 +978,22 @@ void TestPlan::testCcrBailoutGasSelection()
#endif
// check diluent used
cylinder_t *cylinder = get_cylinder(&dive, get_cylinderid_at_time(&dive, &dive.dc, { 20 * 60 - 1 }));
cylinder_t *cylinder = get_cylinder(&dive, get_cylinderid_at_time(&dive, &dive.dcs[0], { 20 * 60 - 1 }));
QCOMPARE(cylinder->cylinder_use, DILUENT);
QCOMPARE(get_o2(cylinder->gasmix), 200);
// check deep bailout used
cylinder = get_cylinder(&dive, get_cylinderid_at_time(&dive, &dive.dc, { 20 * 60 + 1 }));
cylinder = get_cylinder(&dive, get_cylinderid_at_time(&dive, &dive.dcs[0], { 20 * 60 + 1 }));
QCOMPARE(cylinder->cylinder_use, OC_GAS);
QCOMPARE(get_o2(cylinder->gasmix), 190);
// check shallow bailout used
cylinder = get_cylinder(&dive, get_cylinderid_at_time(&dive, &dive.dc, { 30 * 60 }));
cylinder = get_cylinder(&dive, get_cylinderid_at_time(&dive, &dive.dcs[0], { 30 * 60 }));
QCOMPARE(cylinder->cylinder_use, OC_GAS);
QCOMPARE(get_o2(cylinder->gasmix), 530);
// check expected run time of 51 minutes
QVERIFY(compareDecoTime(dive.dc.duration.seconds, 51 * 60, 51 * 60));
QVERIFY(compareDecoTime(dive.dcs[0].duration.seconds, 51 * 60, 51 * 60));
}