diff options
author | Berthold Stoeger <bstoeger@mail.tuwien.ac.at> | 2019-08-04 18:44:57 +0200 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2019-11-09 19:19:04 +0100 |
commit | 7c9f46acd202121e67557bb634961ef17a9f6c1f (patch) | |
tree | f21b6ff42a930cc97c31db9f20c03f1613e70291 /core | |
parent | cd4f66014f7b5269dff9e088c9d7d38241c03156 (diff) | |
download | subsurface-7c9f46acd202121e67557bb634961ef17a9f6c1f.tar.gz |
Core: remove MAX_CYLINDERS restriction
Instead of using fixed size arrays, use a new cylinder_table structure.
The code copies the weightsystem code, but is significantly more complex
because cylinders are such an integral part of the core.
Two functions to access the cylinders were added:
get_cylinder() and get_or_create_cylinder()
The former does a simple array access and supposes that the cylinder
exists. The latter is used by the parser(s) and if a cylinder with
the given id does not exist, cylinders up to that id are generated.
One point will make C programmers cringe: the cylinder structure is
passed by value. This is due to the way the table-macros work. A
refactoring of the table macros is planned. It has to be noted that
the size of a cylinder_t is 64 bytes, i.e. 8 long words on a 64-bit
architecture, so passing on the stack is probably not even significantly
slower than passing as reference.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Diffstat (limited to 'core')
-rw-r--r-- | core/cochran.c | 24 | ||||
-rw-r--r-- | core/datatrak.c | 32 | ||||
-rw-r--r-- | core/display.h | 3 | ||||
-rw-r--r-- | core/dive.c | 282 | ||||
-rw-r--r-- | core/dive.h | 9 | ||||
-rw-r--r-- | core/divelist.c | 10 | ||||
-rw-r--r-- | core/equipment.c | 117 | ||||
-rw-r--r-- | core/equipment.h | 25 | ||||
-rw-r--r-- | core/gaspressures.c | 9 | ||||
-rw-r--r-- | core/import-cobalt.c | 14 | ||||
-rw-r--r-- | core/import-csv.c | 30 | ||||
-rw-r--r-- | core/import-divinglog.c | 26 | ||||
-rw-r--r-- | core/import-shearwater.c | 20 | ||||
-rw-r--r-- | core/import-suunto.c | 34 | ||||
-rw-r--r-- | core/libdivecomputer.c | 58 | ||||
-rw-r--r-- | core/liquivision.c | 7 | ||||
-rw-r--r-- | core/load-git.c | 18 | ||||
-rw-r--r-- | core/parse-xml.c | 92 | ||||
-rw-r--r-- | core/parse.c | 3 | ||||
-rw-r--r-- | core/parse.h | 1 | ||||
-rw-r--r-- | core/planner.c | 80 | ||||
-rw-r--r-- | core/plannernotes.c | 12 | ||||
-rw-r--r-- | core/profile.c | 53 | ||||
-rw-r--r-- | core/qthelper.cpp | 6 | ||||
-rw-r--r-- | core/save-git.c | 2 | ||||
-rw-r--r-- | core/save-html.c | 2 | ||||
-rw-r--r-- | core/save-profiledata.c | 8 | ||||
-rw-r--r-- | core/save-xml.c | 2 | ||||
-rw-r--r-- | core/statistics.c | 24 | ||||
-rw-r--r-- | core/subsurface-qt/DiveObjectHelper.cpp | 38 | ||||
-rw-r--r-- | core/uemis.c | 11 |
31 files changed, 544 insertions, 508 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, ¤t_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; |