aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/cochran.c24
-rw-r--r--core/datatrak.c32
-rw-r--r--core/display.h3
-rw-r--r--core/dive.c282
-rw-r--r--core/dive.h9
-rw-r--r--core/divelist.c10
-rw-r--r--core/equipment.c117
-rw-r--r--core/equipment.h25
-rw-r--r--core/gaspressures.c9
-rw-r--r--core/import-cobalt.c14
-rw-r--r--core/import-csv.c30
-rw-r--r--core/import-divinglog.c26
-rw-r--r--core/import-shearwater.c20
-rw-r--r--core/import-suunto.c34
-rw-r--r--core/libdivecomputer.c58
-rw-r--r--core/liquivision.c7
-rw-r--r--core/load-git.c18
-rw-r--r--core/parse-xml.c92
-rw-r--r--core/parse.c3
-rw-r--r--core/parse.h1
-rw-r--r--core/planner.c80
-rw-r--r--core/plannernotes.c12
-rw-r--r--core/profile.c53
-rw-r--r--core/qthelper.cpp6
-rw-r--r--core/save-git.c2
-rw-r--r--core/save-html.c2
-rw-r--r--core/save-profiledata.c8
-rw-r--r--core/save-xml.c2
-rw-r--r--core/statistics.c24
-rw-r--r--core/subsurface-qt/DiveObjectHelper.cpp38
-rw-r--r--core/uemis.c11
-rw-r--r--desktop-widgets/command_edit.cpp45
-rw-r--r--desktop-widgets/command_edit.h4
-rw-r--r--desktop-widgets/divelogexportdialog.cpp24
-rw-r--r--desktop-widgets/simplewidgets.cpp4
-rw-r--r--desktop-widgets/tab-widgets/TabDiveEquipment.cpp33
-rw-r--r--desktop-widgets/tab-widgets/TabDiveInformation.cpp8
-rw-r--r--desktop-widgets/tab-widgets/TabDiveStatistics.cpp6
-rw-r--r--desktop-widgets/tab-widgets/maintab.cpp13
-rw-r--r--mobile-widgets/qmlmanager.cpp26
-rw-r--r--profile-widget/diveprofileitem.cpp26
-rw-r--r--profile-widget/profilewidget2.cpp6
-rw-r--r--profile-widget/tankitem.cpp2
-rw-r--r--qt-models/cylindermodel.cpp120
-rw-r--r--qt-models/cylindermodel.h1
-rw-r--r--qt-models/diveplannermodel.cpp45
-rw-r--r--qt-models/diveplotdatamodel.cpp4
-rw-r--r--qt-models/divetripmodel.cpp6
-rw-r--r--qt-models/models.cpp6
-rw-r--r--smtk-import/smartrak.c26
-rw-r--r--tests/testplan.cpp132
51 files changed, 807 insertions, 782 deletions
diff --git a/core/cochran.c b/core/cochran.c
index 9cbc51113..632ba5bff 100644
--- a/core/cochran.c
+++ b/core/cochran.c
@@ -675,20 +675,24 @@ static void cochran_parse_dive(const unsigned char *decode, unsigned mod,
case TYPE_GEMINI:
case TYPE_COMMANDER:
if (config.type == TYPE_GEMINI) {
+ cylinder_t cyl = { 0 };
dc->model = "Gemini";
dc->deviceid = buf[0x18c] * 256 + buf[0x18d]; // serial no
- fill_default_cylinder(dive, 0);
- dive->cylinder[0].gasmix.o2.permille = (log[CMD_O2_PERCENT] / 256
+ fill_default_cylinder(dive, &cyl);
+ cyl.gasmix.o2.permille = (log[CMD_O2_PERCENT] / 256
+ log[CMD_O2_PERCENT + 1]) * 10;
- dive->cylinder[0].gasmix.he.permille = 0;
+ cyl.gasmix.he.permille = 0;
+ add_to_cylinder_table(&dive->cylinders, 0, cyl);
} else {
dc->model = "Commander";
dc->deviceid = array_uint32_le(buf + 0x31e); // serial no
for (g = 0; g < 2; g++) {
- fill_default_cylinder(dive, g);
- dive->cylinder[g].gasmix.o2.permille = (log[CMD_O2_PERCENT + g * 2] / 256
+ cylinder_t cyl = { 0 };
+ fill_default_cylinder(dive, &cyl);
+ cyl.gasmix.o2.permille = (log[CMD_O2_PERCENT + g * 2] / 256
+ log[CMD_O2_PERCENT + g * 2 + 1]) * 10;
- dive->cylinder[g].gasmix.he.permille = 0;
+ cyl.gasmix.he.permille = 0;
+ add_to_cylinder_table(&dive->cylinders, g, cyl);
}
}
@@ -727,13 +731,15 @@ static void cochran_parse_dive(const unsigned char *decode, unsigned mod,
dc->model = "EMC";
dc->deviceid = array_uint32_le(buf + 0x31e); // serial no
for (g = 0; g < 4; g++) {
- fill_default_cylinder(dive , g);
- dive->cylinder[g].gasmix.o2.permille =
+ cylinder_t cyl = { 0 };
+ fill_default_cylinder(dive, &cyl);
+ cyl.gasmix.o2.permille =
(log[EMC_O2_PERCENT + g * 2] / 256
+ log[EMC_O2_PERCENT + g * 2 + 1]) * 10;
- dive->cylinder[g].gasmix.he.permille =
+ cyl.gasmix.he.permille =
(log[EMC_HE_PERCENT + g * 2] / 256
+ log[EMC_HE_PERCENT + g * 2 + 1]) * 10;
+ add_to_cylinder_table(&dive->cylinders, g, cyl);
}
tm.tm_year = log[EMC_YEAR];
diff --git a/core/datatrak.c b/core/datatrak.c
index 763b8cc8b..f9f577c73 100644
--- a/core/datatrak.c
+++ b/core/datatrak.c
@@ -317,12 +317,14 @@ static unsigned char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive
*/
read_bytes(2);
if (tmp_2bytes != 0x7FFF) {
- dt_dive->cylinder[0].type.size.mliter = tmp_2bytes * 10;
- dt_dive->cylinder[0].type.description = strdup("");
- dt_dive->cylinder[0].start.mbar = 200000;
- dt_dive->cylinder[0].gasmix.he.permille = 0;
- dt_dive->cylinder[0].gasmix.o2.permille = 210;
- dt_dive->cylinder[0].manually_added = true;
+ cylinder_t cyl = { 0 };
+ cyl.type.size.mliter = tmp_2bytes * 10;
+ cyl.type.description = "";
+ cyl.start.mbar = 200000;
+ cyl.gasmix.he.permille = 0;
+ cyl.gasmix.o2.permille = 210;
+ cyl.manually_added = true;
+ add_cloned_cylinder(&dt_dive->cylinders, cyl);
}
/*
@@ -353,8 +355,8 @@ static unsigned char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive
* Air used in bar*100.
*/
read_bytes(2);
- if (tmp_2bytes != 0x7FFF && dt_dive->cylinder[0].type.size.mliter)
- dt_dive->cylinder[0].gas_used.mliter = lrint(dt_dive->cylinder[0].type.size.mliter * (tmp_2bytes / 100.0));
+ if (tmp_2bytes != 0x7FFF && dt_dive->cylinders.nr > 0)
+ dt_dive->cylinders.cylinders[0].gas_used.mliter = lrint(dt_dive->cylinders.cylinders[0].type.size.mliter * (tmp_2bytes / 100.0));
/*
* Dive Type 1 - Bit table. Subsurface don't have this record, but
@@ -529,11 +531,11 @@ static unsigned char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive
free(compl_buffer);
goto bail;
}
- if (is_nitrox)
- dt_dive->cylinder[0].gasmix.o2.permille =
+ if (is_nitrox && dt_dive->cylinders.nr > 0)
+ dt_dive->cylinders.cylinders[0].gasmix.o2.permille =
lrint(membuf[23] & 0x0F ? 20.0 + 2 * (membuf[23] & 0x0F) : 21.0) * 10;
- if (is_O2)
- dt_dive->cylinder[0].gasmix.o2.permille = membuf[23] * 10;
+ if (is_O2 && dt_dive->cylinders.nr > 0)
+ dt_dive->cylinders.cylinders[0].gasmix.o2.permille = membuf[23] * 10;
free(compl_buffer);
}
JUMP(membuf, profile_length);
@@ -547,9 +549,9 @@ static unsigned char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive
dt_dive->dc.deviceid = 0xffffffff;
create_device_node(dt_dive->dc.model, dt_dive->dc.deviceid, "", "", dt_dive->dc.model);
dt_dive->dc.next = NULL;
- if (!is_SCR && dt_dive->cylinder[0].type.size.mliter) {
- dt_dive->cylinder[0].end.mbar = dt_dive->cylinder[0].start.mbar -
- ((dt_dive->cylinder[0].gas_used.mliter / dt_dive->cylinder[0].type.size.mliter) * 1000);
+ if (!is_SCR && dt_dive->cylinders.nr > 0) {
+ dt_dive->cylinders.cylinders[0].end.mbar = dt_dive->cylinders.cylinders[0].start.mbar -
+ ((dt_dive->cylinders.cylinders[0].gas_used.mliter / dt_dive->cylinders.cylinders[0].type.size.mliter) * 1000);
}
free(devdata);
return membuf;
diff --git a/core/display.h b/core/display.h
index 3e3a9531e..8c6223be6 100644
--- a/core/display.h
+++ b/core/display.h
@@ -12,6 +12,7 @@ extern "C" {
* and one-, two- and three-minute minimums and maximums */
struct plot_info {
int nr;
+ int nr_cylinders;
int maxtime;
int meandepth, maxdepth;
int minpressure, maxpressure;
@@ -21,7 +22,7 @@ struct plot_info {
double endtempcoord;
double maxpp;
struct plot_data *entry;
- struct plot_pressure_data *pressures; /* MAX_CYLINDERS blocks of nr entries. */
+ struct plot_pressure_data *pressures; /* cylinders.nr blocks of nr entries. */
};
extern struct divecomputer *select_dc(struct dive *);
diff --git a/core/dive.c b/core/dive.c
index 6043845f6..0b68819fa 100644
--- a/core/dive.c
+++ b/core/dive.c
@@ -150,7 +150,8 @@ struct event *add_event(struct divecomputer *dc, unsigned int time, int type, in
ev->gas.mix.he.permille = (value >> 16) * 10;
/* Extension to the GASCHANGE2 format: cylinder index in 'flags' */
- if (flags > 0 && flags <= MAX_CYLINDERS)
+ /* TODO: verify that gas_index < num_cylinders. */
+ if (flags > 0)
gas_index = flags-1;
/* Fallthrough */
case SAMPLE_EVENT_GASCHANGE:
@@ -262,8 +263,8 @@ struct gasmix get_gasmix_from_event(const struct dive *dive, const struct event
struct gasmix dummy = { 0 };
if (ev && event_is_gaschange(ev)) {
int index = ev->gas.index;
- if (index >= 0 && index < MAX_CYLINDERS)
- return dive->cylinder[index].gasmix;
+ if (index >= 0 && index < dive->cylinders.nr)
+ return dive->cylinders.cylinders[index].gasmix;
return ev->gas.mix;
}
return dummy;
@@ -360,8 +361,8 @@ static void free_dive_structures(struct dive *d)
taglist_free(d->tag_list);
free_dive_dcs(&d->dc);
STRUCTURED_LIST_FREE(struct picture, d->picture_list, free_picture);
- for (int i = 0; i < MAX_CYLINDERS; i++)
- free((void *)d->cylinder[i].type.description);
+ clear_cylinder_table(&d->cylinders);
+ free(d->cylinders.cylinders);
clear_weightsystem_table(&d->weightsystems);
free(d->weightsystems.weightsystems);
}
@@ -394,14 +395,14 @@ static void copy_dive_nodc(const struct dive *s, struct dive *d)
* relevant components that are referenced through pointers,
* so all the strings and the structured lists */
*d = *s;
+ memset(&d->cylinders, 0, sizeof(d->cylinders));
memset(&d->weightsystems, 0, sizeof(d->weightsystems));
invalidate_dive_cache(d);
d->buddy = copy_string(s->buddy);
d->divemaster = copy_string(s->divemaster);
d->notes = copy_string(s->notes);
d->suit = copy_string(s->suit);
- for (int i = 0; i < MAX_CYLINDERS; i++)
- d->cylinder[i].type.description = copy_string(s->cylinder[i].type.description);
+ copy_cylinders(&s->cylinders, &d->cylinders);
copy_weights(&s->weightsystems, &d->weightsystems);
STRUCTURED_LIST_COPY(struct picture, s->picture_list, d->picture_list, copy_pl);
d->tag_list = taglist_copy(s->tag_list);
@@ -501,14 +502,7 @@ void copy_events(const struct divecomputer *s, struct divecomputer *d)
int nr_cylinders(const struct dive *dive)
{
- int nr;
-
- for (nr = MAX_CYLINDERS; nr; --nr) {
- const cylinder_t *cylinder = dive->cylinder + nr - 1;
- if (!cylinder_nodata(cylinder))
- break;
- }
- return nr;
+ return dive->cylinders.nr;
}
int nr_weightsystems(const struct dive *dive)
@@ -516,24 +510,24 @@ int nr_weightsystems(const struct dive *dive)
return dive->weightsystems.nr;
}
-void copy_cylinders(const struct dive *s, struct dive *d, bool used_only)
+void copy_cylinders(const struct cylinder_table *s, struct cylinder_table *d)
+{
+ int i;
+ clear_cylinder_table(d);
+ for (i = 0; i < s->nr; i++)
+ add_cloned_cylinder(d, s->cylinders[i]);
+}
+
+void copy_used_cylinders(const struct dive *s, struct dive *d, bool used_only)
{
- int i, j;
+ int i;
if (!s || !d)
return;
- for (i = 0, j = 0; i < MAX_CYLINDERS; i++) {
- if (!used_only || is_cylinder_used(s, i) || s->cylinder[i].cylinder_use == NOT_USED) {
- free((void *)d->cylinder[j].type.description);
- d->cylinder[j] = s->cylinder[i];
- if (d->cylinder[j].type.description)
- d->cylinder[j].type.description = strdup(d->cylinder[j].type.description);
- j++;
- }
- }
- for ( ; j < MAX_CYLINDERS; j++) {
- free((void *)d->cylinder[j].type.description);
- memset(d->cylinder + j, 0, sizeof(d->cylinder[j]));
+ clear_cylinder_table(&d->cylinders);
+ for (i = 0; i < s->cylinders.nr; i++) {
+ if (!used_only || is_cylinder_used(s, i) || s->cylinders.cylinders[i].cylinder_use == NOT_USED)
+ add_cloned_cylinder(&d->cylinders, s->cylinders.cylinders[i]);
}
}
@@ -688,8 +682,6 @@ static bool cylinder_used(const cylinder_t *cyl)
{
int start_mbar, end_mbar;
- if (cylinder_nodata(cyl))
- return false;
start_mbar = cyl->start.mbar ?: cyl->sample_start.mbar;
end_mbar = cyl->end.mbar ?: cyl->sample_end.mbar;
@@ -703,8 +695,8 @@ static int get_cylinder_used(const struct dive *dive, bool used[])
{
int i, num = 0;
- for (i = 0; i < MAX_CYLINDERS; i++) {
- used[i] = cylinder_used(dive->cylinder + i);
+ for (i = 0; i < dive->cylinders.nr; i++) {
+ used[i] = cylinder_used(dive->cylinders.cylinders + i);
if (used[i])
num++;
}
@@ -717,8 +709,8 @@ static bool has_unknown_used_cylinders(const struct dive *dive, const struct div
{
int idx;
const struct event *ev;
- bool *used_and_unknown = malloc(MAX_CYLINDERS * sizeof(bool));
- memcpy(used_and_unknown, used_cylinders, MAX_CYLINDERS * sizeof(bool));
+ bool *used_and_unknown = malloc(dive->cylinders.nr * sizeof(bool));
+ memcpy(used_and_unknown, used_cylinders, dive->cylinders.nr * sizeof(bool));
/* We know about using the O2 cylinder in a CCR dive */
if (dc->divemode == CCR) {
@@ -761,7 +753,7 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i
bool *used_cylinders;
int num_used_cylinders;
- for (i = 0; i < MAX_CYLINDERS; i++)
+ for (i = 0; i < dive->cylinders.nr; i++)
mean[i] = duration[i] = 0;
if (!dc)
return;
@@ -771,7 +763,7 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i
* if we don't actually know about the usage of all the
* used cylinders.
*/
- used_cylinders = malloc(MAX_CYLINDERS * sizeof(bool));
+ used_cylinders = malloc(dive->cylinders.nr * sizeof(bool));
num_used_cylinders = get_cylinder_used(dive, used_cylinders);
if (has_unknown_used_cylinders(dive, dc, used_cylinders, num_used_cylinders)) {
/*
@@ -788,7 +780,7 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i
* For a single cylinder, use the overall mean
* and duration
*/
- for (i = 0; i < MAX_CYLINDERS; i++) {
+ for (i = 0; i < dive->cylinders.nr; i++) {
if (used_cylinders[i]) {
mean[i] = dc->meandepth.mm;
duration[i] = dc->duration.seconds;
@@ -802,8 +794,8 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i
if (!dc->samples)
fake_dc(dc);
const struct event *ev = get_next_event(dc->events, "gaschange");
- depthtime = malloc(MAX_CYLINDERS * sizeof(*depthtime));
- memset(depthtime, 0, MAX_CYLINDERS * sizeof(*depthtime));
+ depthtime = malloc(dive->cylinders.nr * sizeof(*depthtime));
+ memset(depthtime, 0, dive->cylinders.nr * sizeof(*depthtime));
for (i = 0; i < dc->samples; i++) {
struct sample *sample = dc->sample + i;
uint32_t time = sample->time.seconds;
@@ -832,7 +824,7 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i
lastdepth = depth;
lasttime = time;
}
- for (i = 0; i < MAX_CYLINDERS; i++) {
+ for (i = 0; i < dive->cylinders.nr; i++) {
if (duration[i])
mean[i] = (depthtime[i] + duration[i] / 2) / duration[i];
}
@@ -1004,9 +996,9 @@ static void sanitize_cylinder_info(struct dive *dive)
{
int i;
- for (i = 0; i < MAX_CYLINDERS; i++) {
- sanitize_gasmix(&dive->cylinder[i].gasmix);
- sanitize_cylinder_type(&dive->cylinder[i].type);
+ for (i = 0; i < dive->cylinders.nr; i++) {
+ sanitize_gasmix(&dive->cylinders.cylinders[i].gasmix);
+ sanitize_cylinder_type(&dive->cylinders.cylinders[i].type);
}
}
@@ -1338,8 +1330,8 @@ static void simplify_dc_pressures(struct divecomputer *dc)
/* Do we need a sensor -> cylinder mapping? */
static void fixup_start_pressure(struct dive *dive, int idx, pressure_t p)
{
- if (idx >= 0 && idx < MAX_CYLINDERS) {
- cylinder_t *cyl = dive->cylinder + idx;
+ if (idx >= 0 && idx < dive->cylinders.nr) {
+ cylinder_t *cyl = dive->cylinders.cylinders + idx;
if (p.mbar && !cyl->sample_start.mbar)
cyl->sample_start = p;
}
@@ -1347,8 +1339,8 @@ static void fixup_start_pressure(struct dive *dive, int idx, pressure_t p)
static void fixup_end_pressure(struct dive *dive, int idx, pressure_t p)
{
- if (idx >= 0 && idx < MAX_CYLINDERS) {
- cylinder_t *cyl = dive->cylinder + idx;
+ if (idx >= 0 && idx < dive->cylinders.nr) {
+ cylinder_t *cyl = dive->cylinders.cylinders + idx;
if (p.mbar && !cyl->sample_end.mbar)
cyl->sample_end = p;
}
@@ -1414,13 +1406,13 @@ static bool validate_gaschange(struct dive *dive, struct event *event)
if (event->gas.index >= 0)
return true;
- index = find_best_gasmix_match(event->gas.mix, dive->cylinder);
- if (index < 0)
+ index = find_best_gasmix_match(event->gas.mix, &dive->cylinders);
+ if (index < 0 || index >= dive->cylinders.nr)
return false;
/* Fix up the event to have the right information */
event->gas.index = index;
- event->gas.mix = dive->cylinder[index].gasmix;
+ event->gas.mix = dive->cylinders.cylinders[index].gasmix;
/* Convert to odd libdivecomputer format */
o2 = get_o2(event->gas.mix);
@@ -1544,8 +1536,8 @@ struct dive *fixup_dive(struct dive *dive)
fixup_duration(dive);
fixup_watertemp(dive);
fixup_airtemp(dive);
- for (i = 0; i < MAX_CYLINDERS; i++) {
- cylinder_t *cyl = dive->cylinder + i;
+ for (i = 0; i < dive->cylinders.nr; i++) {
+ cylinder_t *cyl = dive->cylinders.cylinders + i;
add_cylinder_description(&cyl->type);
if (same_rounded_pressure(cyl->sample_start, cyl->start))
cyl->start.mbar = 0;
@@ -1927,8 +1919,8 @@ static void merge_events(struct dive *d, struct divecomputer *res,
extern int get_cylinder_idx_by_use(const struct dive *dive, enum cylinderuse cylinder_use_type)
{
int cylinder_index;
- for (cylinder_index = 0; cylinder_index < MAX_CYLINDERS; cylinder_index++) {
- if (dive->cylinder[cylinder_index].cylinder_use == cylinder_use_type)
+ for (cylinder_index = 0; cylinder_index < dive->cylinders.nr; cylinder_index++) {
+ if (dive->cylinders.cylinders[cylinder_index].cylinder_use == cylinder_use_type)
return cylinder_index; // return the index of the cylinder with that cylinder use type
}
return -1; // negative number means cylinder_use_type not found in list of cylinders
@@ -2072,13 +2064,13 @@ void cylinder_renumber(struct dive *dive, int mapping[])
dc_cylinder_renumber(dive, dc, mapping);
}
-int same_gasmix_cylinder(cylinder_t *cyl, int cylid, struct dive *dive, bool check_unused)
+int same_gasmix_cylinder(const cylinder_t *cyl, int cylid, const struct dive *dive, bool check_unused)
{
struct gasmix mygas = cyl->gasmix;
- for (int i = 0; i < MAX_CYLINDERS; i++) {
- if (i == cylid || cylinder_none(&dive->cylinder[i]))
+ for (int i = 0; i < dive->cylinders.nr; i++) {
+ if (i == cylid)
continue;
- struct gasmix gas2 = dive->cylinder[i].gasmix;
+ struct gasmix gas2 = dive->cylinders.cylinders[i].gasmix;
if (gasmix_distance(mygas, gas2) == 0 && (is_cylinder_used(dive, i) || check_unused))
return i;
}
@@ -2104,16 +2096,16 @@ static int different_manual_pressures(const cylinder_t *a, const cylinder_t *b)
* same cylinder use (ie OC/Diluent/Oxygen), and if pressures
* have been added manually they need to match.
*/
-static int match_cylinder(const cylinder_t *cyl, const struct dive *dive, bool *used_in_a, bool *matched)
+static int match_cylinder(const cylinder_t *cyl, const struct dive *dive, const bool *used)
{
int i;
- for (i = 0; i < MAX_CYLINDERS; i++) {
+ for (i = 0; i < dive->cylinders.nr; i++) {
const cylinder_t *target;
- if (!used_in_a[i] || matched[i])
+ if (!used[i])
continue;
- target = dive->cylinder + i;
+ target = dive->cylinders.cylinders + i;
if (!same_gasmix(cyl->gasmix, target->gasmix))
continue;
if (cyl->cylinder_use != target->cylinder_use)
@@ -2128,50 +2120,15 @@ static int match_cylinder(const cylinder_t *cyl, const struct dive *dive, bool *
}
/*
- * Note: we only allocate from the end, not in holes in the middle.
- * So we don't look for empty bits, we look for "no more bits set".
- */
-static int find_unused_cylinder(bool used_map[])
-{
- int i;
-
- if (used_map[MAX_CYLINDERS - 1])
- return -1; /* Maximum number of cylinders used! */
- for (i = MAX_CYLINDERS - 1; i > 0; i--) {
- if (used_map[i - 1])
- return i;
- }
- return 0; /* Not a single cylinder used. */
-}
-
-/*
- * Copy a single cylinder
- */
-static void copy_cylinder(const cylinder_t *s, cylinder_t *d)
-{
- d->type.size.mliter = s->type.size.mliter;
- d->type.workingpressure.mbar = s->type.workingpressure.mbar;
- d->type.description = copy_string(s->type.description);
- d->gasmix = s->gasmix;
- d->start.mbar = s->start.mbar;
- d->end.mbar = s->end.mbar;
- d->sample_start.mbar = s->sample_start.mbar;
- d->sample_end.mbar = s->sample_end.mbar;
- d->depth = s->depth;
- d->manually_added = s->manually_added;
- d->gas_used.mliter = s->gas_used.mliter;
- d->deco_gas_used.mliter = s->deco_gas_used.mliter;
- d->bestmix_o2 = s->bestmix_o2;
- d->bestmix_he = s->bestmix_he;
-}
-
-/*
* We matched things up so that they have the same gasmix and
* use, but we might want to fill in any missing cylinder details
* in 'a' if we had it from 'b'.
*/
-static void merge_one_cylinder(cylinder_t *res, const cylinder_t *a, const cylinder_t *b)
+static void merge_one_cylinder(struct cylinder_table *t, const cylinder_t *a, const cylinder_t *b)
{
+ cylinder_t *res;
+ add_empty_cylinder(t);
+ res = t->cylinders + (t->nr - 1);
res->type.size.mliter = a->type.size.mliter ?
a->type.size.mliter : b->type.size.mliter;
res->type.workingpressure.mbar = a->type.workingpressure.mbar ?
@@ -2209,37 +2166,37 @@ static void merge_one_cylinder(cylinder_t *res, const cylinder_t *a, const cylin
* then try to match each of the cylinders in the other dive by the gasmix that
* is the best match and hasn't been used yet.
*
- * For each dive, a cylinder-renumbering table is returned. Currently, only
- * cylinders of dive 'b' are renumbered.
+ * For each dive, a cylinder-renumbering table is returned.
*/
static void merge_cylinders(struct dive *res, const struct dive *a, const struct dive *b,
int mapping_a[], int mapping_b[])
{
int i;
- bool *used_in_a = malloc(MAX_CYLINDERS * sizeof(bool));
- bool *used_in_b = malloc(MAX_CYLINDERS * sizeof(bool));
- bool *matched_in_a = malloc(MAX_CYLINDERS * sizeof(bool));
+ bool *used_in_a = malloc(a->cylinders.nr * sizeof(bool));
+ bool *used_in_b = malloc(b->cylinders.nr * sizeof(bool));
/* First, clear all cylinders in destination */
- memset(res->cylinder, 0, sizeof(res->cylinder));
+ clear_cylinder_table(&res->cylinders);
/* Calculate usage map of cylinders */
- for (i = 0; i < MAX_CYLINDERS; i++) {
- used_in_a[i] = !cylinder_none(a->cylinder+i) || is_cylinder_used(a, i);
- used_in_b[i] = !cylinder_none(b->cylinder+i) || is_cylinder_used(b, i);
- matched_in_a[i] = false;
+ for (i = 0; i < a->cylinders.nr; i++) {
+ used_in_a[i] = is_cylinder_used(a, i);
+ mapping_a[i] = -1;
+ }
+
+ for (i = 0; i < b->cylinders.nr; i++) {
+ used_in_b[i] = is_cylinder_used(b, i);
+ mapping_b[i] = -1;
}
/* For each cylinder in 'b', try to match up things */
- for (i = 0; i < MAX_CYLINDERS; i++) {
+ for (i = 0; i < b->cylinders.nr; i++) {
int j;
- mapping_a[i] = i;
- mapping_b[i] = -1;
if (!used_in_b[i])
continue;
- j = match_cylinder(b->cylinder+i, a, used_in_a, matched_in_a);
+ j = match_cylinder(b->cylinders.cylinders + i, a, used_in_a);
if (j < 0)
continue;
@@ -2250,54 +2207,35 @@ static void merge_cylinders(struct dive *res, const struct dive *a, const struct
*
* - save that in the mapping table
*
- * - mark it as matched so that another cylinder in 'b'
- * will no longer match
+ * - remove it from the used array so that it will not be used later
*
- * - mark 'b' as needing renumbering if the index changed
+ * - mark as needing renumbering if the index changed
*/
- merge_one_cylinder(res->cylinder + j, a->cylinder + j, b->cylinder + i);
- mapping_b[i] = j;
- matched_in_a[j] = true;
- }
-
- /* Now copy all the used cylinders from 'a' which are used, but have not been matched */
- for (i = 0; i < MAX_CYLINDERS; i++) {
- if (used_in_a[i] && !matched_in_a[i])
- copy_cylinder(a->cylinder + i, res->cylinder + i);
+ mapping_b[i] = res->cylinders.nr;
+ mapping_a[j] = res->cylinders.nr;
+ used_in_a[i] = false;
+ used_in_b[j] = false;
+ merge_one_cylinder(&res->cylinders, a->cylinders.cylinders + j, b->cylinders.cylinders + i);
+ }
+
+ /* Now copy all the used cylinders from 'a' that are used but have not been matched */
+ for (i = 0; i < a->cylinders.nr; i++) {
+ if (used_in_a[i]) {
+ mapping_a[i] = res->weightsystems.nr;
+ add_cloned_cylinder(&res->cylinders, a->cylinders.cylinders[i]);
+ }
}
- /*
- * Consider all the cylinders we matched as used, whether they
- * originally were or not (either in 'a' or 'b').
- */
- for (i = 0; i < MAX_CYLINDERS; i++)
- used_in_a[i] |= matched_in_a[i];
-
- /*
- * Go back to 'b' and remap any remaining cylinders that didn't
- * match completely.
- */
- for (i = 0; i < MAX_CYLINDERS; i++) {
- int j;
-
- /* Already remapped, or not interesting? */
- if (mapping_b[i] >= 0)
- continue;
- if (!used_in_b[i])
- continue;
-
- j = find_unused_cylinder(used_in_a);
- if (j < 0)
- continue;
-
- copy_cylinder(b->cylinder + i, res->cylinder + j);
- mapping_b[i] = j;
- used_in_a[i] = true;
+ /* Finally, copy all the used cylinders from 'b' that are used but have not been matched */
+ for (i = 0; i < b->cylinders.nr; i++) {
+ if (used_in_b[i]) {
+ mapping_b[i] = res->weightsystems.nr;
+ add_cloned_cylinder(&res->cylinders, b->cylinders.cylinders[i]);
+ }
}
free(used_in_a);
free(used_in_b);
- free(matched_in_a);
}
/* Check whether a weightsystem table contains a given weightsystem */
@@ -3022,8 +2960,8 @@ struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset,
MERGE_NONZERO(res, a, b, visibility);
STRUCTURED_LIST_COPY(struct picture, a->picture_list ? a->picture_list : b->picture_list, res->picture_list, copy_pl);
taglist_merge(&res->tag_list, a->tag_list, b->tag_list);
- cylinders_map_a = malloc(MAX_CYLINDERS * sizeof(*cylinders_map_a));
- cylinders_map_b = malloc(MAX_CYLINDERS * sizeof(*cylinders_map_b));
+ cylinders_map_a = malloc(a->cylinders.nr * sizeof(*cylinders_map_a));
+ cylinders_map_b = malloc(b->cylinders.nr * sizeof(*cylinders_map_b));
merge_cylinders(res, a, b, cylinders_map_a, cylinders_map_b);
merge_equipment(res, a, b);
merge_temperatures(res, a, b);
@@ -3069,7 +3007,7 @@ static void force_fixup_dive(struct dive *d)
int old_mintemp = d->mintemp.mkelvin;
int old_maxtemp = d->maxtemp.mkelvin;
duration_t old_duration = d->duration;
- struct start_end_pressure *old_pressures = malloc(MAX_CYLINDERS * sizeof(*old_pressures));
+ struct start_end_pressure *old_pressures = malloc(d->cylinders.nr * sizeof(*old_pressures));
d->maxdepth.mm = 0;
dc->maxdepth.mm = 0;
@@ -3078,11 +3016,11 @@ static void force_fixup_dive(struct dive *d)
d->duration.seconds = 0;
d->maxtemp.mkelvin = 0;
d->mintemp.mkelvin = 0;
- for (int i = 0; i < MAX_CYLINDERS; i++) {
- old_pressures[i].start = d->cylinder[i].start;
- old_pressures[i].end = d->cylinder[i].end;
- d->cylinder[i].start.mbar = 0;
- d->cylinder[i].end.mbar = 0;
+ for (int i = 0; i < d->cylinders.nr; i++) {
+ old_pressures[i].start = d->cylinders.cylinders[i].start;
+ old_pressures[i].end = d->cylinders.cylinders[i].end;
+ d->cylinders.cylinders[i].start.mbar = 0;
+ d->cylinders.cylinders[i].end.mbar = 0;
}
fixup_dive(d);
@@ -3101,11 +3039,11 @@ static void force_fixup_dive(struct dive *d)
if (!d->duration.seconds)
d->duration = old_duration;
- for (int i = 0; i < MAX_CYLINDERS; i++) {
- if (!d->cylinder[i].start.mbar)
- d->cylinder[i].start = old_pressures[i].start;
- if (!d->cylinder[i].end.mbar)
- d->cylinder[i].end = old_pressures[i].end;
+ for (int i = 0; i < d->cylinders.nr; i++) {
+ if (!d->cylinders.cylinders[i].start.mbar)
+ d->cylinders.cylinders[i].start = old_pressures[i].start;
+ if (!d->cylinders.cylinders[i].end.mbar)
+ d->cylinders.cylinders[i].end = old_pressures[i].end;
}
free(old_pressures);
}
@@ -4063,10 +4001,14 @@ struct gasmix get_gasmix(const struct dive *dive, const struct divecomputer *dc,
const struct event *ev = *evp;
struct gasmix res;
+ /* if there is no cylinder, return air */
+ if (dive->cylinders.nr <= 0)
+ return gasmix_air;
+
if (!ev) {
/* on first invocation, get initial gas mix and first event (if any) */
int cyl = explicit_first_cylinder(dive, dc);
- res = dive->cylinder[cyl].gasmix;
+ res = dive->cylinders.cylinders[cyl].gasmix;
ev = dc ? get_next_event(dc->events, "gaschange") : NULL;
} else {
res = gasmix;
diff --git a/core/dive.h b/core/dive.h
index 132cc05d6..b1755c192 100644
--- a/core/dive.h
+++ b/core/dive.h
@@ -144,7 +144,7 @@ struct dive {
struct dive_site *dive_site;
char *notes;
char *divemaster, *buddy;
- cylinder_t cylinder[MAX_CYLINDERS];
+ struct cylinder_table cylinders;
struct weightsystem_table weightsystems;
char *suit;
int number;
@@ -183,7 +183,7 @@ extern bool dive_cache_is_valid(const struct dive *dive);
extern int get_cylinder_idx_by_use(const struct dive *dive, enum cylinderuse cylinder_use_type);
extern void cylinder_renumber(struct dive *dive, int mapping[]);
-extern int same_gasmix_cylinder(cylinder_t *cyl, int cylid, struct dive *dive, bool check_unused);
+extern int same_gasmix_cylinder(const cylinder_t *cyl, int cylid, const struct dive *dive, bool check_unused);
/* when selectively copying dive information, which parts should be copied? */
struct dive_components {
@@ -362,11 +362,12 @@ extern struct dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_dow
extern struct event *clone_event(const struct event *src_ev);
extern void copy_events(const struct divecomputer *s, struct divecomputer *d);
extern void free_events(struct event *ev);
-extern void copy_cylinders(const struct dive *s, struct dive *d, bool used_only);
+extern void copy_cylinders(const struct cylinder_table *s, struct cylinder_table *d);
+extern void copy_used_cylinders(const struct dive *s, struct dive *d, bool used_only);
extern void copy_samples(const struct divecomputer *s, struct divecomputer *d);
extern bool is_cylinder_used(const struct dive *dive, int idx);
extern bool is_cylinder_prot(const struct dive *dive, int idx);
-extern void fill_default_cylinder(struct dive *dive, int idx);
+extern void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl);
extern void add_gas_switch_event(struct dive *dive, struct divecomputer *dc, int time, int idx);
extern struct event *add_event(struct divecomputer *dc, unsigned int time, int type, int flags, int value, const char *name);
extern void remove_event(struct event *event);
diff --git a/core/divelist.c b/core/divelist.c
index de9509471..5eae5e638 100644
--- a/core/divelist.c
+++ b/core/divelist.c
@@ -65,15 +65,13 @@ void get_dive_gas(const struct dive *dive, int *o2_p, int *he_p, int *o2max_p)
int maxo2 = -1, maxhe = -1, mino2 = 1000;
- for (i = 0; i < MAX_CYLINDERS; i++) {
- const cylinder_t *cyl = dive->cylinder + i;
+ for (i = 0; i < dive->cylinders.nr; i++) {
+ const cylinder_t *cyl = dive->cylinders.cylinders + i;
int o2 = get_o2(cyl->gasmix);
int he = get_he(cyl->gasmix);
if (!is_cylinder_used(dive, i))
continue;
- if (cylinder_none(cyl))
- continue;
if (o2 > maxo2)
maxo2 = o2;
if (he > maxhe)
@@ -349,9 +347,9 @@ static double calculate_airuse(const struct dive *dive)
int airuse = 0;
int i;
- for (i = 0; i < MAX_CYLINDERS; i++) {
+ for (i = 0; i < dive->cylinders.nr; i++) {
pressure_t start, end;
- const cylinder_t *cyl = dive->cylinder + i;
+ const cylinder_t *cyl = dive->cylinders.cylinders + i;
start = cyl->start.mbar ? cyl->start : cyl->sample_start;
end = cyl->end.mbar ? cyl->end : cyl->sample_end;
diff --git a/core/equipment.c b/core/equipment.c
index d97ed6e4f..13e4a0486 100644
--- a/core/equipment.c
+++ b/core/equipment.c
@@ -24,6 +24,11 @@ static void free_weightsystem(weightsystem_t w)
free((void *)w.description);
}
+static void free_cylinder(cylinder_t c)
+{
+ free((void *)c.type.description);
+}
+
void copy_weights(const struct weightsystem_table *s, struct weightsystem_table *d)
{
clear_weightsystem_table(d);
@@ -41,6 +46,16 @@ MAKE_REMOVE_FROM(weightsystem_table, weightsystems)
//MAKE_REMOVE(weightsystem_table, weightsystem_t, weightsystem)
MAKE_CLEAR_TABLE(weightsystem_table, weightsystems, weightsystem)
+/* cylinder table functions */
+//static MAKE_GET_IDX(cylinder_table, cylinder_t, cylinders)
+static MAKE_GROW_TABLE(cylinder_table, cylinder_t, cylinders)
+//static MAKE_GET_INSERTION_INDEX(cylinder_table, cylinder_t, cylinders, cylinder_less_than)
+MAKE_ADD_TO(cylinder_table, cylinder_t, cylinders)
+MAKE_REMOVE_FROM(cylinder_table, cylinders)
+//MAKE_SORT(cylinder_table, cylinder_t, cylinders, comp_cylinders)
+//MAKE_REMOVE(cylinder_table, cylinder_t, cylinder)
+MAKE_CLEAR_TABLE(cylinder_table, cylinders, cylinder)
+
const char *cylinderuse_text[NUM_GAS_USE] = {
QT_TRANSLATE_NOOP("gettextFromC", "OC-gas"), QT_TRANSLATE_NOOP("gettextFromC", "diluent"), QT_TRANSLATE_NOOP("gettextFromC", "oxygen"), QT_TRANSLATE_NOOP("gettextFromC", "not used")
};
@@ -104,34 +119,27 @@ void add_cloned_weightsystem(struct weightsystem_table *t, weightsystem_t ws)
add_to_weightsystem_table(t, t->nr, w_clone);
}
-bool same_weightsystem(weightsystem_t w1, weightsystem_t w2)
-{
- return w1.weight.grams == w2.weight.grams &&
- same_string(w1.description, w2.description);
-}
-
-bool cylinder_nodata(const cylinder_t *cyl)
+/* Add a clone of a cylinder to the end of a cylinder table.
+ * Cloned in means that the description-string is copied. */
+void add_cloned_cylinder(struct cylinder_table *t, cylinder_t cyl)
{
- return !cyl->type.size.mliter &&
- !cyl->type.workingpressure.mbar &&
- !cyl->type.description &&
- !cyl->gasmix.o2.permille &&
- !cyl->gasmix.he.permille &&
- !cyl->start.mbar &&
- !cyl->end.mbar &&
- !cyl->gas_used.mliter &&
- !cyl->deco_gas_used.mliter;
+ cyl.type.description = copy_string(cyl.type.description);
+ add_to_cylinder_table(t, t->nr, cyl);
}
-static bool cylinder_nosamples(const cylinder_t *cyl)
+bool same_weightsystem(weightsystem_t w1, weightsystem_t w2)
{
- return !cyl->sample_start.mbar &&
- !cyl->sample_end.mbar;
+ return w1.weight.grams == w2.weight.grams &&
+ same_string(w1.description, w2.description);
}
-bool cylinder_none(const cylinder_t *cyl)
+bool same_cylinder(cylinder_t cyl1, cylinder_t cyl2)
{
- return cylinder_nodata(cyl) && cylinder_nosamples(cyl);
+ return same_string(cyl1.type.description, cyl2.type.description) &&
+ same_gasmix(cyl1.gasmix, cyl2.gasmix) &&
+ cyl1.start.mbar == cyl2.start.mbar &&
+ cyl1.end.mbar == cyl2.end.mbar &&
+ cyl1.cylinder_use == cyl2.cylinder_use;
}
void get_gas_string(struct gasmix gasmix, char *text, int len)
@@ -161,18 +169,16 @@ int gas_volume(const cylinder_t *cyl, pressure_t p)
return lrint(cyl->type.size.mliter * bar_to_atm(bar) / z_factor);
}
-int find_best_gasmix_match(struct gasmix mix, const cylinder_t array[])
+int find_best_gasmix_match(struct gasmix mix, const struct cylinder_table *cylinders)
{
int i;
int best = -1, score = INT_MAX;
- for (i = 0; i < MAX_CYLINDERS; i++) {
+ for (i = 0; i < cylinders->nr; i++) {
const cylinder_t *match;
int distance;
- match = array + i;
- if (cylinder_nodata(match))
- continue;
+ match = cylinders->cylinders + i;
distance = gasmix_distance(mix, match->gasmix);
if (distance >= score)
continue;
@@ -258,10 +264,7 @@ struct ws_info_t ws_info[MAX_WS_INFO] = {
void remove_cylinder(struct dive *dive, int idx)
{
- cylinder_t *cyl = dive->cylinder + idx;
- int nr = MAX_CYLINDERS - idx - 1;
- memmove(cyl, cyl + 1, nr * sizeof(*cyl));
- memset(cyl + nr, 0, sizeof(*cyl));
+ remove_from_cylinder_table(&dive->cylinders, idx);
}
void remove_weightsystem(struct dive *dive, int idx)
@@ -275,10 +278,8 @@ void reset_cylinders(struct dive *dive, bool track_gas)
{
pressure_t decopo2 = {.mbar = prefs.decopo2};
- for (int i = 0; i < MAX_CYLINDERS; i++) {
- cylinder_t *cyl = &dive->cylinder[i];
- if (cylinder_none(cyl))
- continue;
+ for (int i = 0; i < dive->cylinders.nr; i++) {
+ cylinder_t *cyl = &dive->cylinders.cylinders[i];
if (cyl->depth.mm == 0) /* if the gas doesn't give a mod, calculate based on prefs */
cyl->depth = gas_mod(cyl->gasmix, decopo2, dive, M_OR_FT(3,10));
if (track_gas)
@@ -290,7 +291,7 @@ void reset_cylinders(struct dive *dive, bool track_gas)
static void copy_cylinder_type(const cylinder_t *s, cylinder_t *d)
{
- free(d->type.description);
+ free_cylinder(*d);
d->type = s->type;
d->type.description = s->type.description ? strdup(s->type.description) : NULL;
d->gasmix = s->gasmix;
@@ -306,16 +307,54 @@ void copy_cylinder_types(const struct dive *s, struct dive *d)
if (!s || !d)
return;
- for (i = 0; i < MAX_CYLINDERS; i++)
- copy_cylinder_type(s->cylinder + i, d->cylinder + i);
+ for (i = 0; i < s->cylinders.nr && i < d->cylinders.nr; i++)
+ copy_cylinder_type(s->cylinders.cylinders + i, d->cylinders.cylinders + i);
+
+ for ( ; i < s->cylinders.nr; i++)
+ add_cloned_cylinder(&d->cylinders, s->cylinders.cylinders[i]);
+}
+
+void add_empty_cylinder(struct cylinder_table *t)
+{
+ cylinder_t cyl = { 0 };
+ cyl.type.description = strdup("");
+ add_to_cylinder_table(t, t->nr, cyl);
+}
+
+/* access to cylinders is controlled by two functions:
+ * - get_cylinder() returns the cylinder of a dive and supposes that
+ * the cylinder with the given index exists. If it doesn't, an error
+ * message is printed and NULL returned.
+ * - get_or_create_cylinder() creates an empty cylinder if it doesn't exist.
+ * Multiple cylinders might be created if the index is bigger than the
+ * number of existing cylinders
+ */
+cylinder_t *get_cylinder(const struct dive *d, int idx)
+{
+ if (idx < 0 || idx >= d->cylinders.nr) {
+ fprintf(stderr, "Warning: accessing invalid cylinder %d (%d existing)\n", idx, d->cylinders.nr);
+ return NULL;
+ }
+ return &d->cylinders.cylinders[idx];
+}
+
+cylinder_t *get_or_create_cylinder(struct dive *d, int idx)
+{
+ if (idx < 0) {
+ fprintf(stderr, "Warning: accessing invalid cylinder %d\n", idx);
+ return NULL;
+ }
+ while (idx >= d->cylinders.nr)
+ add_empty_cylinder(&d->cylinders);
+ return &d->cylinders.cylinders[idx];
}
#ifdef DEBUG_CYL
void dump_cylinders(struct dive *dive, bool verbose)
{
printf("Cylinder list:\n");
- for (int i = 0; i < MAX_CYLINDERS; i++) {
- cylinder_t *cyl = &dive->cylinder[i];
+ for (int i = 0; i < dive->cylinders; i++) {
+ cylinder_t *cyl = &dive->cylinders.cylinders[i];
printf("%02d: Type %s, %3.1fl, %3.0fbar\n", i, cyl->type.description, cyl->type.size.mliter / 1000.0, cyl->type.workingpressure.mbar / 1000.0);
printf(" Gasmix O2 %2.0f%% He %2.0f%%\n", cyl->gasmix.o2.permille / 10.0, cyl->gasmix.he.permille / 10.0);
diff --git a/core/equipment.h b/core/equipment.h
index beef30842..ce5683003 100644
--- a/core/equipment.h
+++ b/core/equipment.h
@@ -33,6 +33,17 @@ typedef struct
bool bestmix_he;
} cylinder_t;
+/* Table of cylinders. Attention: this stores cylinders,
+ * *not* pointers to cylinders. This has two crucial consequences:
+ * 1) Pointers to cylinders are not stable. They may be
+ * invalidated if the table is reallocated.
+ * 2) add_to_cylinder_table(), etc. take ownership of the
+ * cylinder. Notably of the description string. */
+struct cylinder_table {
+ int nr, allocated;
+ cylinder_t *cylinders;
+};
+
typedef struct
{
weight_t weight;
@@ -51,7 +62,6 @@ struct weightsystem_table {
weightsystem_t *weightsystems;
};
-#define MAX_CYLINDERS (20)
#define MAX_TANK_INFO (100)
#define MAX_WS_INFO (100)
@@ -59,16 +69,19 @@ extern int cylinderuse_from_text(const char *text);
extern void copy_weights(const struct weightsystem_table *s, struct weightsystem_table *d);
extern void copy_cylinder_types(const struct dive *s, struct dive *d);
extern void add_cloned_weightsystem(struct weightsystem_table *t, weightsystem_t ws);
+extern void add_empty_cylinder(struct cylinder_table *t);
+extern void add_cloned_cylinder(struct cylinder_table *t, cylinder_t cyl);
+extern cylinder_t *get_cylinder(const struct dive *d, int idx);
+extern cylinder_t *get_or_create_cylinder(struct dive *d, int idx);
extern void add_cylinder_description(const cylinder_type_t *);
extern void add_weightsystem_description(const weightsystem_t *);
extern bool same_weightsystem(weightsystem_t w1, weightsystem_t w2);
-extern bool cylinder_nodata(const cylinder_t *cyl);
-extern bool cylinder_none(const cylinder_t *cyl);
+extern bool same_cylinder(cylinder_t cyl1, cylinder_t cyl2);
extern void remove_cylinder(struct dive *dive, int idx);
extern void remove_weightsystem(struct dive *dive, int idx);
extern void reset_cylinders(struct dive *dive, bool track_gas);
extern int gas_volume(const cylinder_t *cyl, pressure_t p); /* Volume in mliter of a cylinder at pressure 'p' */
-extern int find_best_gasmix_match(struct gasmix mix, const cylinder_t array[]);
+extern int find_best_gasmix_match(struct gasmix mix, const struct cylinder_table *cylinders);
#ifdef DEBUG_CYL
extern void dump_cylinders(struct dive *dive, bool verbose);
#endif
@@ -77,6 +90,10 @@ extern void dump_cylinders(struct dive *dive, bool verbose);
extern void clear_weightsystem_table(struct weightsystem_table *);
extern void add_to_weightsystem_table(struct weightsystem_table *, int idx, weightsystem_t ws);
+/* Cylinder table functions */
+extern void clear_cylinder_table(struct cylinder_table *);
+extern void add_to_cylinder_table(struct cylinder_table *, int idx, cylinder_t cyl);
+
void get_gas_string(struct gasmix gasmix, char *text, int len);
const char *gasname(struct gasmix gasmix);
diff --git a/core/gaspressures.c b/core/gaspressures.c
index 2feeaa7d0..a69dbb295 100644
--- a/core/gaspressures.c
+++ b/core/gaspressures.c
@@ -238,7 +238,7 @@ static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi,
if (!track_pr)
return;
- if (dive->cylinder[cyl].cylinder_use == OC_GAS)
+ if (dive->cylinders.cylinders[cyl].cylinder_use == OC_GAS)
strategy = SAC;
else
strategy = TIME;
@@ -302,7 +302,7 @@ static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi,
last_segment = segment;
}
- if(dive->cylinder[cyl].cylinder_use == OC_GAS) {
+ if(dive->cylinders.cylinders[cyl].cylinder_use == OC_GAS) {
/* if this segment has pressure_time, then calculate a new interpolated pressure */
if (interpolate.pressure_time) {
@@ -366,7 +366,7 @@ void populate_pressure_information(struct dive *dive, struct divecomputer *dc, s
{
UNUSED(dc);
int first, last, cyl;
- cylinder_t *cylinder = dive->cylinder + sensor;
+ cylinder_t *cylinder = dive->cylinders.cylinders + sensor;
pr_track_t *track = NULL;
pr_track_t *current = NULL;
const struct event *ev, *b_ev;
@@ -374,6 +374,9 @@ void populate_pressure_information(struct dive *dive, struct divecomputer *dc, s
enum divemode_t dmode = dc->divemode;
const double gasfactor[5] = {1.0, 0.0, prefs.pscr_ratio/1000.0, 1.0, 1.0 };
+ if (sensor < 0 || sensor >= dive->cylinders.nr)
+ return;
+
/* if we have no pressure data whatsoever, this is pointless, so let's just return */
if (!cylinder->start.mbar && !cylinder->end.mbar &&
!cylinder->sample_start.mbar && !cylinder->sample_end.mbar)
diff --git a/core/import-cobalt.c b/core/import-cobalt.c
index b2c5793d7..967f7df51 100644
--- a/core/import-cobalt.c
+++ b/core/import-cobalt.c
@@ -37,20 +37,22 @@ static int cobalt_cylinders(void *param, int columns, char **data, char **column
UNUSED(columns);
UNUSED(column);
struct parser_state *state = (struct parser_state *)param;
+ cylinder_t *cyl;
cylinder_start(state);
+ cyl = &state->cur_dive->cylinders.cylinders[state->cur_dive->cylinders.nr - 1];
if (data[0])
- state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.o2.permille = atoi(data[0]) * 10;
+ cyl->gasmix.o2.permille = atoi(data[0]) * 10;
if (data[1])
- state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.he.permille = atoi(data[1]) * 10;
+ cyl->gasmix.he.permille = atoi(data[1]) * 10;
if (data[2])
- state->cur_dive->cylinder[state->cur_cylinder_index].start.mbar = psi_to_mbar(atoi(data[2]));
+ cyl->start.mbar = psi_to_mbar(atoi(data[2]));
if (data[3])
- state->cur_dive->cylinder[state->cur_cylinder_index].end.mbar = psi_to_mbar(atoi(data[3]));
+ cyl->end.mbar = psi_to_mbar(atoi(data[3]));
if (data[4])
- state->cur_dive->cylinder[state->cur_cylinder_index].type.size.mliter = atoi(data[4]) * 100;
+ cyl->type.size.mliter = atoi(data[4]) * 100;
if (data[5])
- state->cur_dive->cylinder[state->cur_cylinder_index].gas_used.mliter = atoi(data[5]) * 1000;
+ cyl->gas_used.mliter = atoi(data[5]) * 1000;
cylinder_end(state);
return 0;
diff --git a/core/import-csv.c b/core/import-csv.c
index 9c391025e..f34cb6802 100644
--- a/core/import-csv.c
+++ b/core/import-csv.c
@@ -509,8 +509,8 @@ int parse_txt_file(const char *filename, const char *csv, struct dive_table *tab
int prev_depth = 0, cur_sampletime = 0, prev_setpoint = -1, prev_ndl = -1;
bool has_depth = false, has_setpoint = false, has_ndl = false;
char *lineptr, *key, *value;
- int cur_cylinder_index = 0;
unsigned int prev_time = 0;
+ cylinder_t cyl;
struct dive *dive;
struct divecomputer *dc;
@@ -538,25 +538,25 @@ int parse_txt_file(const char *filename, const char *csv, struct dive_table *tab
dive->dc.divemode = CCR;
dive->dc.no_o2sensors = 2;
- dive->cylinder[cur_cylinder_index].cylinder_use = OXYGEN;
- dive->cylinder[cur_cylinder_index].type.size.mliter = 3000;
- dive->cylinder[cur_cylinder_index].type.workingpressure.mbar = 200000;
- dive->cylinder[cur_cylinder_index].type.description = strdup("3l Mk6");
- dive->cylinder[cur_cylinder_index].gasmix.o2.permille = 1000;
- cur_cylinder_index++;
-
- dive->cylinder[cur_cylinder_index].cylinder_use = DILUENT;
- dive->cylinder[cur_cylinder_index].type.size.mliter = 3000;
- dive->cylinder[cur_cylinder_index].type.workingpressure.mbar = 200000;
- dive->cylinder[cur_cylinder_index].type.description = strdup("3l Mk6");
+ cyl.cylinder_use = OXYGEN;
+ cyl.type.size.mliter = 3000;
+ cyl.type.workingpressure.mbar = 200000;
+ cyl.type.description = "3l Mk6";
+ cyl.gasmix.o2.permille = 1000;
+ add_cloned_cylinder(&dive->cylinders, cyl);
+
+ cyl.cylinder_use = DILUENT;
+ cyl.type.size.mliter = 3000;
+ cyl.type.workingpressure.mbar = 200000;
+ cyl.type.description = "3l Mk6";
value = parse_mkvi_value(memtxt.buffer, "Helium percentage");
he = atoi(value);
free(value);
value = parse_mkvi_value(memtxt.buffer, "Nitrogen percentage");
- dive->cylinder[cur_cylinder_index].gasmix.o2.permille = (100 - atoi(value) - he) * 10;
+ cyl.gasmix.o2.permille = (100 - atoi(value) - he) * 10;
free(value);
- dive->cylinder[cur_cylinder_index].gasmix.he.permille = he * 10;
- cur_cylinder_index++;
+ cyl.gasmix.he.permille = he * 10;
+ add_cloned_cylinder(&dive->cylinders, cyl);
lineptr = strstr(memtxt.buffer, "Dive started at");
while (!empty_string(lineptr) && (lineptr = strchr(lineptr, '\n'))) {
diff --git a/core/import-divinglog.c b/core/import-divinglog.c
index 98d2effbb..cd122c40a 100644
--- a/core/import-divinglog.c
+++ b/core/import-divinglog.c
@@ -18,22 +18,16 @@ static int divinglog_cylinder(void *param, int columns, char **data, char **colu
UNUSED(columns);
UNUSED(column);
struct parser_state *state = (struct parser_state *)param;
+ cylinder_t *cyl;
short dbl = 1;
//char get_cylinder_template[] = "select TankID,TankSize,PresS,PresE,PresW,O2,He,DblTank from Tank where LogID = %d";
- /*
- * Divinglog might have more cylinders than what we support. So
- * better to ignore those.
- */
-
- if (state->cur_cylinder_index >= MAX_CYLINDERS)
- return 0;
-
if (data[7] && atoi(data[7]) > 0)
dbl = 2;
cylinder_start(state);
+ cyl = &state->cur_dive->cylinders.cylinders[state->cur_dive->cylinders.nr - 1];
/*
* Assuming that we have to double the cylinder size, if double
@@ -41,18 +35,18 @@ static int divinglog_cylinder(void *param, int columns, char **data, char **colu
*/
if (data[1] && atoi(data[1]) > 0)
- state->cur_dive->cylinder[state->cur_cylinder_index].type.size.mliter = atol(data[1]) * 1000 * dbl;
+ cyl->type.size.mliter = atol(data[1]) * 1000 * dbl;
if (data[2] && atoi(data[2]) > 0)
- state->cur_dive->cylinder[state->cur_cylinder_index].start.mbar = atol(data[2]) * 1000;
+ cyl->start.mbar = atol(data[2]) * 1000;
if (data[3] && atoi(data[3]) > 0)
- state->cur_dive->cylinder[state->cur_cylinder_index].end.mbar = atol(data[3]) * 1000;
+ cyl->end.mbar = atol(data[3]) * 1000;
if (data[4] && atoi(data[4]) > 0)
- state->cur_dive->cylinder[state->cur_cylinder_index].type.workingpressure.mbar = atol(data[4]) * 1000;
+ cyl->type.workingpressure.mbar = atol(data[4]) * 1000;
if (data[5] && atoi(data[5]) > 0)
- state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.o2.permille = atol(data[5]) * 10;
+ cyl->gasmix.o2.permille = atol(data[5]) * 10;
if (data[6] && atoi(data[6]) > 0)
- state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.he.permille = atol(data[6]) * 10;
+ cyl->gasmix.he.permille = atol(data[6]) * 10;
cylinder_end(state);
@@ -136,8 +130,8 @@ static int divinglog_profile(void *param, int columns, char **data, char **colum
state->cur_sample->temperature.mkelvin = C_to_mkelvin(temp / 10.0f);
state->cur_sample->pressure[0].mbar = pressure * 100;
state->cur_sample->rbt.seconds = rbt;
- if (oldcyl != tank) {
- struct gasmix mix = state->cur_dive->cylinder[tank].gasmix;
+ if (oldcyl != tank && tank >= 0 && tank < state->cur_dive->cylinders.nr) {
+ struct gasmix mix = state->cur_dive->cylinders.cylinders[tank].gasmix;
int o2 = get_o2(mix);
int he = get_he(mix);
diff --git a/core/import-shearwater.c b/core/import-shearwater.c
index 4bed8ff18..cd5815c6e 100644
--- a/core/import-shearwater.c
+++ b/core/import-shearwater.c
@@ -18,6 +18,7 @@ static int shearwater_cylinders(void *param, int columns, char **data, char **co
UNUSED(columns);
UNUSED(column);
struct parser_state *state = (struct parser_state *)param;
+ cylinder_t *cyl;
int o2 = lrint(strtod_flags(data[0], NULL, 0) * 1000);
int he = lrint(strtod_flags(data[1], NULL, 0) * 1000);
@@ -28,8 +29,9 @@ static int shearwater_cylinders(void *param, int columns, char **data, char **co
o2 = 1000;
cylinder_start(state);
- state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.o2.permille = o2;
- state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.he.permille = he;
+ cyl = &state->cur_dive->cylinders.cylinders[state->cur_dive->cylinders.nr - 1];
+ cyl->gasmix.o2.permille = o2;
+ cyl->gasmix.he.permille = he;
cylinder_end(state);
return 0;
@@ -40,6 +42,7 @@ static int shearwater_changes(void *param, int columns, char **data, char **colu
UNUSED(columns);
UNUSED(column);
struct parser_state *state = (struct parser_state *)param;
+ cylinder_t *cyl;
if (columns != 3) {
return 1;
@@ -58,8 +61,9 @@ static int shearwater_changes(void *param, int columns, char **data, char **colu
// Find the cylinder index
int i;
bool found = false;
- for (i = 0; i < state->cur_cylinder_index; ++i) {
- if (state->cur_dive->cylinder[i].gasmix.o2.permille == o2 && state->cur_dive->cylinder[i].gasmix.he.permille == he) {
+ for (i = 0; i < state->cur_dive->cylinders.nr; ++i) {
+ const cylinder_t *cyl = &state->cur_dive->cylinders.cylinders[i];
+ if (cyl->gasmix.o2.permille == o2 && cyl->gasmix.he.permille == he) {
found = true;
break;
}
@@ -67,13 +71,13 @@ static int shearwater_changes(void *param, int columns, char **data, char **colu
if (!found) {
// Cylinder not found, creating a new one
cylinder_start(state);
- state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.o2.permille = o2;
- state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.he.permille = he;
+ cyl = &state->cur_dive->cylinders.cylinders[state->cur_dive->cylinders.nr - 1];
+ cyl->gasmix.o2.permille = o2;
+ cyl->gasmix.he.permille = he;
cylinder_end(state);
- i = state->cur_cylinder_index;
}
- add_gas_switch_event(state->cur_dive, get_dc(state), state->sample_rate ? atoi(data[0]) / state->sample_rate * 10 : atoi(data[0]), i);
+ add_gas_switch_event(state->cur_dive, get_dc(state), state->sample_rate ? atoi(data[0]) / state->sample_rate * 10 : atoi(data[0]), state->cur_dive->cylinders.nr - 1);
return 0;
}
diff --git a/core/import-suunto.c b/core/import-suunto.c
index ac01ba639..408128cb7 100644
--- a/core/import-suunto.c
+++ b/core/import-suunto.c
@@ -173,6 +173,7 @@ static int dm4_dive(void *param, int columns, char **data, char **column)
char get_events_template[] = "select * from Mark where DiveId = %d";
char get_tags_template[] = "select Text from DiveTag where DiveId = %d";
char get_events[64];
+ cylinder_t *cyl;
dive_start(state);
state->cur_dive->number = atoi(data[0]);
@@ -218,22 +219,23 @@ static int dm4_dive(void *param, int columns, char **data, char **column)
* TODO: handle multiple cylinders
*/
cylinder_start(state);
+ cyl = &state->cur_dive->cylinders.cylinders[state->cur_dive->cylinders.nr - 1];
if (data[22] && atoi(data[22]) > 0)
- state->cur_dive->cylinder[state->cur_cylinder_index].start.mbar = atoi(data[22]);
+ cyl->start.mbar = atoi(data[22]);
else if (data[10] && atoi(data[10]) > 0)
- state->cur_dive->cylinder[state->cur_cylinder_index].start.mbar = atoi(data[10]);
+ cyl->start.mbar = atoi(data[10]);
if (data[23] && atoi(data[23]) > 0)
- state->cur_dive->cylinder[state->cur_cylinder_index].end.mbar = (atoi(data[23]));
+ cyl->end.mbar = (atoi(data[23]));
if (data[11] && atoi(data[11]) > 0)
- state->cur_dive->cylinder[state->cur_cylinder_index].end.mbar = (atoi(data[11]));
+ cyl->end.mbar = (atoi(data[11]));
if (data[12])
- state->cur_dive->cylinder[state->cur_cylinder_index].type.size.mliter = lrint((strtod_flags(data[12], NULL, 0)) * 1000);
+ cyl->type.size.mliter = lrint((strtod_flags(data[12], NULL, 0)) * 1000);
if (data[13])
- state->cur_dive->cylinder[state->cur_cylinder_index].type.workingpressure.mbar = (atoi(data[13]));
+ cyl->type.workingpressure.mbar = (atoi(data[13]));
if (data[20])
- state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.o2.permille = atoi(data[20]) * 10;
+ cyl->gasmix.o2.permille = atoi(data[20]) * 10;
if (data[21])
- state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.he.permille = atoi(data[21]) * 10;
+ cyl->gasmix.he.permille = atoi(data[21]) * 10;
cylinder_end(state);
if (data[14])
@@ -324,25 +326,27 @@ static int dm5_cylinders(void *param, int columns, char **data, char **column)
UNUSED(columns);
UNUSED(column);
struct parser_state *state = (struct parser_state *)param;
+ cylinder_t *cyl;
cylinder_start(state);
+ cyl = &state->cur_dive->cylinders.cylinders[state->cur_dive->cylinders.nr - 1];
if (data[7] && atoi(data[7]) > 0 && atoi(data[7]) < 350000)
- state->cur_dive->cylinder[state->cur_cylinder_index].start.mbar = atoi(data[7]);
+ cyl->start.mbar = atoi(data[7]);
if (data[8] && atoi(data[8]) > 0 && atoi(data[8]) < 350000)
- state->cur_dive->cylinder[state->cur_cylinder_index].end.mbar = (atoi(data[8]));
+ cyl->end.mbar = (atoi(data[8]));
if (data[6]) {
/* DM5 shows tank size of 12 liters when the actual
* value is 0 (and using metric units). So we just use
* the same 12 liters when size is not available */
- if (strtod_flags(data[6], NULL, 0) == 0.0 && state->cur_dive->cylinder[state->cur_cylinder_index].start.mbar)
- state->cur_dive->cylinder[state->cur_cylinder_index].type.size.mliter = 12000;
+ if (strtod_flags(data[6], NULL, 0) == 0.0 && cyl->start.mbar)
+ cyl->type.size.mliter = 12000;
else
- state->cur_dive->cylinder[state->cur_cylinder_index].type.size.mliter = lrint((strtod_flags(data[6], NULL, 0)) * 1000);
+ cyl->type.size.mliter = lrint((strtod_flags(data[6], NULL, 0)) * 1000);
}
if (data[2])
- state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.o2.permille = atoi(data[2]) * 10;
+ cyl->gasmix.o2.permille = atoi(data[2]) * 10;
if (data[3])
- state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.he.permille = atoi(data[3]) * 10;
+ cyl->gasmix.he.permille = atoi(data[3]) * 10;
cylinder_end(state);
return 0;
}
diff --git a/core/libdivecomputer.c b/core/libdivecomputer.c
index 9787ab826..d3e5a115d 100644
--- a/core/libdivecomputer.c
+++ b/core/libdivecomputer.c
@@ -112,7 +112,9 @@ static int parse_gasmixes(device_data_t *devdata, struct dive *dive, dc_parser_t
}
bool no_volume = true;
- for (i = 0; i < MAX_CYLINDERS && (i < ngases || i < ntanks); i++) {
+ clear_cylinder_table(&dive->cylinders);
+ for (i = 0; i < ngases || i < ntanks; i++) {
+ cylinder_t cyl = { 0 };
if (i < ngases) {
dc_gasmix_t gasmix = { 0 };
int o2, he;
@@ -139,27 +141,22 @@ static int parse_gasmixes(device_data_t *devdata, struct dive *dive, dc_parser_t
}
he = 0;
}
- dive->cylinder[i].gasmix.o2.permille = o2;
- dive->cylinder[i].gasmix.he.permille = he;
- } else {
- dive->cylinder[i].gasmix.o2.permille = 0;
- dive->cylinder[i].gasmix.he.permille = 0;
+ cyl.gasmix.o2.permille = o2;
+ cyl.gasmix.he.permille = he;
}
if (i < ntanks) {
dc_tank_t tank = { 0 };
rc = dc_parser_get_field(parser, DC_FIELD_TANK, i, &tank);
if (rc == DC_STATUS_SUCCESS) {
- cylinder_t *cyl = dive->cylinder + i;
-
- cyl->type.size.mliter = lrint(tank.volume * 1000);
- cyl->type.workingpressure.mbar = lrint(tank.workpressure * 1000);
+ cyl.type.size.mliter = lrint(tank.volume * 1000);
+ cyl.type.workingpressure.mbar = lrint(tank.workpressure * 1000);
- cyl->cylinder_use = OC_GAS;
+ cyl.cylinder_use = OC_GAS;
if (tank.type & DC_TANKINFO_CC_O2)
- cyl->cylinder_use = OXYGEN;
+ cyl.cylinder_use = OXYGEN;
if (tank.type & DC_TANKINFO_CC_DILUENT)
- cyl->cylinder_use = DILUENT;
+ cyl.cylinder_use = DILUENT;
if (tank.type & DC_TANKINFO_IMPERIAL) {
if (same_string(devdata->model, "Suunto EON Steel")) {
@@ -169,13 +166,13 @@ static int parse_gasmixes(device_data_t *devdata, struct dive *dive, dc_parser_t
* First, the pressures are off by a constant factor. WTF?
* Then we can round the wet sizes so we get to multiples of 10
* for cuft sizes (as that's all that you can enter) */
- dive->cylinder[i].type.workingpressure.mbar = lrint(
- dive->cylinder[i].type.workingpressure.mbar * 206.843 / 206.7 );
+ cyl.type.workingpressure.mbar = lrint(
+ cyl.type.workingpressure.mbar * 206.843 / 206.7 );
char name_buffer[17];
- int rounded_size = lrint(ml_to_cuft(gas_volume(&dive->cylinder[i],
- dive->cylinder[i].type.workingpressure)));
+ int rounded_size = lrint(ml_to_cuft(gas_volume(&cyl,
+ cyl.type.workingpressure)));
rounded_size = (int)((rounded_size + 5) / 10) * 10;
- switch (dive->cylinder[i].type.workingpressure.mbar) {
+ switch (cyl.type.workingpressure.mbar) {
case 206843:
snprintf(name_buffer, sizeof(name_buffer), "AL%d", rounded_size);
break;
@@ -192,9 +189,9 @@ static int parse_gasmixes(device_data_t *devdata, struct dive *dive, dc_parser_t
snprintf(name_buffer, sizeof(name_buffer), "%d cuft", rounded_size);
break;
}
- dive->cylinder[i].type.description = copy_string(name_buffer);
- dive->cylinder[i].type.size.mliter = lrint(cuft_to_l(rounded_size) * 1000 /
- mbar_to_atm(dive->cylinder[i].type.workingpressure.mbar));
+ cyl.type.description = copy_string(name_buffer);
+ cyl.type.size.mliter = lrint(cuft_to_l(rounded_size) * 1000 /
+ mbar_to_atm(cyl.type.workingpressure.mbar));
}
}
if (tank.gasmix != i) { // we don't handle this, yet
@@ -213,22 +210,24 @@ static int parse_gasmixes(device_data_t *devdata, struct dive *dive, dc_parser_t
// rest of the code treats this as if they were valid values
if (!IS_FP_SAME(tank.beginpressure, 0.0)) {
if (!IS_FP_SAME(tank.endpressure, 0.0)) {
- dive->cylinder[i].start.mbar = lrint(tank.beginpressure * 1000);
- dive->cylinder[i].end.mbar = lrint(tank.endpressure * 1000);
+ cyl.start.mbar = lrint(tank.beginpressure * 1000);
+ cyl.end.mbar = lrint(tank.endpressure * 1000);
} else if (same_string(devdata->vendor, "Uwatec")) {
- dive->cylinder[i].start.mbar = lrint(tank.beginpressure * 1000 + 30000);
- dive->cylinder[i].end.mbar = 30000;
+ cyl.start.mbar = lrint(tank.beginpressure * 1000 + 30000);
+ cyl.end.mbar = 30000;
}
}
}
if (no_volume) {
/* for the first tank, if there is no tanksize available from the
* dive computer, fill in the default tank information (if set) */
- fill_default_cylinder(dive, i);
+ fill_default_cylinder(dive, &cyl);
}
/* whatever happens, make sure there is a name for the cylinder */
- if (empty_string(dive->cylinder[i].type.description))
- dive->cylinder[i].type.description = strdup(translate("gettextFromC", "unknown"));
+ if (empty_string(cyl.type.description))
+ cyl.type.description = strdup(translate("gettextFromC", "unknown"));
+
+ add_to_cylinder_table(&dive->cylinders, dive->cylinders.nr, cyl);
}
return DC_STATUS_SUCCESS;
}
@@ -294,7 +293,8 @@ static void handle_event(struct divecomputer *dc, struct sample *sample, dc_samp
static void handle_gasmix(struct divecomputer *dc, struct sample *sample, int idx)
{
- if (idx < 0 || idx >= MAX_CYLINDERS)
+ /* TODO: Verify that index is not higher than the number of cylinders */
+ if (idx < 0)
return;
add_event(dc, sample->time.seconds, SAMPLE_EVENT_GASCHANGE2, idx+1, 0, "gaschange");
current_gas_index = idx;
diff --git a/core/liquivision.c b/core/liquivision.c
index 1e430bcf1..1ea2b814a 100644
--- a/core/liquivision.c
+++ b/core/liquivision.c
@@ -148,8 +148,11 @@ static void parse_dives(int log_version, const unsigned char *buf, unsigned int
dc = &dive->dc;
/* Just the main cylinder until we can handle the buddy cylinder porperly */
- for (i = 0; i < 1; i++)
- fill_default_cylinder(dive, i);
+ for (i = 0; i < 1; i++) {
+ cylinder_t cyl = { 0 };
+ fill_default_cylinder(dive, &cyl);
+ add_to_cylinder_table(&dive->cylinders, i, cyl);
+ }
// Model 0=Xen, 1,2=Xeo, 4=Lynx, other=Liquivision
model = *(buf + ptr);
diff --git a/core/load-git.c b/core/load-git.c
index 2fdb6197b..8cefc5b9f 100644
--- a/core/load-git.c
+++ b/core/load-git.c
@@ -34,7 +34,6 @@ struct git_parser_state {
dive_trip_t *active_trip;
struct picture *active_pic;
struct dive_site *active_site;
- int cylinder_index, weightsystem_index;
int o2pressure_sensor;
};
@@ -391,23 +390,21 @@ static void parse_cylinder_keyvalue(void *_cylinder, const char *key, const char
static void parse_dive_cylinder(char *line, struct membuffer *str, struct git_parser_state *state)
{
- cylinder_t *cylinder = state->active_dive->cylinder + state->cylinder_index;
+ cylinder_t cylinder = { 0 };
- if (state->cylinder_index >= MAX_CYLINDERS)
- return;
-
- cylinder->type.description = get_utf8(str);
+ cylinder.type.description = get_utf8(str);
for (;;) {
char c;
while (isspace(c = *line))
line++;
if (!c)
break;
- line = parse_keyvalue_entry(parse_cylinder_keyvalue, cylinder, line);
+ line = parse_keyvalue_entry(parse_cylinder_keyvalue, &cylinder, line);
}
- if (cylinder->cylinder_use == OXYGEN)
- state->o2pressure_sensor = state->cylinder_index;
- state->cylinder_index++;
+ if (cylinder.cylinder_use == OXYGEN)
+ state->o2pressure_sensor = state->active_dive->cylinders.nr;
+
+ add_to_cylinder_table(&state->active_dive->cylinders, state->active_dive->cylinders.nr, cylinder);
}
static void parse_weightsystem_keyvalue(void *_ws, const char *key, const char *value)
@@ -1493,7 +1490,6 @@ static int parse_dive_entry(struct git_parser_state *state, const git_tree_entry
return report_error("Unable to read dive file");
if (*suffix)
dive->number = atoi(suffix + 1);
- state->cylinder_index = 0;
clear_weightsystem_table(&state->active_dive->weightsystems);
state->o2pressure_sensor = 1;
for_each_line(blob, dive_parser, state);
diff --git a/core/parse-xml.c b/core/parse-xml.c
index 8a7c4e2b9..02363bde6 100644
--- a/core/parse-xml.c
+++ b/core/parse-xml.c
@@ -225,7 +225,7 @@ static void cylinder_use(char *buffer, enum cylinderuse *cyl_use, struct parser_
int use = cylinderuse_from_text(buffer);
*cyl_use = use;
if (use == OXYGEN)
- state->o2pressure_sensor = state->cur_cylinder_index;
+ state->o2pressure_sensor = state->cur_dive->cylinders.nr - 1;
}
}
@@ -408,8 +408,7 @@ static void gasmix(char *buffer, fraction_t *fraction, struct parser_state *stat
/* libdivecomputer does negative percentages. */
if (*buffer == '-')
return;
- if (state->cur_cylinder_index < MAX_CYLINDERS)
- percent(buffer, fraction);
+ percent(buffer, fraction);
}
static void gasmix_nitrogen(char *buffer, struct gasmix *gasmix)
@@ -700,10 +699,12 @@ static void try_to_match_autogroup(const char *name, char *buf)
void add_gas_switch_event(struct dive *dive, struct divecomputer *dc, int seconds, int idx)
{
/* sanity check so we don't crash */
- if (idx < 0 || idx >= MAX_CYLINDERS)
+ if (idx < 0 || idx >= dive->cylinders.nr) {
+ report_error("Unknown cylinder index: %d", idx);
return;
+ }
/* The gas switch event format is insane for historical reasons */
- struct gasmix mix = dive->cylinder[idx].gasmix;
+ struct gasmix mix = dive->cylinders.cylinders[idx].gasmix;
int o2 = get_o2(mix);
int he = get_he(mix);
struct event *ev;
@@ -1000,16 +1001,35 @@ static void divinglog_place(char *place, struct dive *d, struct parser_state *st
static int divinglog_dive_match(struct dive *dive, const char *name, char *buf, struct parser_state *state)
{
+ /* For cylinder related fields, we might have to create a cylinder first. */
+ cylinder_t cyl = { 0 };
+ if (MATCH("tanktype", utf8_string, &cyl.type.description)) {
+ cylinder_t *cyl0 = get_or_create_cylinder(dive, 0);
+ free((void *)cyl0->type.description);
+ cyl0->type.description = cyl.type.description;
+ return 1;
+ }
+ if (MATCH("tanksize", cylindersize, &cyl.type.size)) {
+ get_or_create_cylinder(dive, 0)->type.size = cyl.type.size;
+ return 1;
+ }
+ if (MATCH_STATE("presw", pressure, &cyl.type.workingpressure)) {
+ get_or_create_cylinder(dive, 0)->type.workingpressure = cyl.type.workingpressure;
+ return 1;
+ }
+ if (MATCH_STATE("press", pressure, &cyl.start)) {
+ get_or_create_cylinder(dive, 0)->start = cyl.start;
+ return 1;
+ }
+ if (MATCH_STATE("prese", pressure, &cyl.end)) {
+ get_or_create_cylinder(dive, 0)->end = cyl.end;
+ return 1;
+ }
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("tanktype", utf8_string, &dive->cylinder[0].type.description) ||
- MATCH("tanksize", cylindersize, &dive->cylinder[0].type.size) ||
- MATCH_STATE("presw", pressure, &dive->cylinder[0].type.workingpressure) ||
- MATCH_STATE("press", pressure, &dive->cylinder[0].start) ||
- MATCH_STATE("prese", pressure, &dive->cylinder[0].end) ||
MATCH("comments", utf8_string, &dive->notes) ||
MATCH("names.buddy", utf8_string, &dive->buddy) ||
MATCH("name.country", utf8_string, &state->country) ||
@@ -1222,6 +1242,8 @@ static void gps_picture_location(char *buffer, struct picture *pic)
static void try_to_fill_dive(struct dive *dive, const char *name, char *buf, struct parser_state *state)
{
char *hash = NULL;
+ cylinder_t *cyl = dive->cylinders.nr > 0 ? &dive->cylinders.cylinders[dive->cylinders.nr - 1] : NULL;
+ pressure_t p;
start_match("dive", name, buf);
switch (state->import_source) {
@@ -1270,10 +1292,14 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf, str
free(hash);
return;
}
- if (MATCH_STATE("cylinderstartpressure", pressure, &dive->cylinder[0].start))
+ if (MATCH_STATE("cylinderstartpressure", pressure, &p)) {
+ get_or_create_cylinder(dive, 0)->start = p;
return;
- if (MATCH_STATE("cylinderendpressure", pressure, &dive->cylinder[0].end))
+ }
+ if (MATCH_STATE("cylinderendpressure", pressure, &p)) {
+ get_or_create_cylinder(dive, 0)->end = p;
return;
+ }
if (MATCH_STATE("gps", gps_in_dive, dive))
return;
if (MATCH_STATE("Place", gps_in_dive, dive))
@@ -1316,28 +1342,28 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf, str
return;
if (MATCH_STATE("weight", weight, &dive->weightsystems.weightsystems[dive->weightsystems.nr - 1].weight))
return;
- if (state->cur_cylinder_index < MAX_CYLINDERS) {
- if (MATCH("size.cylinder", cylindersize, &dive->cylinder[state->cur_cylinder_index].type.size))
+ if (cyl) {
+ if (MATCH("size.cylinder", cylindersize, &cyl->type.size))
return;
- if (MATCH_STATE("workpressure.cylinder", pressure, &dive->cylinder[state->cur_cylinder_index].type.workingpressure))
+ if (MATCH_STATE("workpressure.cylinder", pressure, &cyl->type.workingpressure))
return;
- if (MATCH("description.cylinder", utf8_string, &dive->cylinder[state->cur_cylinder_index].type.description))
+ if (MATCH("description.cylinder", utf8_string, &cyl->type.description))
return;
- if (MATCH_STATE("start.cylinder", pressure, &dive->cylinder[state->cur_cylinder_index].start))
+ if (MATCH_STATE("start.cylinder", pressure, &cyl->start))
return;
- if (MATCH_STATE("end.cylinder", pressure, &dive->cylinder[state->cur_cylinder_index].end))
+ if (MATCH_STATE("end.cylinder", pressure, &cyl->end))
return;
- if (MATCH_STATE("use.cylinder", cylinder_use, &dive->cylinder[state->cur_cylinder_index].cylinder_use))
+ if (MATCH_STATE("use.cylinder", cylinder_use, &cyl->cylinder_use))
return;
- if (MATCH_STATE("depth.cylinder", depth, &dive->cylinder[state->cur_cylinder_index].depth))
+ if (MATCH_STATE("depth.cylinder", depth, &cyl->depth))
return;
- if (MATCH_STATE("o2", gasmix, &dive->cylinder[state->cur_cylinder_index].gasmix.o2))
+ if (MATCH_STATE("o2", gasmix, &cyl->gasmix.o2))
return;
- if (MATCH_STATE("o2percent", gasmix, &dive->cylinder[state->cur_cylinder_index].gasmix.o2))
+ if (MATCH_STATE("o2percent", gasmix, &cyl->gasmix.o2))
return;
- if (MATCH("n2", gasmix_nitrogen, &dive->cylinder[state->cur_cylinder_index].gasmix))
+ if (MATCH("n2", gasmix_nitrogen, &cyl->gasmix))
return;
- if (MATCH_STATE("he", gasmix, &dive->cylinder[state->cur_cylinder_index].gasmix.he))
+ if (MATCH_STATE("he", gasmix, &cyl->gasmix.he))
return;
}
if (MATCH_STATE("air.divetemperature", temperature, &dive->airtemp))
@@ -1710,6 +1736,7 @@ int parse_dlf_buffer(unsigned char *buffer, size_t size, struct dive_table *tabl
struct battery_status battery_start = {0, 0, 0, 0};
struct battery_status battery_end = {0, 0, 0, 0};
uint16_t o2_sensor_calibration_values[4] = {0};
+ cylinder_t *cyl;
struct parser_state state;
init_parser_state(&state);
@@ -1765,8 +1792,9 @@ int parse_dlf_buffer(unsigned char *buffer, size_t size, struct dive_table *tabl
state.cur_dc->surface_pressure.mbar = ((ptr[25] << 8) + ptr[24]) / 10;
// Declare initial mix as first cylinder
- state.cur_dive->cylinder[0].gasmix.o2.permille = ptr[26] * 10;
- state.cur_dive->cylinder[0].gasmix.he.permille = ptr[27] * 10;
+ cyl = get_or_create_cylinder(state.cur_dive, 0);
+ cyl->gasmix.o2.permille = ptr[26] * 10;
+ cyl->gasmix.he.permille = ptr[27] * 10;
/* Done with parsing what we know about the dive header */
ptr += 32;
@@ -1874,18 +1902,20 @@ int parse_dlf_buffer(unsigned char *buffer, size_t size, struct dive_table *tabl
state.cur_event.value = ptr[7] << 8 ^ ptr[6];
found = false;
- for (i = 0; i < state.cur_cylinder_index; ++i) {
- if (state.cur_dive->cylinder[i].gasmix.o2.permille == ptr[6] * 10 && state.cur_dive->cylinder[i].gasmix.he.permille == ptr[7] * 10) {
+ for (i = 0; i < state.cur_dive->cylinders.nr; ++i) {
+ const cylinder_t *cyl = &state.cur_dive->cylinders.cylinders[i];
+ if (cyl->gasmix.o2.permille == ptr[6] * 10 && cyl->gasmix.he.permille == ptr[7] * 10) {
found = true;
break;
}
}
if (!found) {
cylinder_start(&state);
- state.cur_dive->cylinder[state.cur_cylinder_index].gasmix.o2.permille = ptr[6] * 10;
- state.cur_dive->cylinder[state.cur_cylinder_index].gasmix.he.permille = ptr[7] * 10;
+ cylinder_t *cyl = &state.cur_dive->cylinders.cylinders[state.cur_dive->cylinders.nr - 1];
+ cyl->gasmix.o2.permille = ptr[6] * 10;
+ cyl->gasmix.he.permille = ptr[7] * 10;
cylinder_end(&state);
- state.cur_event.gas.index = state.cur_cylinder_index;
+ state.cur_event.gas.index = state.cur_dive->cylinders.nr - 1;
} else {
state.cur_event.gas.index = i;
}
diff --git a/core/parse.c b/core/parse.c
index 8344d3552..dd8c612e8 100644
--- a/core/parse.c
+++ b/core/parse.c
@@ -257,7 +257,6 @@ void dive_end(struct parser_state *state)
state->cur_dc = NULL;
state->cur_location.lat.udeg = 0;
state->cur_location.lon.udeg = 0;
- state->cur_cylinder_index = 0;
}
void trip_start(struct parser_state *state)
@@ -290,11 +289,11 @@ void picture_end(struct parser_state *state)
void cylinder_start(struct parser_state *state)
{
+ add_empty_cylinder(&state->cur_dive->cylinders);
}
void cylinder_end(struct parser_state *state)
{
- state->cur_cylinder_index++;
}
void ws_start(struct parser_state *state)
diff --git a/core/parse.h b/core/parse.h
index 79ba57098..a36ca0e61 100644
--- a/core/parse.h
+++ b/core/parse.h
@@ -54,7 +54,6 @@ struct parser_state {
bool in_settings;
bool in_userid;
struct tm cur_tm;
- int cur_cylinder_index;
int lastcylinderindex, next_o2_sensor;
int o2pressure_sensor;
int sample_rate;
diff --git a/core/planner.c b/core/planner.c
index d488413c8..4a480640d 100644
--- a/core/planner.c
+++ b/core/planner.c
@@ -89,7 +89,7 @@ int get_cylinderid_at_time(struct dive *dive, struct divecomputer *dc, duration_
int get_gasidx(struct dive *dive, struct gasmix mix)
{
- return find_best_gasmix_match(mix, dive->cylinder);
+ return find_best_gasmix_match(mix, &dive->cylinders);
}
static void interpolate_transition(struct deco_state *ds, struct dive *dive, duration_t t0, duration_t t1, depth_t d0, depth_t d1, struct gasmix gasmix, o2pressure_t po2, enum divemode_t divemode)
@@ -177,10 +177,9 @@ static int tissue_at_end(struct deco_state *ds, struct dive *dive, struct deco_s
/* if a default cylinder is set, use that */
-void fill_default_cylinder(struct dive *dive, int idx)
+void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl)
{
const char *cyl_name = prefs.default_cylinder;
- cylinder_t *cyl = &dive->cylinder[idx];
struct tank_info_t *ti = tank_info;
pressure_t pO2 = {.mbar = 1600};
@@ -270,7 +269,7 @@ static void create_dive_from_plan(struct diveplan *diveplan, struct dive *dive,
/* Create first sample at time = 0, not based on dp because
* there is no real dp for time = 0, set first cylinder to 0
* O2 setpoint for this sample will be filled later from next dp */
- cyl = &dive->cylinder[0];
+ cyl = get_or_create_cylinder(dive, 0);
sample = prepare_sample(dc);
sample->sac.mliter = prefs.bottomsac;
if (track_gas && cyl->type.workingpressure.mbar)
@@ -304,7 +303,7 @@ static void create_dive_from_plan(struct diveplan *diveplan, struct dive *dive,
if (dp->cylinderid != lastcylid) {
/* need to insert a first sample for the new gas */
add_gas_switch_event(dive, dc, lasttime + 1, dp->cylinderid);
- cyl = &dive->cylinder[dp->cylinderid];
+ cyl = get_or_create_cylinder(dive, dp->cylinderid);
sample = prepare_sample(dc);
sample[-1].setpoint.mbar = po2;
sample->time.seconds = lasttime + 1;
@@ -410,7 +409,7 @@ static struct gaschanges *analyze_gaslist(struct diveplan *diveplan, struct dive
int nr = 0;
struct gaschanges *gaschanges = NULL;
struct divedatapoint *dp = diveplan->dp;
- int best_depth = dive->cylinder[*asc_cylinder].depth.mm;
+ int best_depth = dive->cylinders.cylinders[*asc_cylinder].depth.mm;
bool total_time_zero = true;
while (dp) {
if (dp->time == 0 && total_time_zero) {
@@ -445,7 +444,7 @@ static struct gaschanges *analyze_gaslist(struct diveplan *diveplan, struct dive
for (nr = 0; nr < *gaschangenr; nr++) {
int idx = gaschanges[nr].gasidx;
printf("gaschange nr %d: @ %5.2lfm gasidx %d (%s)\n", nr, gaschanges[nr].depth / 1000.0,
- idx, gasname(dive->cylinder[idx].gasmix));
+ idx, gasname(dive->cylinders.cylinders[idx].gasmix));
}
#endif
return gaschanges;
@@ -528,7 +527,7 @@ int ascent_velocity(int depth, int avg_depth, int bottom_time)
static void track_ascent_gas(int depth, struct dive *dive, int cylinder_id, int avg_depth, int bottom_time, bool safety_stop, enum divemode_t divemode)
{
- cylinder_t *cylinder = &dive->cylinder[cylinder_id];
+ cylinder_t *cylinder = &dive->cylinders.cylinders[cylinder_id];
while (depth > 0) {
int deltad = ascent_velocity(depth, avg_depth, bottom_time) * TIMESTEP;
if (deltad > depth)
@@ -596,7 +595,10 @@ static bool trial_ascent(struct deco_state *ds, int wait_time, int trial_depth,
*/
static bool enough_gas(const struct dive *dive, int current_cylinder)
{
- const cylinder_t *cyl = &dive->cylinder[current_cylinder];
+ cylinder_t *cyl;
+ if (current_cylinder < 0 || current_cylinder >= dive->cylinders.nr)
+ return false;
+ cyl = &dive->cylinders.cylinders[current_cylinder];
if (!cyl->start.mbar)
return true;
@@ -730,7 +732,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
const struct event *ev = NULL;
divemode = UNDEF_COMP_TYPE;
divemode = get_current_divemode(&dive->dc, bottom_time, &ev, &divemode);
- gas = dive->cylinder[current_cylinder].gasmix;
+ gas = dive->cylinders.cylinders[current_cylinder].gasmix;
po2 = sample->setpoint.mbar;
depth = dive->dc.sample[dive->dc.samples - 1].depth.mm;
@@ -785,11 +787,11 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
// How long can we stay at the current depth and still directly ascent to the surface?
do {
add_segment(ds, depth_to_bar(depth, dive),
- dive->cylinder[current_cylinder].gasmix,
+ dive->cylinders.cylinders[current_cylinder].gasmix,
timestep, po2, divemode, prefs.bottomsac);
- update_cylinder_pressure(dive, depth, depth, timestep, prefs.bottomsac, &dive->cylinder[current_cylinder], false, divemode);
+ update_cylinder_pressure(dive, depth, depth, timestep, prefs.bottomsac, &dive->cylinders.cylinders[current_cylinder], false, divemode);
clock += timestep;
- } while (trial_ascent(ds, 0, depth, 0, avg_depth, bottom_time, dive->cylinder[current_cylinder].gasmix,
+ } while (trial_ascent(ds, 0, depth, 0, avg_depth, bottom_time, dive->cylinders.cylinders[current_cylinder].gasmix,
po2, diveplan->surface_pressure / 1000.0, dive, divemode) &&
enough_gas(dive, current_cylinder) && clock < 6 * 3600);
@@ -797,7 +799,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
// In the best of all worlds, we would roll back also the last add_segment in terms of caching deco state, but
// let's ignore that since for the eventual ascent in recreational mode, nobody looks at the ceiling anymore,
// so we don't really have to compute the deco state.
- update_cylinder_pressure(dive, depth, depth, -timestep, prefs.bottomsac, &dive->cylinder[current_cylinder], false, divemode);
+ update_cylinder_pressure(dive, depth, depth, -timestep, prefs.bottomsac, &dive->cylinders.cylinders[current_cylinder], false, divemode);
clock -= timestep;
plan_add_segment(diveplan, clock - previous_point_time, depth, current_cylinder, po2, true, divemode);
previous_point_time = clock;
@@ -835,7 +837,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
if (best_first_ascend_cylinder != current_cylinder) {
current_cylinder = best_first_ascend_cylinder;
- gas = dive->cylinder[current_cylinder].gasmix;
+ gas = dive->cylinders.cylinders[current_cylinder].gasmix;
#if DEBUG_PLAN & 16
printf("switch to gas %d (%d/%d) @ %5.2lfm\n", best_first_ascend_cylinder,
@@ -849,7 +851,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
divemode = OC;
po2 = 0;
add_segment(ds, depth_to_bar(depth, dive),
- dive->cylinder[current_cylinder].gasmix,
+ dive->cylinders.cylinders[current_cylinder].gasmix,
prefs.min_switch_duration, po2, divemode, prefs.bottomsac);
plan_add_segment(diveplan, prefs.min_switch_duration, depth, current_cylinder, po2, false, divemode);
clock += prefs.min_switch_duration;
@@ -891,7 +893,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
last_ascend_rate = ascent_velocity(depth, avg_depth, bottom_time);
/* Always prefer the best_first_ascend_cylinder if it has the right gasmix.
* Otherwise take first cylinder from list with rightgasmix */
- if (same_gasmix(gas, dive->cylinder[best_first_ascend_cylinder].gasmix))
+ if (same_gasmix(gas, dive->cylinders.cylinders[best_first_ascend_cylinder].gasmix))
current_cylinder = best_first_ascend_cylinder;
else
current_cylinder = get_gasidx(dive, gas);
@@ -916,7 +918,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
deltad = depth - stoplevels[stopidx];
add_segment(ds, depth_to_bar(depth, dive),
- dive->cylinder[current_cylinder].gasmix,
+ dive->cylinders.cylinders[current_cylinder].gasmix,
TIMESTEP, po2, divemode, prefs.decosac);
last_segment_min_switch = false;
clock += TIMESTEP;
@@ -941,21 +943,21 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
if (current_cylinder != gaschanges[gi].gasidx) {
if (!prefs.switch_at_req_stop ||
!trial_ascent(ds, 0, depth, stoplevels[stopidx - 1], avg_depth, bottom_time,
- dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0, dive, divemode) || get_o2(dive->cylinder[current_cylinder].gasmix) < 160) {
+ dive->cylinders.cylinders[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0, dive, divemode) || get_o2(dive->cylinders.cylinders[current_cylinder].gasmix) < 160) {
if (is_final_plan)
plan_add_segment(diveplan, clock - previous_point_time, depth, current_cylinder, po2, false, divemode);
stopping = true;
previous_point_time = clock;
current_cylinder = gaschanges[gi].gasidx;
- gas = dive->cylinder[current_cylinder].gasmix;
+ gas = dive->cylinders.cylinders[current_cylinder].gasmix;
#if DEBUG_PLAN & 16
printf("switch to gas %d (%d/%d) @ %5.2lfm\n", gaschanges[gi].gasidx,
(get_o2(&gas) + 5) / 10, (get_he(&gas) + 5) / 10, gaschanges[gi].depth / 1000.0);
#endif
/* Stop for the minimum duration to switch gas unless we switch to o2 */
- if (!last_segment_min_switch && get_o2(dive->cylinder[current_cylinder].gasmix) != 1000) {
+ if (!last_segment_min_switch && get_o2(dive->cylinders.cylinders[current_cylinder].gasmix) != 1000) {
add_segment(ds, depth_to_bar(depth, dive),
- dive->cylinder[current_cylinder].gasmix,
+ dive->cylinders.cylinders[current_cylinder].gasmix,
prefs.min_switch_duration, po2, divemode, prefs.decosac);
clock += prefs.min_switch_duration;
last_segment_min_switch = true;
@@ -975,7 +977,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
while (1) {
/* Check if ascending to next stop is clear, go back and wait if we hit the ceiling on the way */
if (trial_ascent(ds, 0, depth, stoplevels[stopidx], avg_depth, bottom_time,
- dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0, dive, divemode)) {
+ dive->cylinders.cylinders[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0, dive, divemode)) {
decostoptable[decostopcounter].depth = depth;
decostoptable[decostopcounter].time = 0;
decostopcounter++;
@@ -1001,15 +1003,15 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
*/
if (pendinggaschange) {
current_cylinder = gaschanges[gi + 1].gasidx;
- gas = dive->cylinder[current_cylinder].gasmix;
+ gas = dive->cylinders.cylinders[current_cylinder].gasmix;
#if DEBUG_PLAN & 16
printf("switch to gas %d (%d/%d) @ %5.2lfm\n", gaschanges[gi + 1].gasidx,
(get_o2(&gas) + 5) / 10, (get_he(&gas) + 5) / 10, gaschanges[gi + 1].depth / 1000.0);
#endif
/* Stop for the minimum duration to switch gas unless we switch to o2 */
- if (!last_segment_min_switch && get_o2(dive->cylinder[current_cylinder].gasmix) != 1000) {
+ if (!last_segment_min_switch && get_o2(dive->cylinders.cylinders[current_cylinder].gasmix) != 1000) {
add_segment(ds, depth_to_bar(depth, dive),
- dive->cylinder[current_cylinder].gasmix,
+ dive->cylinders.cylinders[current_cylinder].gasmix,
prefs.min_switch_duration, po2, divemode, prefs.decosac);
clock += prefs.min_switch_duration;
last_segment_min_switch = true;
@@ -1018,7 +1020,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
}
int new_clock = wait_until(ds, dive, clock, clock, laststoptime * 2 + 1, timestep, depth, stoplevels[stopidx], avg_depth,
- bottom_time, dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0, divemode);
+ bottom_time, dive->cylinders.cylinders[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0, divemode);
laststoptime = new_clock - clock;
/* Finish infinite deco */
if (laststoptime >= 48 * 3600 && depth >= 6000) {
@@ -1033,12 +1035,12 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
* backgas. This could be customized if there were demand.
*/
if (break_cylinder == -1) {
- if (get_o2(dive->cylinder[best_first_ascend_cylinder].gasmix) <= 320)
+ if (get_o2(dive->cylinders.cylinders[best_first_ascend_cylinder].gasmix) <= 320)
break_cylinder = best_first_ascend_cylinder;
else
break_cylinder = 0;
}
- if (get_o2(dive->cylinder[current_cylinder].gasmix) == 1000) {
+ if (get_o2(dive->cylinders.cylinders[current_cylinder].gasmix) == 1000) {
if (laststoptime >= 12 * 60) {
laststoptime = 12 * 60;
new_clock = clock + laststoptime;
@@ -1049,7 +1051,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
plan_add_segment(diveplan, laststoptime, depth, current_cylinder, po2, false, divemode);
previous_point_time = clock + laststoptime;
current_cylinder = break_cylinder;
- gas = dive->cylinder[current_cylinder].gasmix;
+ gas = dive->cylinders.cylinders[current_cylinder].gasmix;
}
} else if (o2break_next) {
if (laststoptime >= 6 * 60) {
@@ -1061,11 +1063,11 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
plan_add_segment(diveplan, laststoptime, depth, current_cylinder, po2, false, divemode);
previous_point_time = clock + laststoptime;
current_cylinder = breakfrom_cylinder;
- gas = dive->cylinder[current_cylinder].gasmix;
+ gas = dive->cylinders.cylinders[current_cylinder].gasmix;
}
}
}
- add_segment(ds, depth_to_bar(depth, dive), dive->cylinder[stop_cylinder].gasmix,
+ add_segment(ds, depth_to_bar(depth, dive), dive->cylinders.cylinders[stop_cylinder].gasmix,
laststoptime, po2, divemode, prefs.decosac);
last_segment_min_switch = false;
decostoptable[decostopcounter].depth = depth;
@@ -1099,14 +1101,12 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
}
if (prefs.surface_segment != 0) {
- for (int i = 0; i < MAX_CYLINDERS; i++)
- if (cylinder_nodata(&dive->cylinder[i])) {
- // Switch to an empty air cylinder for breathing air at the surface
- // If no empty cylinder is found, keep using last deco gas
- current_cylinder = i;
- dive->cylinder[i].cylinder_use = NOT_USED;
- break;
- }
+ // Switch to an empty air cylinder for breathing air at the surface
+ // If no empty cylinder is found, keep using last deco gas
+ cylinder_t cyl = { 0 };
+ cyl.cylinder_use = NOT_USED;
+ add_to_cylinder_table(&dive->cylinders, dive->cylinders.nr, cyl);
+ current_cylinder = dive->cylinders.nr - 1;
plan_add_segment(diveplan, prefs.surface_segment, 0, current_cylinder, 0, false, OC);
}
create_dive_from_plan(diveplan, dive, is_planner);
diff --git a/core/plannernotes.c b/core/plannernotes.c
index 0bfdbe7d5..dd909108a 100644
--- a/core/plannernotes.c
+++ b/core/plannernotes.c
@@ -190,13 +190,13 @@ void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_d
nextdp = dp->next;
if (dp->time == 0)
continue;
- gasmix = dive->cylinder[dp->cylinderid].gasmix;
+ gasmix = dive->cylinders.cylinders[dp->cylinderid].gasmix;
depthvalue = get_depth_units(dp->depth.mm, &decimals, &depth_unit);
/* analyze the dive points ahead */
while (nextdp && nextdp->time == 0)
nextdp = nextdp->next;
if (nextdp)
- newgasmix = dive->cylinder[nextdp->cylinderid].gasmix;
+ newgasmix = dive->cylinders.cylinders[nextdp->cylinderid].gasmix;
gaschange_after = (nextdp && (gasmix_distance(gasmix, newgasmix)));
gaschange_before = (gasmix_distance(lastprintgasmix, gasmix));
rebreatherchange_after = (nextdp && (dp->setpoint != nextdp->setpoint || dp->divemode != nextdp->divemode));
@@ -461,16 +461,14 @@ void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_d
free(temp);
/* Print gas consumption: This loop covers all cylinders */
- for (int gasidx = 0; gasidx < MAX_CYLINDERS; gasidx++) {
+ for (int gasidx = 0; gasidx < dive->cylinders.nr; gasidx++) {
double volume, pressure, deco_volume, deco_pressure, mingas_volume, mingas_pressure, mingas_d_pressure, mingas_depth;
const char *unit, *pressure_unit, *depth_unit;
char warning[1000] = "";
char mingas[1000] = "";
- cylinder_t *cyl = &dive->cylinder[gasidx];
+ cylinder_t *cyl = &dive->cylinders.cylinders[gasidx];
if (cyl->cylinder_use == NOT_USED)
continue;
- if (cylinder_none(cyl))
- break;
volume = get_volume_units(cyl->gas_used.mliter, NULL, &unit);
deco_volume = get_volume_units(cyl->deco_gas_used.mliter, NULL, &unit);
@@ -583,7 +581,7 @@ void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_d
while (dp) {
if (dp->time != 0) {
struct gas_pressures pressures;
- struct gasmix gasmix = dive->cylinder[dp->cylinderid].gasmix;
+ struct gasmix gasmix = dive->cylinders.cylinders[dp->cylinderid].gasmix;
current_divemode = get_current_divemode(&dive->dc, dp->time, &evd, &current_divemode);
amb = depth_to_atm(dp->depth.mm, dive);
diff --git a/core/profile.c b/core/profile.c
index 8fd669989..4d35155b2 100644
--- a/core/profile.c
+++ b/core/profile.c
@@ -189,7 +189,7 @@ static int get_local_sac(struct plot_info *pi, int idx1, int idx2, struct dive *
depth = (entry1->depth + entry2->depth) / 2;
atm = depth_to_atm(depth, dive);
- cyl = dive->cylinder + index;
+ cyl = dive->cylinders.cylinders + index;
airuse = gas_volume(cyl, a) - gas_volume(cyl, b);
@@ -334,7 +334,7 @@ int get_cylinder_index(const struct dive *dive, const struct event *ev)
fprintf(stderr, "Still looking up cylinder based on gas mix in get_cylinder_index()!\n");
mix = get_gasmix_from_event(dive, ev);
- best = find_best_gasmix_match(mix, dive->cylinder);
+ best = find_best_gasmix_match(mix, &dive->cylinders);
return best < 0 ? 0 : best;
}
@@ -413,8 +413,8 @@ static void calculate_max_limits_new(struct dive *dive, struct divecomputer *giv
int cyl;
/* Get the per-cylinder maximum pressure if they are manual */
- for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
- int mbar = dive->cylinder[cyl].start.mbar;
+ for (cyl = 0; cyl < dive->cylinders.nr; cyl++) {
+ int mbar = dive->cylinders.cylinders[cyl].start.mbar;
if (mbar > maxpressure)
maxpressure = mbar;
if (mbar < minpressure)
@@ -534,7 +534,8 @@ static void populate_plot_entries(struct dive *dive, struct divecomputer *dc, st
nr = dc->samples + 6 + maxtime / 10 + count_events(dc);
plot_data = calloc(nr, sizeof(struct plot_data));
pi->entry = plot_data;
- pi->pressures = calloc(nr * MAX_CYLINDERS, sizeof(struct plot_pressure_data));
+ pi->nr_cylinders = dive->cylinders.nr;
+ pi->pressures = calloc(nr * (size_t)pi->nr_cylinders, sizeof(struct plot_pressure_data));
if (!plot_data)
return;
pi->nr = nr;
@@ -666,7 +667,7 @@ static int sac_between(struct dive *dive, struct plot_info *pi, int first, int l
/* Get airuse for the set of cylinders over the range */
airuse = 0;
- for (i = 0; i < MAX_CYLINDERS; i++) {
+ for (i = 0; i < pi->nr_cylinders; i++) {
pressure_t a, b;
cylinder_t *cyl;
int cyluse;
@@ -676,7 +677,7 @@ static int sac_between(struct dive *dive, struct plot_info *pi, int first, int l
a.mbar = get_plot_pressure(pi, first, i);
b.mbar = get_plot_pressure(pi, last, i);
- cyl = dive->cylinder + i;
+ cyl = dive->cylinders.cylinders + i;
cyluse = gas_volume(cyl, a) - gas_volume(cyl, b);
if (cyluse > 0)
airuse += cyluse;
@@ -708,7 +709,7 @@ static bool all_pressures(struct plot_info *pi, int idx, const bool gases[])
{
int i;
- for (i = 0; i < MAX_CYLINDERS; i++) {
+ for (i = 0; i < pi->nr_cylinders; i++) {
if (gases[i] && !get_plot_pressure(pi, idx, i))
return false;
}
@@ -722,7 +723,7 @@ static bool filter_pressures(struct plot_info *pi, int idx, const bool gases_in[
int i;
bool has_pressure = false;
- for (i = 0; i < MAX_CYLINDERS; i++) {
+ for (i = 0; i < pi->nr_cylinders; i++) {
gases_out[i] = gases_in[i] && get_plot_pressure(pi, idx, i);
has_pressure |= gases_out[i];
}
@@ -798,8 +799,8 @@ static void matching_gases(struct dive *dive, struct gasmix gasmix, bool gases[]
{
int i;
- for (i = 0; i < MAX_CYLINDERS; i++)
- gases[i] = same_gasmix(gasmix, dive->cylinder[i].gasmix);
+ for (i = 0; i < dive->cylinders.nr; i++)
+ gases[i] = same_gasmix(gasmix, dive->cylinders.cylinders[i].gasmix);
}
static void calculate_sac(struct dive *dive, struct divecomputer *dc, struct plot_info *pi)
@@ -808,12 +809,11 @@ static void calculate_sac(struct dive *dive, struct divecomputer *dc, struct plo
const struct event *ev = NULL;
bool *gases, *gases_scratch;
- gases = malloc(MAX_CYLINDERS * sizeof(*gases));
- memset(gases, 0, MAX_CYLINDERS * sizeof(*gases));
+ gases = calloc(pi->nr_cylinders, sizeof(*gases));
/* This might be premature optimization, but let's allocate the gas array for
* the fill_sac function only once an not once per sample */
- gases_scratch = malloc(MAX_CYLINDERS * sizeof(*gases));
+ gases_scratch = malloc(pi->nr_cylinders * sizeof(*gases));
for (int i = 0; i < pi->nr; i++) {
struct plot_data *entry = pi->entry + i;
@@ -855,12 +855,12 @@ static void setup_gas_sensor_pressure(const struct dive *dive, const struct dive
{
int prev, i;
const struct event *ev;
- int *seen = malloc(MAX_CYLINDERS * sizeof(*seen));
- int *first = malloc(MAX_CYLINDERS * sizeof(*first));
- int *last = malloc(MAX_CYLINDERS * sizeof(*last));
+ int *seen = malloc(pi->nr_cylinders * sizeof(*seen));
+ int *first = malloc(pi->nr_cylinders * sizeof(*first));
+ int *last = malloc(pi->nr_cylinders * sizeof(*last));
const struct divecomputer *secondary;
- for (i = 0; i < MAX_CYLINDERS; i++) {
+ for (i = 0; i < pi->nr_cylinders; i++) {
seen[i] = 0;
first[i] = 0;
last[i] = INT_MAX;
@@ -889,8 +889,8 @@ static void setup_gas_sensor_pressure(const struct dive *dive, const struct dive
// Fill in "seen[]" array - mark cylinders we're not interested
// in as negative.
- for (i = 0; i < MAX_CYLINDERS; i++) {
- const cylinder_t *cyl = dive->cylinder + i;
+ for (i = 0; i < pi->nr_cylinders; i++) {
+ const cylinder_t *cyl = dive->cylinders.cylinders + i;
int start = cyl->start.mbar;
int end = cyl->end.mbar;
@@ -918,10 +918,9 @@ static void setup_gas_sensor_pressure(const struct dive *dive, const struct dive
}
}
-
- for (i = 0; i < MAX_CYLINDERS; i++) {
+ for (i = 0; i < pi->nr_cylinders; i++) {
if (seen[i] >= 0) {
- const cylinder_t *cyl = dive->cylinder + i;
+ const cylinder_t *cyl = dive->cylinders.cylinders + i;
add_plot_pressure(pi, first[i], i, cyl->start);
add_plot_pressure(pi, last[i], i, cyl->end);
@@ -1398,7 +1397,7 @@ void create_plot_info_new(struct dive *dive, struct divecomputer *dc, struct plo
check_setpoint_events(dive, dc, pi); /* Populate setpoints */
setup_gas_sensor_pressure(dive, dc, pi); /* Try to populate our gas pressure knowledge */
if (!fast) {
- for (int cyl = 0; cyl < MAX_CYLINDERS; cyl++)
+ for (int cyl = 0; cyl < pi->nr_cylinders; cyl++)
populate_pressure_information(dive, dc, pi, cyl);
}
fill_o2_values(dive, dc, pi); /* .. and insert the O2 sensor data having 0 values. */
@@ -1439,11 +1438,11 @@ static void plot_string(struct plot_info *pi, int idx, struct membuffer *b)
depthvalue = get_depth_units(entry->depth, NULL, &depth_unit);
put_format_loc(b, translate("gettextFromC", "@: %d:%02d\nD: %.1f%s\n"), FRACTION(entry->sec, 60), depthvalue, depth_unit);
- for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
+ for (cyl = 0; cyl < pi->nr_cylinders; cyl++) {
int mbar = get_plot_pressure(pi, idx, cyl);
if (!mbar)
continue;
- struct gasmix mix = displayed_dive.cylinder[cyl].gasmix;
+ struct gasmix mix = displayed_dive.cylinders.cylinders[cyl].gasmix;
pressurevalue = get_pressure_units(mbar, &pressure_unit);
put_format_loc(b, translate("gettextFromC", "P: %d%s (%s)\n"), pressurevalue, pressure_unit, gasname(mix));
}
@@ -1707,7 +1706,7 @@ void compare_samples(struct plot_info *pi, int idx1, int idx2, char *buf, int bu
pressurevalue = get_pressure_units(bar_used, &pressure_unit);
memcpy(buf2, buf, bufsize);
snprintf_loc(buf, bufsize, translate("gettextFromC", "%s ΔP:%d%s"), buf2, pressurevalue, pressure_unit);
- cylinder_t *cyl = displayed_dive.cylinder + 0;
+ cylinder_t *cyl = displayed_dive.cylinders.cylinders + 0;
/* if we didn't cross a tank change and know the cylidner size as well, show SAC rate */
if (!crossed_tankchange && cyl->type.size.mliter) {
double volume_value;
diff --git a/core/qthelper.cpp b/core/qthelper.cpp
index 700854ebc..b8afd8267 100644
--- a/core/qthelper.cpp
+++ b/core/qthelper.cpp
@@ -389,9 +389,9 @@ QVector<QPair<QString, int>> selectedDivesGasUsed()
if (!d->selected)
continue;
volume_t *diveGases = get_gas_used(d);
- for (j = 0; j < MAX_CYLINDERS; j++) {
+ for (j = 0; j < d->cylinders.nr; j++) {
if (diveGases[j].mliter) {
- QString gasName = gasname(d->cylinder[j].gasmix);
+ QString gasName = gasname(d->cylinders.cylinders[j].gasmix);
gasUsed[gasName] += diveGases[j].mliter;
}
}
@@ -1186,7 +1186,7 @@ QString get_gas_string(struct gasmix gas)
QString get_divepoint_gas_string(struct dive *d, const divedatapoint &p)
{
int idx = p.cylinderid;
- return get_gas_string(d->cylinder[idx].gasmix);
+ return get_gas_string(d->cylinders.cylinders[idx].gasmix);
}
QString get_taglist_string(struct tag_entry *tag_list)
diff --git a/core/save-git.c b/core/save-git.c
index ae299af24..662891153 100644
--- a/core/save-git.c
+++ b/core/save-git.c
@@ -138,7 +138,7 @@ static void save_cylinder_info(struct membuffer *b, struct dive *dive)
nr = nr_cylinders(dive);
for (i = 0; i < nr; i++) {
- cylinder_t *cylinder = dive->cylinder + i;
+ cylinder_t *cylinder = dive->cylinders.cylinders + i;
int volume = cylinder->type.size.mliter;
const char *description = cylinder->type.description;
int use = cylinder->cylinder_use;
diff --git a/core/save-html.c b/core/save-html.c
index 09d7152d4..380f2fa8e 100644
--- a/core/save-html.c
+++ b/core/save-html.c
@@ -132,7 +132,7 @@ static void put_cylinder_HTML(struct membuffer *b, struct dive *dive)
put_string(b, separator);
for (i = 0; i < nr; i++) {
- cylinder_t *cylinder = dive->cylinder + i;
+ cylinder_t *cylinder = dive->cylinders.cylinders + i;
put_format(b, "%s{", separator);
separator = ", ";
write_attribute(b, "Type", cylinder->type.description, ", ");
diff --git a/core/save-profiledata.c b/core/save-profiledata.c
index 4f7440708..bc5a8e3a5 100644
--- a/core/save-profiledata.c
+++ b/core/save-profiledata.c
@@ -37,7 +37,7 @@ static void put_pd(struct membuffer *b, const struct plot_info *pi, int idx)
put_int(b, entry->in_deco);
put_int(b, entry->sec);
- for (int c = 0; c < MAX_CYLINDERS; c++) {
+ for (int c = 0; c < pi->nr_cylinders; c++) {
put_int(b, get_plot_sensor_pressure(pi, idx, c));
put_int(b, get_plot_interpolated_pressure(pi, idx, c));
}
@@ -103,11 +103,11 @@ static void put_pd(struct membuffer *b, const struct plot_info *pi, int idx)
put_int(b, entry->icd_warning ? 1 : 0);
}
-static void put_headers(struct membuffer *b)
+static void put_headers(struct membuffer *b, int nr_cylinders)
{
put_csv_string(b, "in_deco");
put_csv_string(b, "sec");
- for (int c = 0; c < MAX_CYLINDERS; c++) {
+ for (int c = 0; c < nr_cylinders; c++) {
put_format(b, "\"pressure_%d_cylinder\", ", c);
put_format(b, "\"pressure_%d_interpolated\", ", c);
}
@@ -203,7 +203,7 @@ static void save_profiles_buffer(struct membuffer *b, bool select_only)
if (select_only && !dive->selected)
continue;
create_plot_info_new(dive, &dive->dc, &pi, false, planner_deco_state);
- put_headers(b);
+ put_headers(b, pi.nr_cylinders);
put_format(b, "\n");
for (int i = 0; i < pi.nr; i++) {
diff --git a/core/save-xml.c b/core/save-xml.c
index 356ee36a7..a7bf6b23e 100644
--- a/core/save-xml.c
+++ b/core/save-xml.c
@@ -179,7 +179,7 @@ static void save_cylinder_info(struct membuffer *b, struct dive *dive)
nr = nr_cylinders(dive);
for (i = 0; i < nr; i++) {
- cylinder_t *cylinder = dive->cylinder + i;
+ cylinder_t *cylinder = dive->cylinders.cylinders + i;
int volume = cylinder->type.size.mliter;
const char *description = cylinder->type.description;
int use = cylinder->cylinder_use;
diff --git a/core/statistics.c b/core/statistics.c
index d5ef58955..fa7985c90 100644
--- a/core/statistics.c
+++ b/core/statistics.c
@@ -330,13 +330,15 @@ 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;
- if (cylinder_none(&dive->cylinder[idx]))
+ cylinder_t *cyl;
+ if (idx < 0 || idx >= dive->cylinders.nr)
return false;
- if ((dive->cylinder[idx].start.mbar - dive->cylinder[idx].end.mbar) > SOME_GAS)
+ cyl = &dive->cylinders.cylinders[idx];
+ if ((cyl->start.mbar - cyl->end.mbar) > SOME_GAS)
return true;
- if ((dive->cylinder[idx].sample_start.mbar - dive->cylinder[idx].sample_end.mbar) > SOME_GAS)
+ if ((cyl->sample_start.mbar - cyl->sample_end.mbar) > SOME_GAS)
return true;
for_each_dc(dive, dc) {
@@ -349,7 +351,7 @@ 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 (cylinder_none(&dive->cylinder[idx]))
+ if (idx < 0 || idx >= dive->cylinders.nr)
return false;
for_each_dc(dive, dc) {
@@ -359,15 +361,15 @@ bool is_cylinder_prot(const struct dive *dive, int idx)
return false;
}
-/* Returns a dynamically allocated array with MAX_CYLINDERS entries that
- * has to be freed by the caller */
+/* Returns a dynamically allocated array with dive->cylinders.nr entries,
+ * which has to be freed by the caller */
volume_t *get_gas_used(struct dive *dive)
{
int idx;
- volume_t *gases = malloc(MAX_CYLINDERS * sizeof(volume_t));
- for (idx = 0; idx < MAX_CYLINDERS; idx++) {
- cylinder_t *cyl = &dive->cylinder[idx];
+ volume_t *gases = malloc(dive->cylinders.nr * sizeof(volume_t));
+ for (idx = 0; idx < dive->cylinders.nr; idx++) {
+ cylinder_t *cyl = &dive->cylinders.cylinders[idx];
pressure_t start, end;
start = cyl->start.mbar ? cyl->start : cyl->sample_start;
@@ -403,10 +405,10 @@ void selected_dives_gas_parts(volume_t *o2_tot, volume_t *he_tot)
if (!d->selected)
continue;
volume_t *diveGases = get_gas_used(d);
- for (j = 0; j < MAX_CYLINDERS; j++) {
+ for (j = 0; j < d->cylinders.nr; j++) {
if (diveGases[j].mliter) {
volume_t o2 = {}, he = {};
- get_gas_parts(d->cylinder[j].gasmix, diveGases[j], O2_IN_AIR, &o2, &he);
+ get_gas_parts(d->cylinders.cylinders[j].gasmix, diveGases[j], O2_IN_AIR, &o2, &he);
o2_tot->mliter += o2.mliter;
he_tot->mliter += he.mliter;
}
diff --git a/core/subsurface-qt/DiveObjectHelper.cpp b/core/subsurface-qt/DiveObjectHelper.cpp
index 5146a6ea1..1deffdd4e 100644
--- a/core/subsurface-qt/DiveObjectHelper.cpp
+++ b/core/subsurface-qt/DiveObjectHelper.cpp
@@ -32,7 +32,7 @@ static QString getFormattedWeight(const struct dive *dive, unsigned int idx)
static QString getFormattedCylinder(const struct dive *dive, unsigned int idx)
{
- const cylinder_t *cyl = &dive->cylinder[idx];
+ const cylinder_t *cyl = &dive->cylinders.cylinders[idx];
const char *desc = cyl->type.description;
if (!desc && idx > 0)
return QString();
@@ -46,7 +46,7 @@ static QString getFormattedCylinder(const struct dive *dive, unsigned int idx)
static QString getPressures(const struct dive *dive, int i, enum returnPressureSelector ret)
{
- const cylinder_t *cyl = &dive->cylinder[i];
+ const cylinder_t *cyl = &dive->cylinders.cylinders[i];
QString fmt;
if (ret == START_PRESSURE) {
if (cyl->start.mbar)
@@ -101,13 +101,13 @@ static QString formatGas(const dive *d)
* from the get_gas_string function or this is correct?
*/
QString gas, gases;
- for (int i = 0; i < MAX_CYLINDERS; i++) {
+ for (int i = 0; i < d->cylinders.nr; i++) {
if (!is_cylinder_used(d, i))
continue;
- gas = d->cylinder[i].type.description;
+ gas = d->cylinders.cylinders[i].type.description;
if (!gas.isEmpty())
gas += QChar(' ');
- gas += gasname(d->cylinder[i].gasmix);
+ gas += gasname(d->cylinders.cylinders[i].gasmix);
// if has a description and if such gas is not already present
if (!gas.isEmpty() && gases.indexOf(gas) == -1) {
if (!gases.isEmpty())
@@ -155,10 +155,8 @@ static QStringList formatWeights(const dive *d)
QStringList formatCylinders(const dive *d)
{
QStringList cylinders;
- for (int i = 0; i < MAX_CYLINDERS; i++) {
+ for (int i = 0; i < d->cylinders.nr; i++) {
QString cyl = getFormattedCylinder(d, i);
- if (cyl.isEmpty())
- continue;
cylinders << cyl;
}
return cylinders;
@@ -167,10 +165,10 @@ QStringList formatCylinders(const dive *d)
static QVector<CylinderObjectHelper> makeCylinderObjects(const dive *d)
{
QVector<CylinderObjectHelper> res;
- for (int i = 0; i < MAX_CYLINDERS; i++) {
+ for (int i = 0; i < d->cylinders.nr; i++) {
//Don't add blank cylinders, only those that have been defined.
- if (d->cylinder[i].type.description)
- res.append(CylinderObjectHelper(&d->cylinder[i])); // no emplace for QVector. :(
+ if (d->cylinders.cylinders[i].type.description)
+ res.append(CylinderObjectHelper(&d->cylinders.cylinders[i])); // no emplace for QVector. :(
}
return res;
}
@@ -178,9 +176,9 @@ static QVector<CylinderObjectHelper> makeCylinderObjects(const dive *d)
QStringList formatGetCylinder(const dive *d)
{
QStringList getCylinder;
- for (int i = 0; i < MAX_CYLINDERS; i++) {
+ for (int i = 0; i < d->cylinders.nr; i++) {
if (is_cylinder_used(d, i))
- getCylinder << d->cylinder[i].type.description;
+ getCylinder << d->cylinders.cylinders[i].type.description;
}
return getCylinder;
}
@@ -188,7 +186,7 @@ QStringList formatGetCylinder(const dive *d)
QStringList getStartPressure(const dive *d)
{
QStringList startPressure;
- for (int i = 0; i < MAX_CYLINDERS; i++) {
+ for (int i = 0; i < d->cylinders.nr; i++) {
if (is_cylinder_used(d, i))
startPressure << getPressures(d, i, START_PRESSURE);
}
@@ -198,7 +196,7 @@ QStringList getStartPressure(const dive *d)
QStringList getEndPressure(const dive *d)
{
QStringList endPressure;
- for (int i = 0; i < MAX_CYLINDERS; i++) {
+ for (int i = 0; i < d->cylinders.nr; i++) {
if (is_cylinder_used(d, i))
endPressure << getPressures(d, i, END_PRESSURE);
}
@@ -208,9 +206,9 @@ QStringList getEndPressure(const dive *d)
QStringList getFirstGas(const dive *d)
{
QStringList gas;
- for (int i = 0; i < MAX_CYLINDERS; i++) {
+ for (int i = 0; i < d->cylinders.nr; i++) {
if (is_cylinder_used(d, i))
- gas << get_gas_string(d->cylinder[i].gasmix);
+ gas << get_gas_string(d->cylinders.cylinders[i].gasmix);
}
return gas;
}
@@ -221,10 +219,8 @@ QStringList getFullCylinderList()
int i = 0;
struct dive *d;
for_each_dive (i, d) {
- for (int j = 0; j < MAX_CYLINDERS; j++) {
- QString cyl = d->cylinder[j].type.description;
- if (cyl.isEmpty())
- continue;
+ for (int j = 0; j < d->cylinders.nr; j++) {
+ QString cyl = d->cylinders.cylinders[j].type.description;
cylinders << cyl;
}
}
diff --git a/core/uemis.c b/core/uemis.c
index 88f402400..7272e2897 100644
--- a/core/uemis.c
+++ b/core/uemis.c
@@ -336,17 +336,18 @@ void uemis_parse_divelog_binary(char *base64, void *datap)
* we store the incorrect working pressure to get the SAC calculations "close"
* but the user will have to correct this manually
*/
- dive->cylinder[i].type.size.mliter = lrintf(volume);
- dive->cylinder[i].type.workingpressure.mbar = 202600;
- dive->cylinder[i].gasmix.o2.permille = *(uint8_t *)(data + 120 + 25 * (gasoffset + i)) * 10;
- dive->cylinder[i].gasmix.he.permille = 0;
+ cylinder_t *cyl = get_or_create_cylinder(dive, i);
+ cyl->type.size.mliter = lrintf(volume);
+ cyl->type.workingpressure.mbar = 202600;
+ cyl->gasmix.o2.permille = *(uint8_t *)(data + 120 + 25 * (gasoffset + i)) * 10;
+ cyl->gasmix.he.permille = 0;
}
/* first byte of divelog data is at offset 0x123 */
i = 0x123;
u_sample = (uemis_sample_t *)(data + i);
while ((i <= datalen) && (data[i] != 0 || data[i + 1] != 0)) {
if (u_sample->active_tank != active) {
- if (u_sample->active_tank >= MAX_CYLINDERS) {
+ if (u_sample->active_tank >= dive->cylinders.nr) {
fprintf(stderr, "got invalid sensor #%d was #%d\n", u_sample->active_tank, active);
} else {
active = u_sample->active_tank;
diff --git a/desktop-widgets/command_edit.cpp b/desktop-widgets/command_edit.cpp
index 95665722d..97fc05c95 100644
--- a/desktop-widgets/command_edit.cpp
+++ b/desktop-widgets/command_edit.cpp
@@ -666,18 +666,6 @@ DiveField EditDiveMaster::fieldId() const
return DiveField::DIVEMASTER;
}
-// Helper function to copy cylinders. This supposes that the destination
-// cylinder is uninitialized. I.e. the old description is not freed!
-static void copy_cylinder(const cylinder_t &s, cylinder_t &d)
-{
- d.type.description = copy_string(s.type.description);
- d.type.size = s.type.size;
- d.type.workingpressure = s.type.workingpressure;
- d.gasmix = s.gasmix;
- d.cylinder_use = s.cylinder_use;
- d.depth = s.depth;
-}
-
static void swapCandQString(QString &q, char *&c)
{
QString tmp(c);
@@ -687,10 +675,9 @@ static void swapCandQString(QString &q, char *&c)
}
PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dIn),
- tags(nullptr),
- cylinders(MAX_CYLINDERS)
+ tags(nullptr)
{
- memset(&cylinders[0], 0, sizeof(cylinders));
+ memset(&cylinders, 0, sizeof(cylinders));
memset(&weightsystems, 0, sizeof(weightsystems));
if (what.notes)
notes = data->notes;
@@ -708,10 +695,8 @@ PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dI
divesite = data->dive_site;
if (what.tags)
tags = taglist_copy(data->tag_list);
- if (what.cylinders) {
- for (int i = 0; i < MAX_CYLINDERS; ++i)
- copy_cylinder(data->cylinder[i], cylinders[i]);
- }
+ if (what.cylinders)
+ copy_cylinders(&data->cylinders, &cylinders);
if (what.weights)
copy_weights(&data->weightsystems, &weightsystems);
}
@@ -719,8 +704,7 @@ PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dI
PasteState::~PasteState()
{
taglist_free(tags);
- for (cylinder_t &c: cylinders)
- free((void *)c.type.description);
+ clear_cylinder_table(&cylinders);
clear_weightsystem_table(&weightsystems);
free(weightsystems.weightsystems);
}
@@ -743,10 +727,8 @@ void PasteState::swap(dive_components what)
std::swap(divesite, d->dive_site);
if (what.tags)
std::swap(tags, d->tag_list);
- if (what.cylinders) {
- for (int i = 0; i < MAX_CYLINDERS; ++i)
- std::swap(cylinders[i], d->cylinder[i]);
- }
+ if (what.cylinders)
+ std::swap(cylinders, d->cylinders);
if (what.weights)
std::swap(weightsystems, d->weightsystems);
}
@@ -836,7 +818,7 @@ ReplanDive::ReplanDive(dive *source) : d(current_dive),
dc({ 0 }),
notes(nullptr)
{
- memset(&cylinders[0], 0, sizeof(cylinders));
+ memset(&cylinders, 0, sizeof(cylinders));
if (!d)
return;
@@ -849,7 +831,7 @@ ReplanDive::ReplanDive(dive *source) : d(current_dive),
surface_pressure = source->surface_pressure;
// This resets the dive computers and cylinders of the source dive, avoiding deep copies.
- std::swap(source->cylinder, cylinders);
+ std::swap(source->cylinders, cylinders);
std::swap(source->dc, dc);
setText(tr("Replan dive"));
@@ -857,8 +839,7 @@ ReplanDive::ReplanDive(dive *source) : d(current_dive),
ReplanDive::~ReplanDive()
{
- for (cylinder_t &c: cylinders)
- free((void *)c.type.description);
+ clear_cylinder_table(&cylinders);
free_dive_dcs(&dc);
free(notes);
}
@@ -873,7 +854,7 @@ void ReplanDive::undo()
std::swap(d->when, when);
std::swap(d->maxdepth, maxdepth);
std::swap(d->meandepth, meandepth);
- std::swap(d->cylinder, cylinders);
+ std::swap(d->cylinders, cylinders);
std::swap(d->dc, dc);
std::swap(d->notes, notes);
std::swap(d->surface_pressure, surface_pressure);
@@ -882,9 +863,11 @@ void ReplanDive::undo()
fixup_dive(d);
QVector<dive *> divesToNotify = { d };
+ // Note that we have to emit cylindersReset before divesChanged, because the divesChanged
+ // updates the DivePlotDataModel, which is out-of-sync and gets confused.
+ emit diveListNotifier.cylindersReset(divesToNotify);
emit diveListNotifier.divesChanged(divesToNotify, DiveField::DATETIME | DiveField::DURATION | DiveField::DEPTH | DiveField::MODE |
DiveField::NOTES | DiveField::SALINITY | DiveField::ATM_PRESS);
- emit diveListNotifier.cylindersReset(divesToNotify);
}
// Redo and undo do the same
diff --git a/desktop-widgets/command_edit.h b/desktop-widgets/command_edit.h
index 489c51046..45fde9e59 100644
--- a/desktop-widgets/command_edit.h
+++ b/desktop-widgets/command_edit.h
@@ -246,7 +246,7 @@ struct PasteState {
int rating;
int visibility;
tag_entry *tags;
- std::vector<cylinder_t> cylinders;
+ struct cylinder_table cylinders;
struct weightsystem_table weightsystems;
PasteState(dive *d, const dive *data, dive_components what); // Read data from dive data for dive d
@@ -273,7 +273,7 @@ class ReplanDive : public Base {
// Exchange these data with current dive
timestamp_t when;
depth_t maxdepth, meandepth;
- cylinder_t cylinders[MAX_CYLINDERS];
+ struct cylinder_table cylinders;
struct divecomputer dc;
char *notes;
pressure_t surface_pressure;
diff --git a/desktop-widgets/divelogexportdialog.cpp b/desktop-widgets/divelogexportdialog.cpp
index 8f192c39e..e093819dd 100644
--- a/desktop-widgets/divelogexportdialog.cpp
+++ b/desktop-widgets/divelogexportdialog.cpp
@@ -444,17 +444,17 @@ void DiveLogExportDialog::export_TeX(const char *filename, const bool selected_o
// Print cylinder data
put_format(&buf, "\n%% Gas use information:\n");
qty_cyl = 0;
- for (i = 0; i < MAX_CYLINDERS; i++){
-
- if (is_cylinder_used(dive, i) || (prefs.display_unused_tanks && dive->cylinder[i].type.description)){
- put_format(&buf, "\\def\\%scyl%cdescription{%s}\n", ssrf, 'a' + i, dive->cylinder[i].type.description);
- put_format(&buf, "\\def\\%scyl%cgasname{%s}\n", ssrf, 'a' + i, gasname(dive->cylinder[i].gasmix));
- put_format(&buf, "\\def\\%scyl%cmixO2{%.1f\\%%}\n", ssrf, 'a' + i, get_o2(dive->cylinder[i].gasmix)/10.0);
- put_format(&buf, "\\def\\%scyl%cmixHe{%.1f\\%%}\n", ssrf, 'a' + i, get_he(dive->cylinder[i].gasmix)/10.0);
- put_format(&buf, "\\def\\%scyl%cmixN2{%.1f\\%%}\n", ssrf, 'a' + i, (100.0 - (get_o2(dive->cylinder[i].gasmix)/10.0) - (get_he(dive->cylinder[i].gasmix)/10.0)));
- delta_p.mbar += dive->cylinder[i].start.mbar - dive->cylinder[i].end.mbar;
- put_format(&buf, "\\def\\%scyl%cstartpress{%.1f\\%spressureunit}\n", ssrf, 'a' + i, get_pressure_units(dive->cylinder[i].start.mbar, &unit)/1.0, ssrf);
- put_format(&buf, "\\def\\%scyl%cendpress{%.1f\\%spressureunit}\n", ssrf, 'a' + i, get_pressure_units(dive->cylinder[i].end.mbar, &unit)/1.0, ssrf);
+ for (i = 0; i < dive->cylinders.nr; i++){
+ const cylinder_t &cyl = dive->cylinders.cylinders[i];
+ if (is_cylinder_used(dive, i) || (prefs.display_unused_tanks && cyl.type.description)){
+ put_format(&buf, "\\def\\%scyl%cdescription{%s}\n", ssrf, 'a' + i, cyl.type.description);
+ put_format(&buf, "\\def\\%scyl%cgasname{%s}\n", ssrf, 'a' + i, gasname(cyl.gasmix));
+ put_format(&buf, "\\def\\%scyl%cmixO2{%.1f\\%%}\n", ssrf, 'a' + i, get_o2(cyl.gasmix)/10.0);
+ put_format(&buf, "\\def\\%scyl%cmixHe{%.1f\\%%}\n", ssrf, 'a' + i, get_he(cyl.gasmix)/10.0);
+ put_format(&buf, "\\def\\%scyl%cmixN2{%.1f\\%%}\n", ssrf, 'a' + i, (100.0 - (get_o2(cyl.gasmix)/10.0) - (get_he(cyl.gasmix)/10.0)));
+ delta_p.mbar += cyl.start.mbar - cyl.end.mbar;
+ put_format(&buf, "\\def\\%scyl%cstartpress{%.1f\\%spressureunit}\n", ssrf, 'a' + i, get_pressure_units(cyl.start.mbar, &unit)/1.0, ssrf);
+ put_format(&buf, "\\def\\%scyl%cendpress{%.1f\\%spressureunit}\n", ssrf, 'a' + i, get_pressure_units(cyl.end.mbar, &unit)/1.0, ssrf);
qty_cyl += 1;
} else {
put_format(&buf, "\\def\\%scyl%cdescription{}\n", ssrf, 'a' + i);
@@ -462,7 +462,7 @@ void DiveLogExportDialog::export_TeX(const char *filename, const bool selected_o
put_format(&buf, "\\def\\%scyl%cmixO2{}\n", ssrf, 'a' + i);
put_format(&buf, "\\def\\%scyl%cmixHe{}\n", ssrf, 'a' + i);
put_format(&buf, "\\def\\%scyl%cmixN2{}\n", ssrf, 'a' + i);
- delta_p.mbar += dive->cylinder[i].start.mbar - dive->cylinder[i].end.mbar;
+ delta_p.mbar += cyl.start.mbar - cyl.end.mbar;
put_format(&buf, "\\def\\%scyl%cstartpress{}\n", ssrf, 'a' + i);
put_format(&buf, "\\def\\%scyl%cendpress{}\n", ssrf, 'a' + i);
qty_cyl += 1;
diff --git a/desktop-widgets/simplewidgets.cpp b/desktop-widgets/simplewidgets.cpp
index 11af56bef..c49a9886b 100644
--- a/desktop-widgets/simplewidgets.cpp
+++ b/desktop-widgets/simplewidgets.cpp
@@ -510,9 +510,9 @@ void DiveComponentSelection::buttonClicked(QAbstractButton *button)
if (what->cylinders) {
int cyl;
text << tr("Cylinders:\n");
- for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
+ for (cyl = 0; cyl < displayed_dive.cylinders.nr; cyl++) {
if (is_cylinder_used(&displayed_dive, cyl))
- text << displayed_dive.cylinder[cyl].type.description << " " << gasname(displayed_dive.cylinder[cyl].gasmix) << "\n";
+ text << displayed_dive.cylinders.cylinders[cyl].type.description << " " << gasname(displayed_dive.cylinders.cylinders[cyl].gasmix) << "\n";
}
}
if (what->weights) {
diff --git a/desktop-widgets/tab-widgets/TabDiveEquipment.cpp b/desktop-widgets/tab-widgets/TabDiveEquipment.cpp
index af4dcbd44..6f43fc5a2 100644
--- a/desktop-widgets/tab-widgets/TabDiveEquipment.cpp
+++ b/desktop-widgets/tab-widgets/TabDiveEquipment.cpp
@@ -207,9 +207,10 @@ static QVector<dive *> getSelectedDivesCurrentLast()
return res;
}
-// TODO: This is only a temporary function until undo of weightsystems is implemented.
+// TODO: This are only temporary functions until undo of weightsystems and cylinders is implemented.
// Therefore it is not worth putting it in a header.
extern bool weightsystems_equal(const dive *d1, const dive *d2);
+extern bool cylinders_equal(const dive *d1, const dive *d2);
void TabDiveEquipment::acceptChanges()
{
@@ -227,31 +228,13 @@ void TabDiveEquipment::acceptChanges()
if (cylindersModel->changed) {
mark_divelist_changed(true);
MODIFY_DIVES(selectedDives,
- for (int i = 0; i < MAX_CYLINDERS; i++) {
- if (mydive != cd) {
- if (same_string(mydive->cylinder[i].type.description, cd->cylinder[i].type.description)) {
- // if we started out with the same cylinder description (for multi-edit) or if we do copt & paste
- // make sure that we have the same cylinder type and copy the gasmix, but DON'T copy the start
- // and end pressures (those are per dive after all)
- if (!same_string(mydive->cylinder[i].type.description, displayed_dive.cylinder[i].type.description)) {
- free((void*)mydive->cylinder[i].type.description);
- mydive->cylinder[i].type.description = copy_string(displayed_dive.cylinder[i].type.description);
- }
- mydive->cylinder[i].type.size = displayed_dive.cylinder[i].type.size;
- mydive->cylinder[i].type.workingpressure = displayed_dive.cylinder[i].type.workingpressure;
- mydive->cylinder[i].gasmix = displayed_dive.cylinder[i].gasmix;
- mydive->cylinder[i].cylinder_use = displayed_dive.cylinder[i].cylinder_use;
- mydive->cylinder[i].depth = displayed_dive.cylinder[i].depth;
- }
- }
- }
+ // if we started out with the same cylinder description (for multi-edit) or if we do copt & paste
+ // make sure that we have the same cylinder type and copy the gasmix, but DON'T copy the start
+ // and end pressures (those are per dive after all)
+ if (cylinders_equal(mydive, cd) && mydive != cd)
+ copy_cylinder_types(&displayed_dive, cd);
+ copy_cylinders(&displayed_dive.cylinders, &cd->cylinders);
);
- for (int i = 0; i < MAX_CYLINDERS; i++) {
- // copy the cylinder but make sure we have our own copy of the strings
- free((void*)cd->cylinder[i].type.description);
- cd->cylinder[i] = displayed_dive.cylinder[i];
- cd->cylinder[i].type.description = copy_string(displayed_dive.cylinder[i].type.description);
- }
/* if cylinders changed we may have changed gas change events
* and sensor idx in samples as well
* - so far this is ONLY supported for a single selected dive */
diff --git a/desktop-widgets/tab-widgets/TabDiveInformation.cpp b/desktop-widgets/tab-widgets/TabDiveInformation.cpp
index d5ce7d035..afa427bdc 100644
--- a/desktop-widgets/tab-widgets/TabDiveInformation.cpp
+++ b/desktop-widgets/tab-widgets/TabDiveInformation.cpp
@@ -53,20 +53,20 @@ void TabDiveInformation::updateProfile()
ui->maximumDepthText->setText(get_depth_string(current_dive->maxdepth, true));
ui->averageDepthText->setText(get_depth_string(current_dive->meandepth, true));
- volume_t *gases = get_gas_used(current_dive);
+ volume_t *gases = get_gas_used(current_dive);
QString volumes;
- std::vector<int> mean(MAX_CYLINDERS), duration(MAX_CYLINDERS);
+ std::vector<int> mean(current_dive->cylinders.nr), duration(current_dive->cylinders.nr);
per_cylinder_mean_depth(current_dive, select_dc(current_dive), &mean[0], &duration[0]);
volume_t sac;
QString gaslist, SACs, separator;
- for (int i = 0; i < MAX_CYLINDERS; i++) {
+ for (int i = 0; i < current_dive->cylinders.nr; i++) {
if (!is_cylinder_used(current_dive, i))
continue;
gaslist.append(separator); volumes.append(separator); SACs.append(separator);
separator = "\n";
- gaslist.append(gasname(current_dive->cylinder[i].gasmix));
+ gaslist.append(gasname(current_dive->cylinders.cylinders[i].gasmix));
if (!gases[i].mliter)
continue;
volumes.append(get_volume_string(gases[i], true));
diff --git a/desktop-widgets/tab-widgets/TabDiveStatistics.cpp b/desktop-widgets/tab-widgets/TabDiveStatistics.cpp
index ee090c6bc..f3c5f5807 100644
--- a/desktop-widgets/tab-widgets/TabDiveStatistics.cpp
+++ b/desktop-widgets/tab-widgets/TabDiveStatistics.cpp
@@ -118,16 +118,12 @@ void TabDiveStatistics::updateData()
QVector<QPair<QString, int> > gasUsed = selectedDivesGasUsed();
QString gasUsedString;
volume_t vol;
- for (int j = 0; j < MAX_CYLINDERS; j++) {
- if (gasUsed.isEmpty())
- break;
+ while (!gasUsed.isEmpty()) {
QPair<QString, int> gasPair = gasUsed.last();
gasUsed.pop_back();
vol.mliter = gasPair.second;
gasUsedString.append(gasPair.first).append(": ").append(get_volume_string(vol, true)).append("\n");
}
- if (!gasUsed.isEmpty())
- gasUsedString.append("...");
volume_t o2_tot = {}, he_tot = {};
selected_dives_gas_parts(&o2_tot, &he_tot);
diff --git a/desktop-widgets/tab-widgets/maintab.cpp b/desktop-widgets/tab-widgets/maintab.cpp
index 3aea3fe39..4d3d7397d 100644
--- a/desktop-widgets/tab-widgets/maintab.cpp
+++ b/desktop-widgets/tab-widgets/maintab.cpp
@@ -651,13 +651,24 @@ bool weightsystems_equal(const dive *d1, const dive *d2)
return true;
}
+bool cylinders_equal(const dive *d1, const dive *d2)
+{
+ if (d1->cylinders.nr != d2->cylinders.nr)
+ return false;
+ for (int i = 0; i < d1->cylinders.nr; ++i) {
+ if (!same_cylinder(d1->cylinders.cylinders[i], d2->cylinders.cylinders[i]))
+ return false;
+ }
+ return true;
+}
+
void MainTab::rejectChanges()
{
EditMode lastMode = editMode;
if (lastMode != NONE && current_dive &&
(modified ||
- memcmp(&current_dive->cylinder[0], &displayed_dive.cylinder[0], sizeof(cylinder_t) * MAX_CYLINDERS) ||
+ !cylinders_equal(current_dive, &displayed_dive) ||
!weightsystems_equal(current_dive, &displayed_dive))) {
if (QMessageBox::warning(MainWindow::instance(), TITLE_OR_TEXT(tr("Discard the changes?"),
tr("You are about to discard your changes.")),
diff --git a/mobile-widgets/qmlmanager.cpp b/mobile-widgets/qmlmanager.cpp
index bace5aed6..f14092fb1 100644
--- a/mobile-widgets/qmlmanager.cpp
+++ b/mobile-widgets/qmlmanager.cpp
@@ -1125,10 +1125,10 @@ void QMLManager::commitChanges(QString diveId, QString number, QString date, QSt
if (state != "add" && !is_cylinder_used(d, i))
continue;
- d->cylinder[i].start.mbar = parsePressureToMbar(startpressure[j]);
- d->cylinder[i].end.mbar = parsePressureToMbar(endpressure[j]);
- if (d->cylinder[i].end.mbar > d->cylinder[i].start.mbar)
- d->cylinder[i].end.mbar = d->cylinder[i].start.mbar;
+ d->cylinders.cylinders[i].start.mbar = parsePressureToMbar(startpressure[j]);
+ d->cylinders.cylinders[i].end.mbar = parsePressureToMbar(endpressure[j]);
+ if (d->cylinders.cylinders[i].end.mbar > d->cylinders.cylinders[i].start.mbar)
+ d->cylinders.cylinders[i].end.mbar = d->cylinders.cylinders[i].start.mbar;
j++;
}
@@ -1146,8 +1146,8 @@ void QMLManager::commitChanges(QString diveId, QString number, QString date, QSt
he >= 0 && he <= 1000 &&
o2 + he <= 1000) {
diveChanged = true;
- d->cylinder[i].gasmix.o2.permille = o2;
- d->cylinder[i].gasmix.he.permille = he;
+ d->cylinders.cylinders[i].gasmix.o2.permille = o2;
+ d->cylinders.cylinders[i].gasmix.he.permille = he;
}
j++;
}
@@ -1157,7 +1157,7 @@ void QMLManager::commitChanges(QString diveId, QString number, QString date, QSt
diveChanged = true;
unsigned long i;
int size = 0, wp = 0, j = 0, k = 0;
- for (j = 0; k < usedCylinder.length() && j < MAX_CYLINDERS; j++) {
+ for (j = 0; k < usedCylinder.length(); j++) {
if (state != "add" && !is_cylinder_used(d, j))
continue;
@@ -1173,9 +1173,9 @@ void QMLManager::commitChanges(QString diveId, QString number, QString date, QSt
break;
}
}
- d->cylinder[j].type.description = copy_qstring(usedCylinder[k]);
- d->cylinder[j].type.size.mliter = size;
- d->cylinder[j].type.workingpressure.mbar = wp;
+ d->cylinders.cylinders[j].type.description = copy_qstring(usedCylinder[k]);
+ d->cylinders.cylinders[j].type.size.mliter = size;
+ d->cylinders.cylinders[j].type.workingpressure.mbar = wp;
k++;
}
}
@@ -1788,9 +1788,9 @@ QStringList QMLManager::cylinderInit() const
struct dive *d;
int i = 0;
for_each_dive (i, d) {
- for (int j = 0; j < MAX_CYLINDERS; j++) {
- if (!empty_string(d->cylinder[j].type.description))
- cylinders << d->cylinder[j].type.description;
+ for (int j = 0; j < d->cylinders.nr; j++) {
+ if (!empty_string(d->cylinders.cylinders[j].type.description))
+ cylinders << d->cylinders.cylinders[j].type.description;
}
}
diff --git a/profile-widget/diveprofileitem.cpp b/profile-widget/diveprofileitem.cpp
index bc74f7f40..3d0ba2e7a 100644
--- a/profile-widget/diveprofileitem.cpp
+++ b/profile-widget/diveprofileitem.cpp
@@ -659,17 +659,17 @@ void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QMo
if (!shouldCalculateStuff(topLeft, bottomRight))
return;
- std::vector<int> plotted_cyl(MAX_CYLINDERS, false);
- std::vector<int> last_plotted(MAX_CYLINDERS, 0);
- std::vector<QPolygonF> poly(MAX_CYLINDERS);
+ const struct plot_info *pInfo = &dataModel->data();
+ std::vector<int> plotted_cyl(pInfo->nr_cylinders, false);
+ std::vector<int> last_plotted(pInfo->nr_cylinders, 0);
+ std::vector<QPolygonF> poly(pInfo->nr_cylinders);
QPolygonF boundingPoly;
polygons.clear();
- const struct plot_info *pInfo = &dataModel->data();
for (int i = 0, count = dataModel->rowCount(); i < count; i++) {
const struct plot_data *entry = pInfo->entry + i;
- for (int cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
+ for (int cyl = 0; cyl < pInfo->nr_cylinders; cyl++) {
int mbar = get_plot_pressure(pInfo, i, cyl);
int time = entry->sec;
@@ -698,7 +698,7 @@ void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QMo
}
}
- for (int cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
+ for (int cyl = 0; cyl < pInfo->nr_cylinders; cyl++) {
if (!plotted_cyl[cyl])
continue;
polygons.append(poly[cyl]);
@@ -708,9 +708,9 @@ void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QMo
qDeleteAll(texts);
texts.clear();
- std::vector<int> seen_cyl(MAX_CYLINDERS, false);
- std::vector<int> last_pressure(MAX_CYLINDERS, 0);
- std::vector<int> last_time(MAX_CYLINDERS, 0);
+ std::vector<int> seen_cyl(pInfo->nr_cylinders, false);
+ std::vector<int> last_pressure(pInfo->nr_cylinders, 0);
+ std::vector<int> last_time(pInfo->nr_cylinders, 0);
// These are offset values used to print the gas lables and pressures on a
// dive profile at appropriate Y-coordinates. We alternate aligning the
@@ -721,7 +721,7 @@ void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QMo
// pressures.
QFlags<Qt::AlignmentFlag> alignVar = Qt::AlignTop;
- std::vector<QFlags<Qt::AlignmentFlag>> align(MAX_CYLINDERS);
+ std::vector<QFlags<Qt::AlignmentFlag>> align(pInfo->nr_cylinders);
double axisRange = (vAxis->maximum() - vAxis->minimum())/1000; // Convert axis pressure range to bar
double axisLog = log10(log10(axisRange));
@@ -729,7 +729,7 @@ void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QMo
for (int i = 0, count = dataModel->rowCount(); i < count; i++) {
const struct plot_data *entry = pInfo->entry + i;
- for (int cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
+ for (int cyl = 0; cyl < pInfo->nr_cylinders; cyl++) {
int mbar = get_plot_pressure(pInfo, i, cyl);
if (!mbar)
@@ -748,7 +748,7 @@ void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QMo
label_y_offset = -7 * axisLog;
}
plotPressureValue(mbar, entry->sec, alignVar, value_y_offset);
- plotGasValue(mbar, entry->sec, displayed_dive.cylinder[cyl].gasmix, alignVar, label_y_offset);
+ plotGasValue(mbar, entry->sec, displayed_dive.cylinders.cylinders[cyl].gasmix, alignVar, label_y_offset);
seen_cyl[cyl] = true;
/* Alternate alignment as we see cylinder use.. */
@@ -761,7 +761,7 @@ void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QMo
}
// For each cylinder, on right hand side of profile, write cylinder pressure
- for (int cyl = 0; cyl < MAX_CYLINDERS; cyl++) {
+ for (int cyl = 0; cyl < pInfo->nr_cylinders; cyl++) {
if (last_time[cyl]) {
double value_y_offset = -0.5;
plotPressureValue(last_pressure[cyl], last_time[cyl], align[cyl] | Qt::AlignLeft, value_y_offset);
diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp
index e065361d3..01cd733be 100644
--- a/profile-widget/profilewidget2.cpp
+++ b/profile-widget/profilewidget2.cpp
@@ -1536,7 +1536,7 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
int newGasIdx = gasChangeIdx + 1;
const struct plot_data &newGasEntry = plotInfo.entry[newGasIdx];
qDebug() << "after gas change at " << newGasEntry->sec << ": sensor pressure" << newGasEntry->pressure[0] << "interpolated" << newGasEntry->pressure[1];
- if (get_plot_sensor_pressure(&plotInfo, gasChangeIdx) == 0 || displayed_dive.cylinder[gasChangeEntry->sensor[0]].sample_start.mbar == 0) {
+ if (get_plot_sensor_pressure(&plotInfo, gasChangeIdx) == 0 || displayed_dive.cylinders.cylinders[gasChangeEntry->sensor[0]].sample_start.mbar == 0) {
// if we have no sensorpressure or if we have no pressure from samples we can assume that
// we only have interpolated pressure (the pressure in the entry may be stored in the sensor
// pressure field if this is the first or last entry for this tank... see details in gaspressures.c
@@ -1545,7 +1545,7 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
QAction *adjustOldPressure = m.addAction(tr("Adjust pressure of cyl. %1 (currently interpolated as %2)")
.arg(gasChangeEntry->sensor[0] + 1).arg(get_pressure_string(pressure)));
}
- if (get_plot_sensor_pressure(&plotInfo, newGasIdx) == 0 || displayed_dive.cylinder[newGasEntry->sensor[0]].sample_start.mbar == 0) {
+ if (get_plot_sensor_pressure(&plotInfo, newGasIdx) == 0 || displayed_dive.cylinders.cylinders[newGasEntry->sensor[0]].sample_start.mbar == 0) {
// we only have interpolated press -- see commend above
pressure_t pressure;
pressure.mbar = get_plot_interpolated_pressure(&plotInfo, newGasIdx) ? : get_plot_sensor_pressure(&plotInfo, newGasIdx);
@@ -1882,7 +1882,7 @@ void ProfileWidget2::repositionDiveHandlers()
QLineF line(p1, p2);
QPointF pos = line.pointAt(0.5);
gases[i]->setPos(pos);
- gases[i]->setText(get_gas_string(displayed_dive.cylinder[datapoint.cylinderid].gasmix));
+ gases[i]->setText(get_gas_string(displayed_dive.cylinders.cylinders[datapoint.cylinderid].gasmix));
gases[i]->setVisible(datapoint.entered &&
(i == 0 || gases[i]->text() != gases[i-1]->text()));
}
diff --git a/profile-widget/tankitem.cpp b/profile-widget/tankitem.cpp
index f40baa357..8cd53b5d4 100644
--- a/profile-widget/tankitem.cpp
+++ b/profile-widget/tankitem.cpp
@@ -98,7 +98,7 @@ void TankItem::modelDataChanged(const QModelIndex&, const QModelIndex&)
// start with the first gasmix and at the start of the dive
int cyl = explicit_first_cylinder(&displayed_dive, dc);
- struct gasmix gasmix = displayed_dive.cylinder[cyl].gasmix;
+ struct gasmix gasmix = displayed_dive.cylinders.cylinders[cyl].gasmix;
int startTime = 0;
// work through all the gas changes and add the rectangle for each gas while it was used
diff --git a/qt-models/cylindermodel.cpp b/qt-models/cylindermodel.cpp
index 3a2b6e536..f64cc213a 100644
--- a/qt-models/cylindermodel.cpp
+++ b/qt-models/cylindermodel.cpp
@@ -131,10 +131,10 @@ static QVariant percent_string(fraction_t fraction)
QVariant CylindersModel::data(const QModelIndex &index, int role) const
{
- if (!index.isValid() || index.row() >= MAX_CYLINDERS)
+ if (!index.isValid() || index.row() >= rows)
return QVariant();
- const cylinder_t *cyl = &displayed_dive.cylinder[index.row()];
+ const cylinder_t *cyl = &displayed_dive.cylinders.cylinders[index.row()];
switch (role) {
case Qt::BackgroundRole: {
@@ -259,7 +259,7 @@ QVariant CylindersModel::data(const QModelIndex &index, int role) const
cylinder_t *CylindersModel::cylinderAt(const QModelIndex &index)
{
- return &displayed_dive.cylinder[index.row()];
+ return &displayed_dive.cylinders.cylinders[index.row()];
}
// this is our magic 'pass data in' function that allows the delegate to get
@@ -420,16 +420,14 @@ int CylindersModel::rowCount(const QModelIndex&) const
void CylindersModel::add()
{
- if (rows >= MAX_CYLINDERS) {
- return;
- }
-
int row = rows;
- fill_default_cylinder(&displayed_dive, row);
- displayed_dive.cylinder[row].start = displayed_dive.cylinder[row].type.workingpressure;
- displayed_dive.cylinder[row].manually_added = true;
- displayed_dive.cylinder[row].cylinder_use = OC_GAS;
+ cylinder_t cyl = { 0 };
+ fill_default_cylinder(&displayed_dive, &cyl);
+ cyl.start = cyl.type.workingpressure;
+ cyl.manually_added = true;
+ cyl.cylinder_use = OC_GAS;
beginInsertRows(QModelIndex(), row, row);
+ add_to_cylinder_table(&displayed_dive.cylinders, row, cyl);
rows++;
changed = true;
endInsertRows();
@@ -446,12 +444,12 @@ void CylindersModel::clear()
static bool show_cylinder(struct dive *dive, int i)
{
- cylinder_t *cyl = dive->cylinder + i;
-
+ if (i < 0 || i >= dive->cylinders.nr)
+ return false;
if (is_cylinder_used(dive, i))
return true;
- if (cylinder_none(cyl))
- return false;
+
+ cylinder_t *cyl = dive->cylinders.cylinders + i;
if (cyl->start.mbar || cyl->sample_start.mbar ||
cyl->end.mbar || cyl->sample_end.mbar)
return true;
@@ -467,34 +465,18 @@ static bool show_cylinder(struct dive *dive, int i)
void CylindersModel::updateDive()
{
- clear();
- rows = 0;
#ifdef DEBUG_CYL
dump_cylinders(&displayed_dive, true);
#endif
- for (int i = 0; i < MAX_CYLINDERS; i++) {
- if (show_cylinder(&displayed_dive, i))
- rows = i + 1;
- }
- if (rows > 0) {
- beginInsertRows(QModelIndex(), 0, rows - 1);
- endInsertRows();
- }
-}
-
-void CylindersModel::copyFromDive(dive *d)
-{
- if (!d)
- return;
+ beginResetModel();
+ // TODO: this is fundamentally broken - it assumes that unused cylinders are at
+ // the end. Fix by using a QSortFilterProxyModel.
rows = 0;
- for (int i = 0; i < MAX_CYLINDERS; i++) {
- if (show_cylinder(d, i))
- rows = i + 1;
- }
- if (rows > 0) {
- beginInsertRows(QModelIndex(), 0, rows - 1);
- endInsertRows();
+ for (int i = 0; i < displayed_dive.cylinders.nr; ++i) {
+ if (show_cylinder(&displayed_dive, i))
+ ++rows;
}
+ endResetModel();
}
Qt::ItemFlags CylindersModel::flags(const QModelIndex &index) const
@@ -506,7 +488,6 @@ Qt::ItemFlags CylindersModel::flags(const QModelIndex &index) const
void CylindersModel::remove(const QModelIndex &index)
{
- std::vector<int> mapping(MAX_CYLINDERS);
if (index.column() == USE) {
cylinder_t *cyl = cylinderAt(index);
@@ -518,48 +499,53 @@ void CylindersModel::remove(const QModelIndex &index)
dataChanged(index, index);
return;
}
- if (index.column() != REMOVE) {
+
+ if (index.column() != REMOVE)
return;
- }
if ((in_planner() && DivePlannerPointsModel::instance()->tankInUse(index.row())) ||
(!in_planner() && is_cylinder_prot(&displayed_dive, index.row())))
return;
- beginRemoveRows(QModelIndex(), index.row(), index.row()); // yah, know, ugly.
+ beginRemoveRows(QModelIndex(), index.row(), index.row());
rows--;
-
remove_cylinder(&displayed_dive, index.row());
- for (int i = 0; i < index.row(); i++)
- mapping[i] = i;
- // No mapping for removed gas, set to -1
+ changed = true;
+ endRemoveRows();
+
+ // Create a mapping of cylinder indexes:
+ // 1) Fill mapping[0]..mapping[index-1] with 0..index
+ // 2) Set mapping[index] to -1
+ // 3) Fill mapping[index+1]..mapping[end] with index..
+ std::vector<int> mapping(displayed_dive.cylinders.nr + 1);
+ std::iota(mapping.begin(), mapping.begin() + index.row(), 0);
mapping[index.row()] = -1;
- for (int i = index.row() + 1; i < MAX_CYLINDERS; i++)
- mapping[i] = i - 1;
+ std::iota(mapping.begin() + index.row() + 1, mapping.end(), index.row());
cylinder_renumber(&displayed_dive, &mapping[0]);
if (in_planner())
DivePlannerPointsModel::instance()->cylinderRenumber(&mapping[0]);
changed = true;
- endRemoveRows();
- dataChanged(index, index);
}
void CylindersModel::moveAtFirst(int cylid)
{
- std::vector<int> mapping(MAX_CYLINDERS);
cylinder_t temp_cyl;
beginMoveRows(QModelIndex(), cylid, cylid, QModelIndex(), 0);
- memmove(&temp_cyl, &displayed_dive.cylinder[cylid], sizeof(temp_cyl));
- for (int i = cylid - 1; i >= 0; i--) {
- memmove(&displayed_dive.cylinder[i + 1], &displayed_dive.cylinder[i], sizeof(temp_cyl));
- mapping[i] = i + 1;
- }
- memmove(&displayed_dive.cylinder[0], &temp_cyl, sizeof(temp_cyl));
+ memmove(&temp_cyl, &displayed_dive.cylinders.cylinders[cylid], sizeof(temp_cyl));
+ for (int i = cylid - 1; i >= 0; i--)
+ memmove(&displayed_dive.cylinders.cylinders[i + 1], &displayed_dive.cylinders.cylinders[i], sizeof(temp_cyl));
+ memmove(&displayed_dive.cylinders.cylinders[0], &temp_cyl, sizeof(temp_cyl));
+
+ // Create a mapping of cylinder indexes:
+ // 1) Fill mapping[0]..mapping[cyl] with 0..index
+ // 2) Set mapping[cyl] to 0
+ // 3) Fill mapping[cyl+1]..mapping[end] with cyl..
+ std::vector<int> mapping(displayed_dive.cylinders.nr);
+ std::iota(mapping.begin(), mapping.begin() + cylid, 1);
mapping[cylid] = 0;
- for (int i = cylid + 1; i < MAX_CYLINDERS; i++)
- mapping[i] = i;
+ std::iota(mapping.begin() + (cylid + 1), mapping.end(), cylid);
cylinder_renumber(&displayed_dive, &mapping[0]);
if (in_planner())
DivePlannerPointsModel::instance()->cylinderRenumber(&mapping[0]);
@@ -571,28 +557,28 @@ void CylindersModel::updateDecoDepths(pressure_t olddecopo2)
{
pressure_t decopo2;
decopo2.mbar = prefs.decopo2;
- for (int i = 0; i < MAX_CYLINDERS; i++) {
- cylinder_t *cyl = &displayed_dive.cylinder[i];
+ for (int i = 0; i < displayed_dive.cylinders.nr; i++) {
+ cylinder_t *cyl = &displayed_dive.cylinders.cylinders[i];
/* If the gas's deco MOD matches the old pO2, it will have been automatically calculated and should be updated.
* If they don't match, we should leave the user entered depth as it is */
if (cyl->depth.mm == gas_mod(cyl->gasmix, olddecopo2, &displayed_dive, M_OR_FT(3, 10)).mm) {
cyl->depth = gas_mod(cyl->gasmix, decopo2, &displayed_dive, M_OR_FT(3, 10));
}
}
- emit dataChanged(createIndex(0, 0), createIndex(MAX_CYLINDERS - 1, COLUMNS - 1));
+ emit dataChanged(createIndex(0, 0), createIndex(displayed_dive.cylinders.nr - 1, COLUMNS - 1));
}
void CylindersModel::updateTrashIcon()
{
- emit dataChanged(createIndex(0, 0), createIndex(MAX_CYLINDERS - 1, 0));
+ emit dataChanged(createIndex(0, 0), createIndex(displayed_dive.cylinders.nr - 1, 0));
}
bool CylindersModel::updateBestMixes()
{
// Check if any of the cylinders are best mixes, update if needed
bool gasUpdated = false;
- for (int i = 0; i < MAX_CYLINDERS; i++) {
- cylinder_t *cyl = &displayed_dive.cylinder[i];
+ for (int i = 0; i < displayed_dive.cylinders.nr; i++) {
+ cylinder_t *cyl = &displayed_dive.cylinders.cylinders[i];
if (cyl->bestmix_o2) {
cyl->gasmix.o2 = best_o2(displayed_dive.maxdepth, &displayed_dive);
// fO2 + fHe must not be greater than 1
@@ -614,7 +600,7 @@ bool CylindersModel::updateBestMixes()
/* This slot is called when the bottom pO2 and END preferences are updated, we want to
* emit dataChanged so MOD and MND are refreshed, even if the gas mix hasn't been changed */
if (gasUpdated)
- emit dataChanged(createIndex(0, 0), createIndex(MAX_CYLINDERS - 1, COLUMNS - 1));
+ emit dataChanged(createIndex(0, 0), createIndex(displayed_dive.cylinders.nr - 1, COLUMNS - 1));
return gasUpdated;
}
@@ -626,7 +612,7 @@ void CylindersModel::cylindersReset(const QVector<dive *> &dives)
return;
// Copy the cylinders from the current dive to the displayed dive.
- copy_cylinders(current_dive, &displayed_dive, false);
+ copy_cylinders(&current_dive->cylinders, &displayed_dive.cylinders);
// And update the model..
updateDive();
diff --git a/qt-models/cylindermodel.h b/qt-models/cylindermodel.h
index 58d11e971..0def53ba9 100644
--- a/qt-models/cylindermodel.h
+++ b/qt-models/cylindermodel.h
@@ -37,7 +37,6 @@ public:
void add();
void clear();
void updateDive();
- void copyFromDive(struct dive *d);
void updateDecoDepths(pressure_t olddecopo2);
void updateTrashIcon();
void moveAtFirst(int cylid);
diff --git a/qt-models/diveplannermodel.cpp b/qt-models/diveplannermodel.cpp
index 537bf278f..8d19afcfb 100644
--- a/qt-models/diveplannermodel.cpp
+++ b/qt-models/diveplannermodel.cpp
@@ -152,29 +152,32 @@ void DivePlannerPointsModel::loadFromDive(dive *d)
// setup the cylinder widget accordingly
void DivePlannerPointsModel::setupCylinders()
{
- int i;
+ clear_cylinder_table(&displayed_dive.cylinders);
if (mode == PLAN && current_dive) {
// take the displayed cylinders from the selected dive as starting point
- CylindersModel::instance()->copyFromDive(current_dive);
- copy_cylinders(current_dive, &displayed_dive, !prefs.display_unused_tanks);
+ copy_used_cylinders(current_dive, &displayed_dive, !prefs.display_unused_tanks);
reset_cylinders(&displayed_dive, true);
- for (i = 0; i < MAX_CYLINDERS; i++)
- if (!cylinder_none(&(displayed_dive.cylinder[i])))
- return; // We have at least one cylinder
+ if (displayed_dive.cylinders.nr > 0) {
+ CylindersModel::instance()->updateDive();
+ return; // We have at least one cylinder
+ }
}
if (!empty_string(prefs.default_cylinder)) {
- fill_default_cylinder(&displayed_dive, 0);
- displayed_dive.cylinder[0].start = displayed_dive.cylinder[0].type.workingpressure;
- }
- if (cylinder_none(&displayed_dive.cylinder[0])) {
+ cylinder_t cyl = { 0 };
+ fill_default_cylinder(&displayed_dive, &cyl);
+ cyl.start = cyl.type.workingpressure;
+ add_to_cylinder_table(&displayed_dive.cylinders, 0, cyl);
+ } else {
+ cylinder_t cyl = { 0 };
// roughly an AL80
- displayed_dive.cylinder[0].type.description = copy_qstring(tr("unknown"));
- displayed_dive.cylinder[0].type.size.mliter = 11100;
- displayed_dive.cylinder[0].type.workingpressure.mbar = 207000;
+ cyl.type.description = copy_qstring(tr("unknown"));
+ cyl.type.size.mliter = 11100;
+ cyl.type.workingpressure.mbar = 207000;
+ add_to_cylinder_table(&displayed_dive.cylinders, 0, cyl);
}
reset_cylinders(&displayed_dive, false);
- CylindersModel::instance()->copyFromDive(&displayed_dive);
+ CylindersModel::instance()->updateDive();
}
// Update the dive's maximum depth. Returns true if max. depth changed
@@ -265,13 +268,13 @@ QVariant DivePlannerPointsModel::data(const QModelIndex &index, int role) const
case GAS:
/* Check if we have the same gasmix two or more times
* If yes return more verbose string */
- int same_gas = same_gasmix_cylinder(&displayed_dive.cylinder[p.cylinderid], p.cylinderid, &displayed_dive, true);
+ int same_gas = same_gasmix_cylinder(&displayed_dive.cylinders.cylinders[p.cylinderid], p.cylinderid, &displayed_dive, true);
if (same_gas == -1)
- return get_gas_string(displayed_dive.cylinder[p.cylinderid].gasmix);
+ return get_gas_string(displayed_dive.cylinders.cylinders[p.cylinderid].gasmix);
else
- return get_gas_string(displayed_dive.cylinder[p.cylinderid].gasmix) +
+ return get_gas_string(displayed_dive.cylinders.cylinders[p.cylinderid].gasmix) +
QString(" (%1 %2 ").arg(tr("cyl.")).arg(p.cylinderid + 1) +
- displayed_dive.cylinder[p.cylinderid].type.description + ")";
+ displayed_dive.cylinders.cylinders[p.cylinderid].type.description + ")";
}
} else if (role == Qt::DecorationRole) {
switch (index.column()) {
@@ -333,7 +336,7 @@ bool DivePlannerPointsModel::setData(const QModelIndex &index, const QVariant &v
p.setpoint = po2;
} break;
case GAS:
- if (value.toInt() >= 0 && value.toInt() < MAX_CYLINDERS)
+ if (value.toInt() >= 0)
p.cylinderid = value.toInt();
/* Did we change the start (dp 0) cylinder to another cylinderid than 0? */
if (value.toInt() != 0 && index.row() == 0)
@@ -890,8 +893,8 @@ void DivePlannerPointsModel::createTemporaryPlan()
// what does the cache do???
struct deco_state *cache = NULL;
struct divedatapoint *dp = NULL;
- for (int i = 0; i < MAX_CYLINDERS; i++) {
- cylinder_t *cyl = &displayed_dive.cylinder[i];
+ for (int i = 0; i < displayed_dive.cylinders.nr; i++) {
+ cylinder_t *cyl = &displayed_dive.cylinders.cylinders[i];
if (cyl->depth.mm && cyl->cylinder_use != NOT_USED) {
dp = create_dp(0, cyl->depth.mm, i, 0);
if (diveplan.dp) {
diff --git a/qt-models/diveplotdatamodel.cpp b/qt-models/diveplotdatamodel.cpp
index 164cd04a4..eed13c501 100644
--- a/qt-models/diveplotdatamodel.cpp
+++ b/qt-models/diveplotdatamodel.cpp
@@ -190,8 +190,8 @@ void DivePlotDataModel::setDive(dive *d, const plot_info &info)
pInfo = info;
pInfo.entry = (plot_data *)malloc(sizeof(plot_data) * pInfo.nr);
memcpy(pInfo.entry, info.entry, sizeof(plot_data) * pInfo.nr);
- pInfo.pressures = (plot_pressure_data *)malloc(sizeof(plot_pressure_data) * MAX_CYLINDERS * pInfo.nr);
- memcpy(pInfo.pressures, info.pressures, sizeof(plot_pressure_data) * MAX_CYLINDERS * pInfo.nr);
+ pInfo.pressures = (plot_pressure_data *)malloc(sizeof(plot_pressure_data) * pInfo.nr_cylinders * pInfo.nr);
+ memcpy(pInfo.pressures, info.pressures, sizeof(plot_pressure_data) * pInfo.nr_cylinders * pInfo.nr);
endResetModel();
}
diff --git a/qt-models/divetripmodel.cpp b/qt-models/divetripmodel.cpp
index 30ab2175b..220d122d4 100644
--- a/qt-models/divetripmodel.cpp
+++ b/qt-models/divetripmodel.cpp
@@ -157,7 +157,7 @@ QVariant DiveTripModelBase::diveData(const struct dive *d, int column, int role)
case SUIT:
return QString(d->suit);
case CYLINDER:
- return QString(d->cylinder[0].type.description);
+ return d->cylinders.nr > 0 ? QString(d->cylinders.cylinders[0].type.description) : QString();
case SAC:
return displaySac(d, prefs.units.show_units_table);
case OTU:
@@ -1410,7 +1410,9 @@ bool DiveTripModelList::lessThan(const QModelIndex &i1, const QModelIndex &i2) c
case SUIT:
return lessThanHelper(strCmp(d1->suit, d2->suit), row_diff);
case CYLINDER:
- return lessThanHelper(strCmp(d1->cylinder[0].type.description, d2->cylinder[0].type.description), row_diff);
+ if (d1->cylinders.nr > 0 && d2->cylinders.nr > 0)
+ return lessThanHelper(strCmp(d1->cylinders.cylinders[0].type.description, d2->cylinders.cylinders[0].type.description), row_diff);
+ return d1->cylinders.nr - d2->cylinders.nr < 0;
case GAS:
return lessThanHelper(nitrox_sort_value(d1) - nitrox_sort_value(d2), row_diff);
case SAC:
diff --git a/qt-models/models.cpp b/qt-models/models.cpp
index f6b3e927f..ab80f95f0 100644
--- a/qt-models/models.cpp
+++ b/qt-models/models.cpp
@@ -26,10 +26,8 @@ GasSelectionModel *GasSelectionModel::instance()
static QStringList getGasList()
{
QStringList list;
- for (int i = 0; i < MAX_CYLINDERS; i++) {
- cylinder_t *cyl = &displayed_dive.cylinder[i];
- if (cylinder_nodata(cyl))
- break;
+ for (int i = 0; i < displayed_dive.cylinders.nr; i++) {
+ const cylinder_t *cyl = &displayed_dive.cylinders.cylinders[i];
/* Check if we have the same gasmix two or more times
* If yes return more verbose string */
int same_gas = same_gasmix_cylinder(cyl, i, &displayed_dive, true);
diff --git a/smtk-import/smartrak.c b/smtk-import/smartrak.c
index 968233eda..64a613fc7 100644
--- a/smtk-import/smartrak.c
+++ b/smtk-import/smartrak.c
@@ -507,7 +507,7 @@ static void merge_cylinder_info(cylinder_t *src, cylinder_t *dst)
static int smtk_clean_cylinders(struct dive *d)
{
int i = tanks - 1;
- cylinder_t *cyl, *base = &d->cylinder[0];
+ cylinder_t *cyl, *base = &d->cylinders.cylinders[0];
cyl = base + tanks - 1;
while (cyl != base) {
@@ -966,8 +966,6 @@ void smartrak_import(const char *file, struct dive_table *divetable)
smtk_version = atoi(smtk_ver[0]);
tanks = (smtk_version < 10213) ? 3 : 10;
-
-
mdb_table = smtk_open_table(mdb, "Dives", col, bound_values);
if (!mdb_table) {
report_error("[Error][smartrak_import]\tFile %s does not seem to be an SmartTrak file.", file);
@@ -978,6 +976,8 @@ void smartrak_import(const char *file, struct dive_table *divetable)
dc_family_t dc_fam = DC_FAMILY_NULL;
unsigned char *prf_buffer, *hdr_buffer, *compl_buffer;
struct dive *smtkdive = alloc_dive();
+ for (i = 0; i < tanks; ++i)
+ add_empty_cylinder(&smtkdive->cylinders);
struct tm *tm_date = malloc(sizeof(struct tm));
size_t hdr_length, prf_length;
dc_status_t rc = 0;
@@ -1038,24 +1038,24 @@ void smartrak_import(const char *file, struct dive_table *divetable)
int tankidxcol = coln(TANKIDX);
for (i = 0; i < tanks; i++) {
- if (smtkdive->cylinder[i].start.mbar == 0)
- smtkdive->cylinder[i].start.mbar = lrint(strtod(col[(i * 2) + pstartcol]->bind_ptr, NULL) * 1000);
+ if (smtkdive->cylinders.cylinders[i].start.mbar == 0)
+ smtkdive->cylinders.cylinders[i].start.mbar = lrint(strtod(col[(i * 2) + pstartcol]->bind_ptr, NULL) * 1000);
/*
* If there is a start pressure ensure that end pressure is not zero as
* will be registered in DCs which only keep track of differential pressures,
* and collect the data registered by the user in mdb
*/
- if (smtkdive->cylinder[i].end.mbar == 0 && smtkdive->cylinder[i].start.mbar != 0)
- smtkdive->cylinder[i].end.mbar = lrint(strtod(col[(i * 2) + 1 + pstartcol]->bind_ptr, NULL) * 1000 ? : 1000);
- if (smtkdive->cylinder[i].gasmix.o2.permille == 0)
- smtkdive->cylinder[i].gasmix.o2.permille = lrint(strtod(col[i + o2fraccol]->bind_ptr, NULL) * 10);
+ if (smtkdive->cylinders.cylinders[i].end.mbar == 0 && smtkdive->cylinders.cylinders[i].start.mbar != 0)
+ smtkdive->cylinders.cylinders[i].end.mbar = lrint(strtod(col[(i * 2) + 1 + pstartcol]->bind_ptr, NULL) * 1000 ? : 1000);
+ if (smtkdive->cylinders.cylinders[i].gasmix.o2.permille == 0)
+ smtkdive->cylinders.cylinders[i].gasmix.o2.permille = lrint(strtod(col[i + o2fraccol]->bind_ptr, NULL) * 10);
if (smtk_version == 10213) {
- if (smtkdive->cylinder[i].gasmix.he.permille == 0)
- smtkdive->cylinder[i].gasmix.he.permille = lrint(strtod(col[i + hefraccol]->bind_ptr, NULL) * 10);
+ if (smtkdive->cylinders.cylinders[i].gasmix.he.permille == 0)
+ smtkdive->cylinders.cylinders[i].gasmix.he.permille = lrint(strtod(col[i + hefraccol]->bind_ptr, NULL) * 10);
} else {
- smtkdive->cylinder[i].gasmix.he.permille = 0;
+ smtkdive->cylinders.cylinders[i].gasmix.he.permille = 0;
}
- smtk_build_tank_info(mdb_clon, &smtkdive->cylinder[i], col[i + tankidxcol]->bind_ptr);
+ smtk_build_tank_info(mdb_clon, &smtkdive->cylinders.cylinders[i], col[i + tankidxcol]->bind_ptr);
}
/* Check for duplicated cylinders and clean them */
smtk_clean_cylinders(smtkdive);
diff --git a/tests/testplan.cpp b/tests/testplan.cpp
index 2e78ec3c9..b567fe5d7 100644
--- a/tests/testplan.cpp
+++ b/tests/testplan.cpp
@@ -51,11 +51,14 @@ void setupPlan(struct diveplan *dp)
struct gasmix ean36 = {{360}, {0}};
struct gasmix oxygen = {{1000}, {0}};
pressure_t po2 = {1600};
- displayed_dive.cylinder[0].gasmix = bottomgas;
- displayed_dive.cylinder[0].type.size.mliter = 36000;
- displayed_dive.cylinder[0].type.workingpressure.mbar = 232000;
- displayed_dive.cylinder[1].gasmix = ean36;
- displayed_dive.cylinder[2].gasmix = oxygen;
+ cylinder_t *cyl0 = get_or_create_cylinder(&displayed_dive, 0);
+ cylinder_t *cyl1 = get_or_create_cylinder(&displayed_dive, 1);
+ cylinder_t *cyl2 = get_or_create_cylinder(&displayed_dive, 2);
+ cyl0->gasmix = bottomgas;
+ cyl0->type.size.mliter = 36000;
+ cyl0->type.workingpressure.mbar = 232000;
+ cyl1->gasmix = ean36;
+ cyl2->gasmix = oxygen;
reset_cylinders(&displayed_dive, true);
free_dps(dp);
@@ -79,11 +82,14 @@ void setupPlanVpmb45m30mTx(struct diveplan *dp)
struct gasmix ean50 = {{500}, {0}};
struct gasmix oxygen = {{1000}, {0}};
pressure_t po2 = {1600};
- displayed_dive.cylinder[0].gasmix = bottomgas;
- displayed_dive.cylinder[0].type.size.mliter = 24000;
- displayed_dive.cylinder[0].type.workingpressure.mbar = 232000;
- displayed_dive.cylinder[1].gasmix = ean50;
- displayed_dive.cylinder[2].gasmix = oxygen;
+ cylinder_t *cyl0 = get_or_create_cylinder(&displayed_dive, 0);
+ cylinder_t *cyl1 = get_or_create_cylinder(&displayed_dive, 1);
+ cylinder_t *cyl2 = get_or_create_cylinder(&displayed_dive, 2);
+ cyl0->gasmix = bottomgas;
+ cyl0->type.size.mliter = 24000;
+ cyl0->type.workingpressure.mbar = 232000;
+ cyl1->gasmix = ean50;
+ cyl2->gasmix = oxygen;
reset_cylinders(&displayed_dive, true);
free_dps(dp);
@@ -107,11 +113,14 @@ void setupPlanVpmb60m10mTx(struct diveplan *dp)
struct gasmix tx50_15 = {{500}, {150}};
struct gasmix oxygen = {{1000}, {0}};
pressure_t po2 = {1600};
- displayed_dive.cylinder[0].gasmix = bottomgas;
- displayed_dive.cylinder[0].type.size.mliter = 24000;
- displayed_dive.cylinder[0].type.workingpressure.mbar = 232000;
- displayed_dive.cylinder[1].gasmix = tx50_15;
- displayed_dive.cylinder[2].gasmix = oxygen;
+ cylinder_t *cyl0 = get_or_create_cylinder(&displayed_dive, 0);
+ cylinder_t *cyl1 = get_or_create_cylinder(&displayed_dive, 1);
+ cylinder_t *cyl2 = get_or_create_cylinder(&displayed_dive, 2);
+ cyl0->gasmix = bottomgas;
+ cyl0->type.size.mliter = 24000;
+ cyl0->type.workingpressure.mbar = 232000;
+ cyl1->gasmix = tx50_15;
+ cyl2->gasmix = oxygen;
reset_cylinders(&displayed_dive, true);
free_dps(dp);
@@ -130,9 +139,10 @@ void setupPlanVpmb60m30minAir(struct diveplan *dp)
dp->decosac = prefs.decosac;
struct gasmix bottomgas = {{210}, {0}};
- displayed_dive.cylinder[0].gasmix = bottomgas;
- displayed_dive.cylinder[0].type.size.mliter = 100000;
- displayed_dive.cylinder[0].type.workingpressure.mbar = 232000;
+ cylinder_t *cyl0 = get_or_create_cylinder(&displayed_dive, 0);
+ cyl0->gasmix = bottomgas;
+ cyl0->type.size.mliter = 100000;
+ cyl0->type.workingpressure.mbar = 232000;
displayed_dive.surface_pressure.mbar = 1013;
reset_cylinders(&displayed_dive, true);
free_dps(dp);
@@ -152,10 +162,12 @@ void setupPlanVpmb60m30minEan50(struct diveplan *dp)
struct gasmix bottomgas = {{210}, {0}};
struct gasmix ean50 = {{500}, {0}};
pressure_t po2 = {1600};
- displayed_dive.cylinder[0].gasmix = bottomgas;
- displayed_dive.cylinder[0].type.size.mliter = 36000;
- displayed_dive.cylinder[0].type.workingpressure.mbar = 232000;
- displayed_dive.cylinder[1].gasmix = ean50;
+ cylinder_t *cyl0 = get_or_create_cylinder(&displayed_dive, 0);
+ cylinder_t *cyl1 = get_or_create_cylinder(&displayed_dive, 1);
+ cyl0->gasmix = bottomgas;
+ cyl0->type.size.mliter = 36000;
+ cyl0->type.workingpressure.mbar = 232000;
+ cyl1->gasmix = ean50;
displayed_dive.surface_pressure.mbar = 1013;
reset_cylinders(&displayed_dive, true);
free_dps(dp);
@@ -176,10 +188,12 @@ void setupPlanVpmb60m30minTx(struct diveplan *dp)
struct gasmix bottomgas = {{180}, {450}};
struct gasmix ean50 = {{500}, {0}};
pressure_t po2 = {1600};
- displayed_dive.cylinder[0].gasmix = bottomgas;
- displayed_dive.cylinder[0].type.size.mliter = 36000;
- displayed_dive.cylinder[0].type.workingpressure.mbar = 232000;
- displayed_dive.cylinder[1].gasmix = ean50;
+ cylinder_t *cyl0 = get_or_create_cylinder(&displayed_dive, 0);
+ cylinder_t *cyl1 = get_or_create_cylinder(&displayed_dive, 1);
+ cyl0->gasmix = bottomgas;
+ cyl0->type.size.mliter = 36000;
+ cyl0->type.workingpressure.mbar = 232000;
+ cyl1->gasmix = ean50;
displayed_dive.surface_pressure.mbar = 1013;
reset_cylinders(&displayed_dive, true);
free_dps(dp);
@@ -198,9 +212,10 @@ void setupPlanVpmbMultiLevelAir(struct diveplan *dp)
dp->decosac = prefs.decosac;
struct gasmix bottomgas = {{210}, {0}};
- displayed_dive.cylinder[0].gasmix = bottomgas;
- displayed_dive.cylinder[0].type.size.mliter = 200000;
- displayed_dive.cylinder[0].type.workingpressure.mbar = 232000;
+ cylinder_t *cyl0 = get_or_create_cylinder(&displayed_dive, 0);
+ cyl0->gasmix = bottomgas;
+ cyl0->type.size.mliter = 200000;
+ cyl0->type.workingpressure.mbar = 232000;
displayed_dive.surface_pressure.mbar = 1013;
reset_cylinders(&displayed_dive, true);
free_dps(dp);
@@ -223,11 +238,14 @@ void setupPlanVpmb100m60min(struct diveplan *dp)
struct gasmix ean50 = {{500}, {0}};
struct gasmix oxygen = {{1000}, {0}};
pressure_t po2 = {1600};
- displayed_dive.cylinder[0].gasmix = bottomgas;
- displayed_dive.cylinder[0].type.size.mliter = 200000;
- displayed_dive.cylinder[0].type.workingpressure.mbar = 232000;
- displayed_dive.cylinder[1].gasmix = ean50;
- displayed_dive.cylinder[2].gasmix = oxygen;
+ cylinder_t *cyl0 = get_or_create_cylinder(&displayed_dive, 0);
+ cylinder_t *cyl1 = get_or_create_cylinder(&displayed_dive, 1);
+ cylinder_t *cyl2 = get_or_create_cylinder(&displayed_dive, 2);
+ cyl0->gasmix = bottomgas;
+ cyl0->type.size.mliter = 200000;
+ cyl0->type.workingpressure.mbar = 232000;
+ cyl1->gasmix = ean50;
+ cyl2->gasmix = oxygen;
displayed_dive.surface_pressure.mbar = 1013;
reset_cylinders(&displayed_dive, true);
free_dps(dp);
@@ -250,11 +268,14 @@ void setupPlanVpmb100m10min(struct diveplan *dp)
struct gasmix ean50 = {{500}, {0}};
struct gasmix oxygen = {{1000}, {0}};
pressure_t po2 = {1600};
- displayed_dive.cylinder[0].gasmix = bottomgas;
- displayed_dive.cylinder[0].type.size.mliter = 60000;
- displayed_dive.cylinder[0].type.workingpressure.mbar = 232000;
- displayed_dive.cylinder[1].gasmix = ean50;
- displayed_dive.cylinder[2].gasmix = oxygen;
+ cylinder_t *cyl0 = get_or_create_cylinder(&displayed_dive, 0);
+ cylinder_t *cyl1 = get_or_create_cylinder(&displayed_dive, 1);
+ cylinder_t *cyl2 = get_or_create_cylinder(&displayed_dive, 2);
+ cyl0->gasmix = bottomgas;
+ cyl0->type.size.mliter = 60000;
+ cyl0->type.workingpressure.mbar = 232000;
+ cyl1->gasmix = ean50;
+ cyl2->gasmix = oxygen;
displayed_dive.surface_pressure.mbar = 1013;
reset_cylinders(&displayed_dive, true);
free_dps(dp);
@@ -274,9 +295,10 @@ void setupPlanVpmb30m20min(struct diveplan *dp)
dp->decosac = prefs.decosac;
struct gasmix bottomgas = {{210}, {0}};
- displayed_dive.cylinder[0].gasmix = bottomgas;
- displayed_dive.cylinder[0].type.size.mliter = 36000;
- displayed_dive.cylinder[0].type.workingpressure.mbar = 232000;
+ cylinder_t *cyl0 = get_or_create_cylinder(&displayed_dive, 0);
+ cyl0->gasmix = bottomgas;
+ cyl0->type.size.mliter = 36000;
+ cyl0->type.workingpressure.mbar = 232000;
displayed_dive.surface_pressure.mbar = 1013;
reset_cylinders(&displayed_dive, true);
free_dps(dp);
@@ -298,12 +320,16 @@ void setupPlanVpmb100mTo70m30min(struct diveplan *dp)
struct gasmix ean50 = {{500}, {0}};
struct gasmix oxygen = {{1000}, {0}};
pressure_t po2 = {1600};
- displayed_dive.cylinder[0].gasmix = bottomgas;
- displayed_dive.cylinder[0].type.size.mliter = 36000;
- displayed_dive.cylinder[0].type.workingpressure.mbar = 232000;
- displayed_dive.cylinder[1].gasmix = tx21_35;
- displayed_dive.cylinder[2].gasmix = ean50;
- displayed_dive.cylinder[3].gasmix = oxygen;
+ cylinder_t *cyl0 = get_or_create_cylinder(&displayed_dive, 0);
+ cylinder_t *cyl1 = get_or_create_cylinder(&displayed_dive, 1);
+ cylinder_t *cyl2 = get_or_create_cylinder(&displayed_dive, 2);
+ cylinder_t *cyl3 = get_or_create_cylinder(&displayed_dive, 3);
+ cyl0->gasmix = bottomgas;
+ cyl0->type.size.mliter = 36000;
+ cyl0->type.workingpressure.mbar = 232000;
+ cyl1->gasmix = tx21_35;
+ cyl2->gasmix = ean50;
+ cyl3->gasmix = oxygen;
displayed_dive.surface_pressure.mbar = 1013;
reset_cylinders(&displayed_dive, true);
free_dps(dp);
@@ -330,10 +356,12 @@ void setupPlanSeveralGases(struct diveplan *dp)
struct gasmix ean36 = {{360}, {0}};
struct gasmix tx11_50 = {{110}, {500}};
- displayed_dive.cylinder[0].gasmix = ean36;
- displayed_dive.cylinder[0].type.size.mliter = 36000;
- displayed_dive.cylinder[0].type.workingpressure.mbar = 232000;
- displayed_dive.cylinder[1].gasmix = tx11_50;
+ cylinder_t *cyl0 = get_or_create_cylinder(&displayed_dive, 0);
+ cylinder_t *cyl1 = get_or_create_cylinder(&displayed_dive, 1);
+ cyl0->gasmix = ean36;
+ cyl0->type.size.mliter = 36000;
+ cyl0->type.workingpressure.mbar = 232000;
+ cyl1->gasmix = tx11_50;
displayed_dive.surface_pressure.mbar = 1013;
reset_cylinders(&displayed_dive, true);
free_dps(dp);