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