diff --git a/.clang-format b/.clang-format index bd73416d4..e753e2b49 100644 --- a/.clang-format +++ b/.clang-format @@ -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 diff --git a/backend-shared/exportfuncs.cpp b/backend-shared/exportfuncs.cpp index ec459292a..65bf89155 100644 --- a/backend-shared/exportfuncs.cpp +++ b/backend-shared/exportfuncs.cpp @@ -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; diff --git a/commands/command_divelist.cpp b/commands/command_divelist.cpp index 08ef58d43..49f16b8bd 100644 --- a/commands/command_divelist.cpp +++ b/commands/command_divelist.cpp @@ -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 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; diff --git a/commands/command_edit.cpp b/commands/command_edit.cpp index d8a5dd08a..5d5976068 100644 --- a/commands/command_edit.cpp +++ b/commands/command_edit.cpp @@ -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; diff --git a/core/cochran.cpp b/core/cochran.cpp index 1fbcc92d6..d39d73ef7 100644 --- a/core/cochran.cpp +++ b/core/cochran.cpp @@ -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(); - dc = &dive->dc; + dc = &dive->dcs[0]; unsigned char *log = (buf + 0x4914); diff --git a/core/datatrak.cpp b/core/datatrak.cpp index 6f623e2b5..821692bbe 100644 --- a/core/datatrak.cpp +++ b/core/datatrak.cpp @@ -192,7 +192,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 @@ -240,19 +240,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; } /* @@ -260,7 +260,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 @@ -297,7 +297,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 @@ -350,14 +350,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 @@ -365,7 +365,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; @@ -405,7 +405,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; } /* @@ -520,7 +520,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 @@ -562,10 +562,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); diff --git a/core/device.cpp b/core/device.cpp index 4b4362794..1a9014510 100644 --- a/core/device.cpp +++ b/core/device.cpp @@ -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; } } diff --git a/core/dive.cpp b/core/dive.cpp index 4b45dcb63..d8abc574a 100644 --- a/core/dive.cpp +++ b/core/dive.cpp @@ -22,6 +22,7 @@ #include "range.h" #include "membuffer.h" #include "picture.h" +#include "range.h" #include "sample.h" #include "tag.h" #include "trip.h" @@ -41,7 +42,9 @@ const char *divemode_text[] = {"OC", "CCR", "PSCR", "Freedive"}; static double calculate_depth_to_mbarf(int depth, pressure_t surface_pressure, int salinity); -dive::dive() +// It's the "manually added" divecomputer. +// Even for dives without divecomputer, we allocate a divecomputer structure. +dive::dive() : dcs(1) { id = dive_getUniqID(); } @@ -151,30 +154,15 @@ int dive_getUniqID() return maxId; } -/* this is very different from the copy_dive_computer later in this file; - * this function actually makes full copies of the content */ -static void copy_dc(const struct divecomputer *sdc, struct divecomputer *ddc) -{ - *ddc = *sdc; -} +static void dc_cylinder_renumber(struct dive *dive, struct divecomputer &dc, const int mapping[]); -static void dc_cylinder_renumber(struct dive *dive, struct divecomputer *dc, const int mapping[]); - -/* copy dive computer list and renumber the cylinders - * space for the first divecomputer is provided by the - * caller, the remainder is allocated */ -static void copy_dc_renumber(struct dive *d, const struct divecomputer *sdc, struct divecomputer *ddc, const int cylinders_map[]) +/* copy dive computer list and renumber the cylinders */ +static void copy_dc_renumber(struct dive *d, const struct dive *s, const int cylinders_map[]) { - for (;;) { - *ddc = *sdc; - dc_cylinder_renumber(d, ddc, cylinders_map); - if (!sdc->next) - break; - sdc = sdc->next; - ddc->next = new divecomputer; - ddc = ddc->next; + for (const divecomputer &dc: s->dcs) { + d->dcs.push_back(dc); + dc_cylinder_renumber(d, d->dcs.back(), cylinders_map); } - ddc->next = NULL; } static void free_dive_structures(struct dive *d) @@ -189,7 +177,6 @@ static void free_dive_structures(struct dive *d) free(d->suit); /* free tags, additional dive computers, and pictures */ taglist_free(d->tag_list); - free_dive_dcs(&d->dc); clear_cylinder_table(&d->cylinders); free(d->cylinders.cylinders); clear_weightsystem_table(&d->weightsystems); @@ -213,7 +200,7 @@ void clear_dive(struct dive *d) /* make a true copy that is independent of the source dive; * all data structures are duplicated, so the copy can be modified without * any impact on the source */ -static void copy_dive_nodc(const struct dive *s, struct dive *d) +void copy_dive(const struct dive *s, struct dive *d) { clear_dive(d); /* simply copy things over, but then make actual copies of the @@ -235,20 +222,11 @@ static void copy_dive_nodc(const struct dive *s, struct dive *d) d->tag_list = taglist_copy(s->tag_list); } -void copy_dive(const struct dive *s, struct dive *d) +static void copy_dive_onedc(const struct dive *s, const struct divecomputer &sdc, struct dive *d) { - copy_dive_nodc(s, d); - - // Copy the first dc explicitly, then the list of subsequent dc's - d->dc = s->dc; - STRUCTURED_LIST_COPY(struct divecomputer, s->dc.next, d->dc.next, copy_dc); -} - -static void copy_dive_onedc(const struct dive *s, const struct divecomputer *sdc, struct dive *d) -{ - copy_dive_nodc(s, d); - d->dc = *sdc; - d->dc.next = NULL; + copy_dive(s, d); + d->dcs.clear(); + d->dcs.push_back(sdc); } /* make a clone of the source dive and clean out the source dive; @@ -303,7 +281,7 @@ void copy_events_until(const struct dive *sd, struct dive *dd, int dcNr, int tim if (!sd || !dd) return; - const struct divecomputer *s = &sd->dc; + const struct divecomputer *s = &sd->dcs[0]; struct divecomputer *d = get_dive_dc(dd, dcNr); if (!s || !d) @@ -712,13 +690,13 @@ static bool is_potentially_redundant(const struct event &event) pressure_t calculate_surface_pressure(const struct dive *dive) { - const struct divecomputer *dc; pressure_t res; int sum = 0, nr = 0; - for_each_relevant_dc(dive, dc) { - if (dc->surface_pressure.mbar) { - sum += dc->surface_pressure.mbar; + bool logged = is_logged(dive); + for (auto &dc: dive->dcs) { + if ((logged || !is_dc_planner(&dc)) && dc.surface_pressure.mbar) { + sum += dc.surface_pressure.mbar; nr++; } } @@ -744,14 +722,14 @@ pressure_t un_fixup_surface_pressure(const struct dive *d) static void fixup_water_salinity(struct dive *dive) { - struct divecomputer *dc; int sum = 0, nr = 0; - for_each_relevant_dc (dive, dc) { - if (dc->salinity) { - if (dc->salinity < 500) - dc->salinity += FRESHWATER_SALINITY; - sum += dc->salinity; + bool logged = is_logged(dive); + for (auto &dc: dive->dcs) { + if ((logged || !is_dc_planner(&dc)) && dc.salinity) { + if (dc.salinity < 500) + dc.salinity += FRESHWATER_SALINITY; + sum += dc.salinity; nr++; } } @@ -766,12 +744,12 @@ int get_dive_salinity(const struct dive *dive) static void fixup_meandepth(struct dive *dive) { - struct divecomputer *dc; int sum = 0, nr = 0; - for_each_relevant_dc (dive, dc) { - if (dc->meandepth.mm) { - sum += dc->meandepth.mm; + bool logged = is_logged(dive); + for (auto &dc: dive->dcs) { + if ((logged || !is_dc_planner(&dc)) && dc.meandepth.mm) { + sum += dc.meandepth.mm; nr++; } } @@ -782,11 +760,12 @@ static void fixup_meandepth(struct dive *dive) static void fixup_duration(struct dive *dive) { - struct divecomputer *dc; duration_t duration = { }; - for_each_relevant_dc (dive, dc) { - duration.seconds = std::max(duration.seconds, dc->duration.seconds); + bool logged = is_logged(dive); + for (auto &dc: dive->dcs) { + if (logged || !is_dc_planner(&dc)) + duration.seconds = std::max(duration.seconds, dc.duration.seconds); } dive->duration.seconds = duration.seconds; } @@ -794,13 +773,13 @@ static void fixup_duration(struct dive *dive) static void fixup_watertemp(struct dive *dive) { if (!dive->watertemp.mkelvin) - dive->watertemp.mkelvin = dc_watertemp(&dive->dc); + dive->watertemp = dc_watertemp(dive); } static void fixup_airtemp(struct dive *dive) { if (!dive->airtemp.mkelvin) - dive->airtemp.mkelvin = dc_airtemp(&dive->dc); + dive->airtemp = dc_airtemp(dive); } /* if the air temperature in the dive data is redundant to the one in its @@ -809,7 +788,7 @@ static void fixup_airtemp(struct dive *dive) static temperature_t un_fixup_airtemp(const struct dive *a) { temperature_t res = a->airtemp; - if (a->airtemp.mkelvin && a->airtemp.mkelvin == dc_airtemp(&a->dc)) + if (a->airtemp.mkelvin && a->airtemp.mkelvin == dc_airtemp(a).mkelvin) res.mkelvin = 0; return res; } @@ -827,15 +806,15 @@ static temperature_t un_fixup_airtemp(const struct dive *a) * seconds... that would be pretty pointless to plot the * profile with) */ -static void fixup_dc_events(struct divecomputer *dc) +static void fixup_dc_events(struct divecomputer &dc) { std::vector to_delete; - for (auto [idx, event]: enumerated_range(dc->events)) { + for (auto [idx, event]: enumerated_range(dc.events)) { if (!is_potentially_redundant(event)) continue; for (int idx2 = idx - 1; idx2 > 0; --idx2) { - const auto &prev = dc->events[idx2]; + const auto &prev = dc.events[idx2]; if (prev.name == event.name && prev.flags == event.flags && event.time.seconds - prev.time.seconds < 61) to_delete.push_back(idx); @@ -843,15 +822,15 @@ static void fixup_dc_events(struct divecomputer *dc) } // Delete from back to not invalidate indexes for (auto it = to_delete.rbegin(); it != to_delete.rend(); ++it) - dc->events.erase(dc->events.begin() + *it); + dc.events.erase(dc.events.begin() + *it); } -static int interpolate_depth(struct divecomputer *dc, int idx, int lastdepth, int lasttime, int now) +static int interpolate_depth(struct divecomputer &dc, int idx, int lastdepth, int lasttime, int now) { int nextdepth = lastdepth; int nexttime = now; - for (auto it = dc->samples.begin() + idx; it != dc->samples.end(); ++it) { + for (auto it = dc.samples.begin() + idx; it != dc.samples.end(); ++it) { if (it->depth.mm < 0) continue; nextdepth = it->depth.mm; @@ -861,16 +840,16 @@ static int interpolate_depth(struct divecomputer *dc, int idx, int lastdepth, in return interpolate(lastdepth, nextdepth, now-lasttime, nexttime-lasttime); } -static void fixup_dc_depths(struct dive *dive, struct divecomputer *dc) +static void fixup_dc_depths(struct dive *dive, struct divecomputer &dc) { - int maxdepth = dc->maxdepth.mm; + int maxdepth = dc.maxdepth.mm; int lasttime = 0, lastdepth = 0; - for (const auto [idx, sample]: enumerated_range(dc->samples)) { + for (const auto [idx, sample]: enumerated_range(dc.samples)) { int time = sample.time.seconds; int depth = sample.depth.mm; - if (depth < 0 && idx + 2 < static_cast(dc->samples.size())) { + if (depth < 0 && idx + 2 < static_cast(dc.samples.size())) { depth = interpolate_depth(dc, idx, lastdepth, lasttime, time); sample.depth.mm = depth; } @@ -886,15 +865,15 @@ static void fixup_dc_depths(struct dive *dive, struct divecomputer *dc) dive->maxcns = sample.cns; } - update_depth(&dc->maxdepth, maxdepth); - if (!is_logged(dive) || !is_dc_planner(dc)) + update_depth(&dc.maxdepth, maxdepth); + if (!is_logged(dive) || !is_dc_planner(&dc)) if (maxdepth > dive->maxdepth.mm) dive->maxdepth.mm = maxdepth; } -static void fixup_dc_ndl(struct divecomputer *dc) +static void fixup_dc_ndl(struct divecomputer &dc) { - for (auto &sample: dc->samples) { + for (auto &sample: dc.samples) { if (sample.ndl.seconds != 0) break; if (sample.ndl.seconds == 0) @@ -902,11 +881,11 @@ static void fixup_dc_ndl(struct divecomputer *dc) } } -static void fixup_dc_temp(struct dive *dive, struct divecomputer *dc) +static void fixup_dc_temp(struct dive *dive, struct divecomputer &dc) { int mintemp = 0, lasttemp = 0; - for (auto &sample: dc->samples) { + for (auto &sample: dc.samples) { int temp = sample.temperature.mkelvin; if (temp) { @@ -926,17 +905,17 @@ static void fixup_dc_temp(struct dive *dive, struct divecomputer *dc) update_min_max_temperatures(dive, sample.temperature); } - update_temperature(&dc->watertemp, mintemp); - update_min_max_temperatures(dive, dc->watertemp); + update_temperature(&dc.watertemp, mintemp); + update_min_max_temperatures(dive, dc.watertemp); } /* Remove redundant pressure information */ -static void simplify_dc_pressures(struct divecomputer *dc) +static void simplify_dc_pressures(struct divecomputer &dc) { int lastindex[2] = { -1, -1 }; int lastpressure[2] = { 0 }; - for (auto &sample: dc->samples) { + for (auto &sample: dc.samples) { int j; for (j = 0; j < MAX_SENSORS; j++) { @@ -986,10 +965,10 @@ static void fixup_end_pressure(struct dive *dive, int idx, pressure_t p) * for computers like the Uemis Zurich that end up saving * quite a bit of samples after the dive has ended). */ -static void fixup_dive_pressures(struct dive *dive, struct divecomputer *dc) +static void fixup_dive_pressures(struct dive *dive, struct divecomputer &dc) { /* Walk the samples from the beginning to find starting pressures.. */ - for (auto &sample: dc->samples) { + for (auto &sample: dc.samples) { if (sample.depth.mm < SURFACE_THRESHOLD) continue; @@ -998,7 +977,7 @@ static void fixup_dive_pressures(struct dive *dive, struct divecomputer *dc) } /* ..and from the end for ending pressures */ - for (auto it = dc->samples.rbegin(); it != dc->samples.rend(); ++it) { + for (auto it = dc.samples.rbegin(); it != dc.samples.rend(); ++it) { if (it->depth.mm < SURFACE_THRESHOLD) continue; @@ -1056,22 +1035,22 @@ static bool validate_event(struct dive *dive, struct event &event) return true; } -static void fixup_dc_gasswitch(struct dive *dive, struct divecomputer *dc) +static void fixup_dc_gasswitch(struct dive *dive, struct divecomputer &dc) { // erase-remove idiom - auto &events = dc->events; + auto &events = dc.events; events.erase(std::remove_if(events.begin(), events.end(), [dive](auto &ev) { return !validate_event(dive, ev); }), events.end()); } -static void fixup_no_o2sensors(struct divecomputer *dc) +static void fixup_no_o2sensors(struct divecomputer &dc) { // Its only relevant to look for sensor values on CCR and PSCR dives without any no_o2sensors recorded. - if (dc->no_o2sensors != 0 || !(dc->divemode == CCR || dc->divemode == PSCR)) + if (dc.no_o2sensors != 0 || !(dc.divemode == CCR || dc.divemode == PSCR)) return; - for (const auto &sample: dc->samples) { + for (const auto &sample: dc.samples) { int nsensor = 0; // How many o2 sensors can we find in this sample? @@ -1080,8 +1059,8 @@ static void fixup_no_o2sensors(struct divecomputer *dc) nsensor++; // If we fond more than the previous found max, record it. - if (nsensor > dc->no_o2sensors) - dc->no_o2sensors = nsensor; + if (nsensor > dc.no_o2sensors) + dc.no_o2sensors = nsensor; // Already found the maximum posible amount. if (nsensor == MAX_O2_SENSORS) @@ -1089,11 +1068,11 @@ static void fixup_no_o2sensors(struct divecomputer *dc) } } -static void fixup_dc_sample_sensors(struct dive *dive, struct divecomputer *dc) +static void fixup_dc_sample_sensors(struct dive *dive, struct divecomputer &dc) { unsigned long sensor_mask = 0; - for (auto &sample: dc->samples) { + for (auto &sample: dc.samples) { for (int j = 0; j < MAX_SENSORS; j++) { int sensor = sample.sensor[j]; @@ -1125,7 +1104,7 @@ static void fixup_dc_sample_sensors(struct dive *dive, struct divecomputer *dc) } } -static void fixup_dive_dc(struct dive *dive, struct divecomputer *dc) +static void fixup_dive_dc(struct dive *dive, struct divecomputer &dc) { /* Fixup duration and mean depth */ fixup_dc_duration(dc); @@ -1154,14 +1133,13 @@ static void fixup_dive_dc(struct dive *dive, struct divecomputer *dc) fixup_no_o2sensors(dc); /* If there are no samples, generate a fake profile based on depth and time */ - if (dc->samples.empty()) - fake_dc(dc); + if (dc.samples.empty()) + fake_dc(&dc); } struct dive *fixup_dive(struct dive *dive) { int i; - struct divecomputer *dc; sanitize_cylinder_info(dive); dive->maxcns = dive->cns; @@ -1173,7 +1151,7 @@ struct dive *fixup_dive(struct dive *dive) update_min_max_temperatures(dive, dive->watertemp); - for_each_dc (dive, dc) + for (auto &dc: dive->dcs) fixup_dive_dc(dive, dc); fixup_water_salinity(dive); @@ -1574,19 +1552,19 @@ static void event_renumber(struct event &ev, const int mapping[]) ev.gas.index = mapping[ev.gas.index]; } -static void dc_cylinder_renumber(struct dive *dive, struct divecomputer *dc, const int mapping[]) +static void dc_cylinder_renumber(struct dive *dive, struct divecomputer &dc, const int mapping[]) { /* Remap or delete the sensor indices */ - for (auto [i, sample]: enumerated_range(dc->samples)) - sample_renumber(sample, i > 0 ? &dc->samples[i-1] : nullptr, mapping); + for (auto [i, sample]: enumerated_range(dc.samples)) + sample_renumber(sample, i > 0 ? &dc.samples[i-1] : nullptr, mapping); /* Remap the gas change indices */ - for (auto &ev: dc->events) + for (auto &ev: dc.events) event_renumber(ev, mapping); /* If the initial cylinder of a dive was remapped, add a gas change event to that cylinder */ if (mapping[0] > 0) - add_initial_gaschange(dive, dc, 0, mapping[0]); + add_initial_gaschange(dive, &dc, 0, mapping[0]); } /* @@ -1599,8 +1577,7 @@ static void dc_cylinder_renumber(struct dive *dive, struct divecomputer *dc, con */ void cylinder_renumber(struct dive *dive, int mapping[]) { - struct divecomputer *dc; - for_each_dc (dive, dc) + for (auto &dc: dive->dcs) dc_cylinder_renumber(dive, dc, mapping); } @@ -2094,18 +2071,15 @@ static int similar(unsigned long a, unsigned long b, unsigned long expected) * 0 for "don't know" * 1 for "is definitely the same dive" */ -static int match_dc_dive(const struct divecomputer *a, const struct divecomputer *b) +static int match_dc_dive(const struct dive &a, const struct dive &b) { - do { - const struct divecomputer *tmp = b; - do { - int match = match_one_dc(a, tmp); + for (auto &dc1: a.dcs) { + for (auto &dc2: b.dcs) { + int match = match_one_dc(dc1, dc2); if (match) return match; - tmp = tmp->next; - } while (tmp); - a = a->next; - } while (a); + } + } return 0; } @@ -2143,8 +2117,8 @@ static int likely_same_dive(const struct dive *a, const struct dive *b) int match, fuzz = 20 * 60; /* don't merge manually added dives with anything */ - if (is_dc_manually_added_dive(&a->dc) || - is_dc_manually_added_dive(&b->dc)) + if (is_dc_manually_added_dive(&a->dcs[0]) || + is_dc_manually_added_dive(&b->dcs[0])) return 0; /* @@ -2158,7 +2132,7 @@ static int likely_same_dive(const struct dive *a, const struct dive *b) return 0; /* See if we can get an exact match on the dive computer */ - match = match_dc_dive(&a->dc, &b->dc); + match = match_dc_dive(*a, *b); if (match) return match > 0; @@ -2212,79 +2186,69 @@ static bool operator==(const sample &a, const sample &b) return a.sensor[0] == b.sensor[0]; } -static int same_dc(struct divecomputer *a, struct divecomputer *b) +static int same_dc(const struct divecomputer &a, const struct divecomputer &b) { int i; i = match_one_dc(a, b); if (i) return i > 0; - if (a->when && b->when && a->when != b->when) + if (a.when && b.when && a.when != b.when) return 0; - if (a->samples != b->samples) + if (a.samples != b.samples) return 0; - return a->events == b->events; + return a.events == b.events; } -static int might_be_same_device(const struct divecomputer *a, const struct divecomputer *b) +static int might_be_same_device(const struct divecomputer &a, const struct divecomputer &b) { /* No dive computer model? That matches anything */ - if (a->model.empty() || b->model.empty()) + if (a.model.empty() || b.model.empty()) return 1; /* Otherwise at least the model names have to match */ - if (strcasecmp(a->model.c_str(), b->model.c_str())) + if (strcasecmp(a.model.c_str(), b.model.c_str())) return 0; /* No device ID? Match */ - if (!a->deviceid || !b->deviceid) + if (!a.deviceid || !b.deviceid) return 1; - return a->deviceid == b->deviceid; + return a.deviceid == b.deviceid; } -static void remove_redundant_dc(struct divecomputer *dc, int prefer_downloaded) +static void remove_redundant_dc(struct dive *d, bool prefer_downloaded) { - do { - struct divecomputer **p = &dc->next; + // Note: since the vector doesn't grow and we only erase + // elements after the iteratore, this is fine. + for (auto it = d->dcs.begin(); it != d->dcs.end(); ++it) { + // Remove all following DCs that compare as equal. + // Use the (infamous) erase-remove idiom. + auto it2 = std::remove_if(std::next(it), d->dcs.end(), + [d, prefer_downloaded, &it] (const divecomputer &dc) { + return same_dc(*it, dc) || + (prefer_downloaded && might_be_same_device(*it, dc)); + }); + d->dcs.erase(it2, d->dcs.end()); - /* Check this dc against all the following ones.. */ - while (*p) { - struct divecomputer *check = *p; - if (same_dc(dc, check) || (prefer_downloaded && might_be_same_device(dc, check))) { - *p = check->next; - check->next = NULL; - delete check; - continue; - } - p = &check->next; - } - - /* .. and then continue down the chain, but we */ - prefer_downloaded = 0; - dc = dc->next; - } while (dc); -} - -static const struct divecomputer *find_matching_computer(const struct divecomputer *match, const struct divecomputer *list) -{ - const struct divecomputer *p; - - while ((p = list) != NULL) { - list = list->next; - - if (might_be_same_device(match, p)) - break; + prefer_downloaded = false; } - return p; } -static void copy_dive_computer(struct divecomputer *res, const struct divecomputer *a) +static const struct divecomputer *find_matching_computer(const struct divecomputer &match, const struct dive *d) { - *res = *a; - res->samples.clear(); - res->events.clear(); - res->next = NULL; + for (const auto &dc: d->dcs) { + if (might_be_same_device(match, dc)) + return &dc; + } + return nullptr; +} + +static void copy_dive_computer(struct divecomputer &res, const struct divecomputer &a) +{ + res = a; + res.samples.clear(); + res.events.clear(); } /* @@ -2295,36 +2259,30 @@ static void copy_dive_computer(struct divecomputer *res, const struct divecomput * to match them up. If we find a matching dive computer, we * merge them. If not, we just take the data from 'a'. */ -static void interleave_dive_computers(struct dive *d, struct divecomputer *res, - const struct divecomputer *a, const struct divecomputer *b, +static void interleave_dive_computers(struct dive *res, + const struct dive *a, const struct dive *b, const int cylinders_map_a[], const int cylinders_map_b[], int offset) { - do { - const struct divecomputer *match; - - copy_dive_computer(res, a); - - match = find_matching_computer(a, b); + res->dcs.clear(); + for (const auto &dc1: a->dcs) { + res->dcs.emplace_back(); + divecomputer &newdc = res->dcs.back(); + copy_dive_computer(newdc, dc1); + const divecomputer *match = find_matching_computer(dc1, b); if (match) { - merge_events(d, res, a, match, cylinders_map_a, cylinders_map_b, offset); - merge_samples(res, a, match, cylinders_map_a, cylinders_map_b, offset); - merge_extra_data(res, a, match); + merge_events(res, &newdc, &dc1, match, cylinders_map_a, cylinders_map_b, offset); + merge_samples(&newdc, &dc1, match, cylinders_map_a, cylinders_map_b, offset); + merge_extra_data(&newdc, &dc1, match); /* Use the diveid of the later dive! */ if (offset > 0) - res->diveid = match->diveid; + newdc.diveid = match->diveid; } else { - copy_dc_renumber(d, a, res, cylinders_map_a); + dc_cylinder_renumber(res, res->dcs.back(), cylinders_map_a); } - a = a->next; - if (!a) - break; - res->next = new divecomputer; - res = res->next; - } while (res); + } } - /* * Join dive computer information. * @@ -2338,43 +2296,32 @@ static void interleave_dive_computers(struct dive *d, struct divecomputer *res, * try to throw out old information that *might* be from * that one. */ -static void join_dive_computers(struct dive *d, struct divecomputer *res, - const struct divecomputer *a, const struct divecomputer *b, +static void join_dive_computers(struct dive *d, + const struct dive *a, const struct dive *b, const int cylinders_map_a[], const int cylinders_map_b[], - int prefer_downloaded) + bool prefer_downloaded) { - struct divecomputer *tmp; - - if (!a->model.empty() && b->model.empty()) { - copy_dc_renumber(d, a, res, cylinders_map_a); + d->dcs.clear(); + if (!a->dcs[0].model.empty() && b->dcs[0].model.empty()) { + copy_dc_renumber(d, a, cylinders_map_a); return; } - if (!b->model.empty() && a->model.empty()) { - copy_dc_renumber(d, b, res, cylinders_map_b); + if (!b->dcs[0].model.empty() && a->dcs[0].model.empty()) { + copy_dc_renumber(d, b, cylinders_map_b); return; } - copy_dc_renumber(d, a, res, cylinders_map_a); - tmp = res; - while (tmp->next) - tmp = tmp->next; + copy_dc_renumber(d, a, cylinders_map_a); + copy_dc_renumber(d, b, cylinders_map_b); - tmp->next = new divecomputer; - copy_dc_renumber(d, b, tmp->next, cylinders_map_b); - - remove_redundant_dc(res, prefer_downloaded); + remove_redundant_dc(d, prefer_downloaded); } static bool has_dc_type(const struct dive *dive, bool dc_is_planner) { - const struct divecomputer *dc = &dive->dc; - - while (dc) { - if (is_dc_planner(dc) == dc_is_planner) - return true; - dc = dc->next; - } - return false; + return std::any_of(dive->dcs.begin(), dive->dcs.end(), + [dc_is_planner] (const divecomputer &dc) + { return is_dc_planner(&dc) == dc_is_planner; }); } // Does this dive have a dive computer for which is_dc_planner has value planned @@ -2432,7 +2379,7 @@ struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset, offset = 0; } - if (is_dc_planner(&a->dc)) { + if (is_dc_planner(&a->dcs[0])) { const struct dive *tmp = a; a = b; b = tmp; @@ -2463,11 +2410,12 @@ struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset, merge_temperatures(res, a, b); if (prefer_downloaded) { /* If we prefer downloaded, do those first, and get rid of "might be same" computers */ - join_dive_computers(res, &res->dc, &b->dc, &a->dc, cylinders_map_b.get(), cylinders_map_a.get(), 1); - } else if (offset && might_be_same_device(&a->dc, &b->dc)) - interleave_dive_computers(res, &res->dc, &a->dc, &b->dc, cylinders_map_a.get(), cylinders_map_b.get(), offset); - else - join_dive_computers(res, &res->dc, &a->dc, &b->dc, cylinders_map_a.get(), cylinders_map_b.get(), 0); + join_dive_computers(res, b, a, cylinders_map_b.get(), cylinders_map_a.get(), true); + } else if (offset && might_be_same_device(a->dcs[0], b->dcs[0])) { + interleave_dive_computers(res, a, b, cylinders_map_a.get(), cylinders_map_b.get(), offset); + } else { + join_dive_computers(res, a, b, cylinders_map_a.get(), cylinders_map_b.get(), false); + } /* The CNS values will be recalculated from the sample in fixup_dive() */ res->cns = res->maxcns = 0; @@ -2504,7 +2452,7 @@ struct start_end_pressure { static void force_fixup_dive(struct dive *d) { - struct divecomputer *dc = &d->dc; + struct divecomputer *dc = &d->dcs[0]; int old_temp = dc->watertemp.mkelvin; int old_mintemp = d->mintemp.mkelvin; int old_maxtemp = d->maxtemp.mkelvin; @@ -2569,7 +2517,7 @@ static int split_dive_at(const struct dive *dive, int a, int b, struct dive **ou return -1; /* Splitting should leave at least 3 samples per dive */ - if (a < 3 || static_cast(b + 4) > dive->dc.samples.size()) + if (a < 3 || static_cast(b + 4) > dive->dcs[0].samples.size()) return -1; /* We're not trying to be efficient here.. */ @@ -2582,8 +2530,8 @@ static int split_dive_at(const struct dive *dive, int a, int b, struct dive **ou * so the algorithm keeps splitting the dive further */ d1->selected = false; - dc1 = &d1->dc; - dc2 = &d2->dc; + dc1 = &d1->dcs[0]; + dc2 = &d2->dcs[0]; /* * Cut off the samples of d1 at the beginning * of the interval. @@ -2595,44 +2543,45 @@ static int split_dive_at(const struct dive *dive, int a, int b, struct dive **ou /* Now the secondary dive computers */ t = dc2->samples[0].time.seconds; - while ((dc1 = dc1->next)) { - auto it = std::find_if(dc1->samples.begin(), dc1->samples.end(), + for (auto it1 = d1->dcs.begin() + 1; it1 != d1->dcs.end(); ++it1) { + auto it = std::find_if(it1->samples.begin(), it1->samples.end(), [t](auto &sample) { return sample.time.seconds >= t; }); - dc1->samples.erase(it, dc1->samples.end()); + it1->samples.erase(it, it1->samples.end()); } - while ((dc2 = dc2->next)) { - auto it = std::find_if(dc2->samples.begin(), dc2->samples.end(), + for (auto it2 = d2->dcs.begin() + 1; it2 != d2->dcs.end(); ++it2) { + auto it = std::find_if(it2->samples.begin(), it2->samples.end(), [t](auto &sample) { return sample.time.seconds >= t; }); - dc2->samples.erase(dc2->samples.begin(), it); + it2->samples.erase(it2->samples.begin(), it); } - dc1 = &d1->dc; - dc2 = &d2->dc; + /* * This is where we cut off events from d1, * and shift everything in d2 */ d2->when += t; - while (dc1 && dc2) { - dc2->when += t; - for (auto &sample: dc2->samples) + auto it1 = d1->dcs.begin(); + auto it2 = d2->dcs.begin(); + while (it1 != d1->dcs.end() && it2 != d2->dcs.end()) { + it2->when += t; + for (auto &sample: it2->samples) sample.time.seconds -= t; /* Remove the events past 't' from d1 */ - auto it = std::lower_bound(dc1->events.begin(), dc1->events.end(), t, + auto it = std::lower_bound(it1->events.begin(), it1->events.end(), t, [] (struct event &ev, int t) { return ev.time.seconds < t; }); - dc1->events.erase(it, dc1->events.end()); + it1->events.erase(it, it1->events.end()); /* Remove the events before 't' from d2, and shift the rest */ - it = std::lower_bound(dc2->events.begin(), dc2->events.end(), t, + it = std::lower_bound(it2->events.begin(), it2->events.end(), t, [] (struct event &ev, int t) { return ev.time.seconds < t; }); - dc2->events.erase(dc2->events.begin(), it); - for (auto &ev: dc2->events) + it2->events.erase(it2->events.begin(), it); + for (auto &ev: it2->events) ev.time.seconds -= t; - dc1 = dc1->next; - dc2 = dc2->next; + ++it1; + ++it2; } force_fixup_dive(d1); @@ -2680,7 +2629,7 @@ int split_dive(const struct dive *dive, struct dive **new1, struct dive **new2) if (!dive) return -1; - const struct divecomputer *dc = &dive->dc; + const struct divecomputer *dc = &dive->dcs[0]; bool at_surface = true; if (dc->samples.empty()) return -1; @@ -2719,11 +2668,11 @@ int split_dive_at_time(const struct dive *dive, duration_t time, struct dive **n if (!dive) return -1; - auto it = std::find_if(dive->dc.samples.begin(), dive->dc.samples.end(), + auto it = std::find_if(dive->dcs[0].samples.begin(), dive->dcs[0].samples.end(), [time](auto &sample) { return sample.time.seconds >= time.seconds; }); - if (it == dive->dc.samples.end()) + if (it == dive->dcs[0].samples.end()) return -1; - size_t idx = it - dive->dc.samples.begin(); + size_t idx = it - dive->dcs[0].samples.begin(); if (idx < 1) return -1; return split_dive_at(dive, static_cast(idx), static_cast(idx - 1), new1, new2); @@ -2737,11 +2686,11 @@ int split_dive_at_time(const struct dive *dive, duration_t time, struct dive **n * Still, we do ignore all but the last surface samples from the * end, because some divecomputers just generate lots of them. */ -static inline int dc_totaltime(const struct divecomputer *dc) +static inline int dc_totaltime(const struct divecomputer &dc) { - int time = dc->duration.seconds; + int time = dc.duration.seconds; - for (auto it = dc->samples.rbegin(); it != dc->samples.rend(); ++it) { + for (auto it = dc.samples.rbegin(); it != dc.samples.rend(); ++it) { time = it->time.seconds; if (it->depth.mm >= SURFACE_THRESHOLD) break; @@ -2762,12 +2711,14 @@ static inline int dc_totaltime(const struct divecomputer *dc) static inline int dive_totaltime(const struct dive *dive) { int time = dive->duration.seconds; - const struct divecomputer *dc; - for_each_relevant_dc(dive, dc) { - int dc_time = dc_totaltime(dc); - if (dc_time > time) - time = dc_time; + bool logged = is_logged(dive); + for (auto &dc: dive->dcs) { + if (logged || !is_dc_planner(&dc)) { + int dc_time = dc_totaltime(dc); + if (dc_time > time) + time = dc_time; + } } return time; } @@ -2845,8 +2796,6 @@ void set_git_prefs(const char *prefs) /* clones a dive and moves given dive computer to front */ struct dive *make_first_dc(const struct dive *d, int dc_number) { - struct divecomputer *dc, *newdc, *old_dc; - /* copy the dive */ dive *res = new dive; copy_dive(d, res); @@ -2857,54 +2806,24 @@ struct dive *make_first_dc(const struct dive *d, int dc_number) if (dc_number == 0) return res; - dc = &res->dc; - newdc = (divecomputer *)malloc(sizeof(*newdc)); - old_dc = get_dive_dc(res, dc_number); - - /* skip the current DC in the linked list */ - for (dc = &res->dc; dc && dc->next != old_dc; dc = dc->next) - ; - if (!dc) { - free(newdc); - report_info("data inconsistent: can't find the current DC"); - return res; - } - dc->next = old_dc->next; - *newdc = res->dc; - res->dc = *old_dc; - res->dc.next = newdc; - free(old_dc); + move_in_range(res->dcs, dc_number, dc_number + 1, 0); return res; } static void delete_divecomputer(struct dive *d, int num) { - int i; - /* Refuse to delete the last dive computer */ - if (!d->dc.next) + if (d->dcs.size() <= 1) return; - if (num == 0) { - /* During our move to C++, copy the divecomputer instead of moving the internals. - * Yes, this is "inefficient", but I don't care. Will be removed anyways. */ - struct divecomputer *fdc = d->dc.next; - d->dc = *fdc; - delete fdc; - } else { - struct divecomputer *pdc = &d->dc; - for (i = 0; i < num - 1 && pdc; i++) - pdc = pdc->next; - if (pdc && pdc->next) { - struct divecomputer *dc = pdc->next; - pdc->next = dc->next; - delete dc; - } - } + if (num < 0 || num >= (int)d->dcs.size()) + return; + + d->dcs.erase(d->dcs.begin() + num); } -/* Clone a dive and delete goven dive computer */ +/* Clone a dive and delete given dive computer */ struct dive *clone_delete_divecomputer(const struct dive *d, int dc_number) { /* copy the dive */ @@ -2928,12 +2847,12 @@ struct dive *clone_delete_divecomputer(const struct dive *d, int dc_number) */ void split_divecomputer(const struct dive *src, int num, struct dive **out1, struct dive **out2) { - const struct divecomputer *srcdc = get_dive_dc_const(src, num); + const struct divecomputer *srcdc = get_dive_dc(src, num); if (src && srcdc) { // Copy the dive, but only using the selected dive computer *out2 = new dive; - copy_dive_onedc(src, srcdc, *out2); + copy_dive_onedc(src, *srcdc, *out2); // This will also make fixup_dive() to allocate a new dive id... (*out2)->id = 0; @@ -3036,10 +2955,10 @@ int depth_to_mbar(int depth, const struct dive *dive) double depth_to_mbarf(int depth, const struct dive *dive) { // For downloaded and planned dives, use DC's values - int salinity = dive->dc.salinity; - pressure_t surface_pressure = dive->dc.surface_pressure; + int salinity = dive->dcs[0].salinity; + pressure_t surface_pressure = dive->dcs[0].surface_pressure; - if (is_dc_manually_added_dive(&dive->dc)) { // For manual dives, salinity and pressure in another place... + if (is_dc_manually_added_dive(&dive->dcs[0])) { // For manual dives, salinity and pressure in another place... surface_pressure = dive->surface_pressure; salinity = dive->user_salinity; } @@ -3063,7 +2982,7 @@ double depth_to_atm(int depth, const struct dive *dive) int rel_mbar_to_depth(int mbar, const struct dive *dive) { // For downloaded and planned dives, use DC's salinity. Manual dives, use user's salinity - int salinity = is_dc_manually_added_dive(&dive->dc) ? dive->user_salinity : dive->dc.salinity; + int salinity = is_dc_manually_added_dive(&dive->dcs[0]) ? dive->user_salinity : dive->dcs[0].salinity; if (!salinity) salinity = SEAWATER_SALINITY; @@ -3075,9 +2994,9 @@ int rel_mbar_to_depth(int mbar, const struct dive *dive) int mbar_to_depth(int mbar, const struct dive *dive) { // For downloaded and planned dives, use DC's pressure. Manual dives, use user's pressure - pressure_t surface_pressure = is_dc_manually_added_dive(&dive->dc) + pressure_t surface_pressure = is_dc_manually_added_dive(&dive->dcs[0]) ? dive->surface_pressure - : dive->dc.surface_pressure; + : dive->dcs[0].surface_pressure; if (!surface_pressure.mbar) surface_pressure.mbar = SURFACE_PRESSURE; @@ -3140,35 +3059,18 @@ std::string get_dive_location(const struct dive *dive) unsigned int number_of_computers(const struct dive *dive) { - unsigned int total_number = 0; - const struct divecomputer *dc = &dive->dc; - - if (!dive) - return 1; - - do { - total_number++; - dc = dc->next; - } while (dc); - return total_number; + return dive ? static_cast(dive->dcs.size()) : 1; } struct divecomputer *get_dive_dc(struct dive *dive, int nr) { - struct divecomputer *dc; - if (!dive) + if (!dive || dive->dcs.empty()) return NULL; - dc = &dive->dc; - - while (nr-- > 0) { - dc = dc->next; - if (!dc) - return &dive->dc; - } - return dc; + nr = std::max(0, nr); + return &dive->dcs[static_cast(nr) % dive->dcs.size()]; } -const struct divecomputer *get_dive_dc_const(const struct dive *dive, int nr) +const struct divecomputer *get_dive_dc(const struct dive *dive, int nr) { return get_dive_dc((struct dive *)dive, nr); } @@ -3251,10 +3153,8 @@ static location_t dc_get_gps_location(const struct divecomputer *dc) */ location_t dive_get_gps_location(const struct dive *d) { - location_t res = { }; - - for (const struct divecomputer *dc = &d->dc; dc; dc = dc->next) { - res = dc_get_gps_location(dc); + for (const struct divecomputer &dc: d->dcs) { + location_t res = dc_get_gps_location(&dc); if (has_location(&res)) return res; } @@ -3263,9 +3163,9 @@ location_t dive_get_gps_location(const struct dive *d) * Let's use the location of the current dive site. */ if (d->dive_site) - res = d->dive_site->location; + return d->dive_site->location; - return res; + return location_t(); } gasmix_loop::gasmix_loop(const struct dive &d, const struct divecomputer &dc) : @@ -3304,8 +3204,8 @@ struct gasmix get_gasmix_at_time(const struct dive &d, const struct divecomputer /* Does that cylinder have any pressure readings? */ bool cylinder_with_sensor_sample(const struct dive *dive, int cylinder_id) { - for (const struct divecomputer *dc = &dive->dc; dc; dc = dc->next) { - for (const auto &sample: dc->samples) { + for (const auto &dc: dive->dcs) { + for (const auto &sample: dc.samples) { for (int j = 0; j < MAX_SENSORS; ++j) { if (!sample.pressure[j].mbar) continue; @@ -3316,3 +3216,40 @@ bool cylinder_with_sensor_sample(const struct dive *dive, int cylinder_id) } return false; } + +/* + * What do the dive computers say the water temperature is? + * (not in the samples, but as dc property for dcs that support that) + */ +temperature_t dc_watertemp(const struct dive *d) +{ + int sum = 0, nr = 0; + + for (auto &dc: d->dcs) { + if (dc.watertemp.mkelvin) { + sum += dc.watertemp.mkelvin; + nr++; + } + } + if (!nr) + return temperature_t(); + return temperature_t{ static_cast((sum + nr / 2) / nr) }; +} + +/* + * What do the dive computers say the air temperature is? + */ +temperature_t dc_airtemp(const struct dive *d) +{ + int sum = 0, nr = 0; + + for (auto &dc: d->dcs) { + if (dc.airtemp.mkelvin) { + sum += dc.airtemp.mkelvin; + nr++; + } + } + if (!nr) + return temperature_t(); + return temperature_t{ static_cast((sum + nr / 2) / nr) }; +} diff --git a/core/dive.h b/core/dive.h index 3d63aa153..2e3747856 100644 --- a/core/dive.h +++ b/core/dive.h @@ -10,6 +10,7 @@ #include "picture.h" // TODO: remove #include +#include 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 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); diff --git a/core/divecomputer.cpp b/core/divecomputer.cpp index 63addf3be..ac4dbdd33 100644 --- a/core/divecomputer.cpp +++ b/core/divecomputer.cpp @@ -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"; diff --git a/core/divecomputer.h b/core/divecomputer.h index b7f0d338c..8d2c510ef 100644 --- a/core/divecomputer.h +++ b/core/divecomputer.h @@ -43,10 +43,10 @@ struct divecomputer { std::vector samples; std::vector events; std::vector 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 diff --git a/core/divelist.cpp b/core/divelist.cpp index 8042ea84e..c9ecb1525 100644 --- a/core/divelist.cpp +++ b/core/divelist.cpp @@ -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; @@ -1401,15 +1403,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; } diff --git a/core/filterconstraint.cpp b/core/filterconstraint.cpp index 17a8b8e8b..402fd21ad 100644 --- a/core/filterconstraint.cpp +++ b/core/filterconstraint.cpp @@ -820,7 +820,7 @@ static bool has_tags(const filter_constraint &c, const struct dive *d) QStringList dive_tags; for (const tag_entry *tag = d->tag_list; tag; tag = tag->next) dive_tags.push_back(QString::fromStdString(tag->tag->name).trimmed()); - dive_tags.append(gettextFromC::tr(divemode_text_ui[d->dc.divemode]).trimmed()); + dive_tags.append(gettextFromC::tr(divemode_text_ui[d->dcs[0].divemode]).trimmed()); return check(c, dive_tags); } @@ -1078,7 +1078,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: diff --git a/core/import-cobalt.cpp b/core/import-cobalt.cpp index bae68b9e9..43e8c0e14 100644 --- a/core/import-cobalt.cpp +++ b/core/import-cobalt.cpp @@ -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); diff --git a/core/import-csv.cpp b/core/import-csv.cpp index b577777a0..56d6849b5 100644 --- a/core/import-csv.cpp +++ b/core/import-csv.cpp @@ -418,7 +418,7 @@ int try_to_open_csv(std::string &mem, enum csv_format type, struct divelog *log) auto dive = std::make_unique(); 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(); 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 diff --git a/core/import-divinglog.cpp b/core/import-divinglog.cpp index 224bb7ef8..6907caeb7 100644 --- a/core/import-divinglog.cpp +++ b/core/import-divinglog.cpp @@ -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); diff --git a/core/import-seac.cpp b/core/import-seac.cpp index d681f0b5e..1ff8bfba7 100644 --- a/core/import-seac.cpp +++ b/core/import-seac.cpp @@ -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); diff --git a/core/import-shearwater.cpp b/core/import-shearwater.cpp index 96f47300e..5ce5bbc3d 100644 --- a/core/import-shearwater.cpp +++ b/core/import-shearwater.cpp @@ -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; } } diff --git a/core/import-suunto.cpp b/core/import-suunto.cpp index 1dc23a3a1..4396c85dd 100644 --- a/core/import-suunto.cpp +++ b/core/import-suunto.cpp @@ -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]); diff --git a/core/libdivecomputer.cpp b/core/libdivecomputer.cpp index 992e37e74..2bf817a45 100644 --- a/core/libdivecomputer.cpp +++ b/core/libdivecomputer.cpp @@ -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(); // 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); diff --git a/core/liquivision.cpp b/core/liquivision.cpp index d09245c7a..ef2203596 100644 --- a/core/liquivision.cpp +++ b/core/liquivision.cpp @@ -143,7 +143,7 @@ static void parse_dives(int log_version, const unsigned char *buf, unsigned int int i; auto dive = std::make_unique(); 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++) { diff --git a/core/load-git.cpp b/core/load-git.cpp index fa92aff10..55333fd46 100644 --- a/core/load-git.cpp +++ b/core/load-git.cpp @@ -1639,15 +1639,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; diff --git a/core/ostctools.cpp b/core/ostctools.cpp index a1ec4bb9d..8f05a1e89 100644 --- a/core/ostctools.cpp +++ b/core/ostctools.cpp @@ -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()); diff --git a/core/parse-xml.cpp b/core/parse-xml.cpp index 4a85a58e0..b67827586 100644 --- a/core/parse-xml.cpp +++ b/core/parse-xml.cpp @@ -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)) diff --git a/core/parse.cpp b/core/parse.cpp index b6d2c9461..6859d1299 100644 --- a/core/parse.cpp +++ b/core/parse.cpp @@ -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(); - 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 */ diff --git a/core/planner.cpp b/core/planner.cpp index 6d7bf28aa..f6f856a43 100644 --- a/core/planner.cpp +++ b/core/planner.cpp @@ -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; } diff --git a/core/plannernotes.cpp b/core/plannernotes.cpp index 58b089aff..b47b8101f 100644 --- a/core/plannernotes.cpp +++ b/core/plannernotes.cpp @@ -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; diff --git a/core/profile.cpp b/core/profile.cpp index dd27218d1..fffb6108a 100644 --- a/core/profile.cpp +++ b/core/profile.cpp @@ -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 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 seen(num_cyl, 0); std::vector first(num_cyl, 0); std::vector 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; } diff --git a/core/save-git.cpp b/core/save-git.cpp index c19319d33..5c27b0a77 100644 --- a/core/save-git.cpp +++ b/core/save-git.cpp @@ -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()); diff --git a/core/save-html.cpp b/core/save-html.cpp index c5da45b3d..28ab7e579 100644 --- a/core/save-html.cpp +++ b/core/save-html.cpp @@ -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 = ", "; } diff --git a/core/save-profiledata.cpp b/core/save-profiledata.cpp index 06c22d190..e3ac11136 100644 --- a/core/save-profiledata.cpp +++ b/core/save-profiledata.cpp @@ -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()); diff --git a/core/save-xml.cpp b/core/save-xml.cpp index 4da3ed744..db8ec819b 100644 --- a/core/save-xml.cpp +++ b/core/save-xml.cpp @@ -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, " 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, "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, "\n"); diff --git a/core/statistics.cpp b/core/statistics.cpp index 055a0ba96..6b36209aa 100644 --- a/core/statistics.cpp +++ b/core/statistics.cpp @@ -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 */ diff --git a/core/string-format.cpp b/core/string-format.cpp index a81d35ae5..718865fa8 100644 --- a/core/string-format.cpp +++ b/core/string-format.cpp @@ -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 "\n" tmp.replace("", "" _NOTES_BR) diff --git a/core/uemis-downloader.cpp b/core/uemis-downloader.cpp index 9bbe5e028..4123367bf 100644 --- a/core/uemis-downloader.cpp +++ b/core/uemis-downloader.cpp @@ -188,15 +188,15 @@ static void uemis_get_weight(std::string_view buffer, weightsystem_t &weight, in static std::unique_ptr uemis_start_dive(uint32_t deviceid) { auto dive = std::make_unique(); - 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 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++; } diff --git a/core/uemis.cpp b/core/uemis.cpp index 1e7f1413b..33ec3539f 100644 --- a/core/uemis.cpp +++ b/core/uemis.cpp @@ -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", diff --git a/desktop-widgets/diveplanner.cpp b/desktop-widgets/diveplanner.cpp index 9ce1f6588..c848c01d3 100644 --- a/desktop-widgets/diveplanner.cpp +++ b/desktop-widgets/diveplanner.cpp @@ -564,7 +564,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) @@ -576,8 +576,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 diff --git a/desktop-widgets/mainwindow.cpp b/desktop-widgets/mainwindow.cpp index f8e711004..75bd9ba54 100644 --- a/desktop-widgets/mainwindow.cpp +++ b/desktop-widgets/mainwindow.cpp @@ -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); diff --git a/desktop-widgets/profilewidget.cpp b/desktop-widgets/profilewidget.cpp index 6d6e62f93..8fcb8f66d 100644 --- a/desktop-widgets/profilewidget.cpp +++ b/desktop-widgets/profilewidget.cpp @@ -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); diff --git a/desktop-widgets/tab-widgets/TabDiveInformation.cpp b/desktop-widgets/tab-widgets/TabDiveInformation.cpp index 98a23f3b0..bd3a82cbb 100644 --- a/desktop-widgets/tab-widgets/TabDiveInformation.cpp +++ b/desktop-widgets/tab-widgets/TabDiveInformation.cpp @@ -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 diff --git a/desktop-widgets/tab-widgets/TabDiveNotes.cpp b/desktop-widgets/tab-widgets/TabDiveNotes.cpp index 85174aa67..ddd678694 100644 --- a/desktop-widgets/tab-widgets/TabDiveNotes.cpp +++ b/desktop-widgets/tab-widgets/TabDiveNotes.cpp @@ -254,7 +254,7 @@ void TabDiveNotes::updateData(const std::vector &, 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(¤tDive->dc); + bool isManual = is_dc_manually_added_dive(¤tDive->dcs[0]); ui.depth->setVisible(isManual); ui.depthLabel->setVisible(isManual); ui.duration->setVisible(isManual); diff --git a/desktop-widgets/tab-widgets/TabDiveStatistics.cpp b/desktop-widgets/tab-widgets/TabDiveStatistics.cpp index 76b113b11..08f38357f 100644 --- a/desktop-widgets/tab-widgets/TabDiveStatistics.cpp +++ b/desktop-widgets/tab-widgets/TabDiveStatistics.cpp @@ -108,7 +108,7 @@ void TabDiveStatistics::updateData(const std::vector &, 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)); diff --git a/desktop-widgets/templatelayout.cpp b/desktop-widgets/templatelayout.cpp index 4278ea524..fb58f0629 100644 --- a/desktop-widgets/templatelayout.cpp +++ b/desktop-widgets/templatelayout.cpp @@ -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") { diff --git a/mobile-widgets/qmlmanager.cpp b/mobile-widgets/qmlmanager.cpp index cb8fe5ae7..40c5417de 100644 --- a/mobile-widgets/qmlmanager.cpp +++ b/mobile-widgets/qmlmanager.cpp @@ -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 diff --git a/profile-widget/profilescene.cpp b/profile-widget/profilescene.cpp index 566a11286..94ed17860 100644 --- a/profile-widget/profilescene.cpp +++ b/profile-widget/profilescene.cpp @@ -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; diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp index aef0f578f..0ff940d84 100644 --- a/profile-widget/profilewidget2.cpp +++ b/profile-widget/profilewidget2.cpp @@ -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); diff --git a/qt-models/cylindermodel.cpp b/qt-models/cylindermodel.cpp index 26a5df057..203d48ae7 100644 --- a/qt-models/cylindermodel.cpp +++ b/qt-models/cylindermodel.cpp @@ -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 diff --git a/qt-models/diveplannermodel.cpp b/qt-models/diveplannermodel.cpp index a32967b60..234b09fc3 100644 --- a/qt-models/diveplannermodel.cpp +++ b/qt-models/diveplannermodel.cpp @@ -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); diff --git a/qt-models/divesummarymodel.cpp b/qt-models/divesummarymodel.cpp index b679da1f0..a3345a396 100644 --- a/qt-models/divesummarymodel.cpp +++ b/qt-models/divesummarymodel.cpp @@ -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; } diff --git a/qt-models/divetripmodel.cpp b/qt-models/divetripmodel.cpp index e020fdd5b..d2d858ca1 100644 --- a/qt-models/divetripmodel.cpp +++ b/qt-models/divetripmodel.cpp @@ -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); } } diff --git a/smtk-import/smartrak.cpp b/smtk-import/smartrak.cpp index 252684e8e..5aeafee25 100644 --- a/smtk-import/smartrak.cpp +++ b/smtk-import/smartrak.cpp @@ -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(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) diff --git a/stats/statsvariables.cpp b/stats/statsvariables.cpp index b705f2716..c7a770838 100644 --- a/stats/statsvariables.cpp +++ b/stats/statsvariables.cpp @@ -1402,7 +1402,7 @@ struct DiveModeBinner : public SimpleBinner { 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 StatsVariableTemplatedc.divemode; + int mode = (int)d->dcs[0].divemode; return mode >= 0 && mode < NUM_DIVEMODE ? QString(divemode_text_ui[mode]) : QString(); } diff --git a/tests/testparse.cpp b/tests/testparse.cpp index ec62ab130..8fd48889c 100644 --- a/tests/testparse.cpp +++ b/tests/testparse.cpp @@ -189,7 +189,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; } QCOMPARE(save_dives("./testhudcout.ssrf"), 0); diff --git a/tests/testplan.cpp b/tests/testplan.cpp index 6a39ed7ed..849efb82a 100644 --- a/tests/testplan.cpp +++ b/tests/testplan.cpp @@ -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)); }