Core: remove MAX_CYLINDERS restriction

Instead of using fixed size arrays, use a new cylinder_table structure.
The code copies the weightsystem code, but is significantly more complex
because cylinders are such an integral part of the core.

Two functions to access the cylinders were added:
get_cylinder() and get_or_create_cylinder()
The former does a simple array access and supposes that the cylinder
exists. The latter is used by the parser(s) and if a cylinder with
the given id does not exist, cylinders up to that id are generated.

One point will make C programmers cringe: the cylinder structure is
passed by value. This is due to the way the table-macros work. A
refactoring of the table macros is planned. It has to be noted that
the size of a cylinder_t is 64 bytes, i.e. 8 long words on a 64-bit
architecture, so passing on the stack is probably not even significantly
slower than passing as reference.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2019-08-04 18:44:57 +02:00 committed by Dirk Hohndel
parent cd4f66014f
commit 7c9f46acd2
51 changed files with 804 additions and 779 deletions

View file

@ -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];

View file

@ -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;

View file

@ -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 *);

View file

@ -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, j;
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;
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)
@ -2127,51 +2119,16 @@ static int match_cylinder(const cylinder_t *cyl, const struct dive *dive, bool *
return -1;
}
/*
* 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;
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' 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);
/* 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;

View file

@ -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);

View file

@ -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;

View file

@ -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);
}
/* 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)
{
cyl.type.description = copy_string(cyl.type.description);
add_to_cylinder_table(t, t->nr, cyl);
}
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)
bool same_cylinder(cylinder_t cyl1, cylinder_t cyl2)
{
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;
}
static bool cylinder_nosamples(const cylinder_t *cyl)
{
return !cyl->sample_start.mbar &&
!cyl->sample_end.mbar;
}
bool cylinder_none(const cylinder_t *cyl)
{
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);

View file

@ -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);

View file

@ -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)

View file

@ -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;

View file

@ -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++;
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);
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 = 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'))) {

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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;
}

View file

@ -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)

View file

@ -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;

View file

@ -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);

View file

@ -190,13 +190,13 @@ void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_d
nextdp = dp->next;
if (dp->time == 0)
continue;
gasmix = dive->cylinder[dp->cylinderid].gasmix;
gasmix = dive->cylinders.cylinders[dp->cylinderid].gasmix;
depthvalue = get_depth_units(dp->depth.mm, &decimals, &depth_unit);
/* analyze the dive points ahead */
while (nextdp && nextdp->time == 0)
nextdp = nextdp->next;
if (nextdp)
newgasmix = dive->cylinder[nextdp->cylinderid].gasmix;
newgasmix = dive->cylinders.cylinders[nextdp->cylinderid].gasmix;
gaschange_after = (nextdp && (gasmix_distance(gasmix, newgasmix)));
gaschange_before = (gasmix_distance(lastprintgasmix, gasmix));
rebreatherchange_after = (nextdp && (dp->setpoint != nextdp->setpoint || dp->divemode != nextdp->divemode));
@ -461,16 +461,14 @@ void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_d
free(temp);
/* Print gas consumption: This loop covers all cylinders */
for (int gasidx = 0; gasidx < MAX_CYLINDERS; gasidx++) {
for (int gasidx = 0; gasidx < dive->cylinders.nr; gasidx++) {
double volume, pressure, deco_volume, deco_pressure, mingas_volume, mingas_pressure, mingas_d_pressure, mingas_depth;
const char *unit, *pressure_unit, *depth_unit;
char warning[1000] = "";
char mingas[1000] = "";
cylinder_t *cyl = &dive->cylinder[gasidx];
cylinder_t *cyl = &dive->cylinders.cylinders[gasidx];
if (cyl->cylinder_use == NOT_USED)
continue;
if (cylinder_none(cyl))
break;
volume = get_volume_units(cyl->gas_used.mliter, NULL, &unit);
deco_volume = get_volume_units(cyl->deco_gas_used.mliter, NULL, &unit);
@ -583,7 +581,7 @@ void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_d
while (dp) {
if (dp->time != 0) {
struct gas_pressures pressures;
struct gasmix gasmix = dive->cylinder[dp->cylinderid].gasmix;
struct gasmix gasmix = dive->cylinders.cylinders[dp->cylinderid].gasmix;
current_divemode = get_current_divemode(&dive->dc, dp->time, &evd, &current_divemode);
amb = depth_to_atm(dp->depth.mm, dive);

View file

@ -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;

View file

@ -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)

View file

@ -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;

View file

@ -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, ", ");

View file

@ -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++) {

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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) {

View file

@ -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 */

View file

@ -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));

View file

@ -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);

View file

@ -651,13 +651,24 @@ bool weightsystems_equal(const dive *d1, const dive *d2)
return true;
}
bool cylinders_equal(const dive *d1, const dive *d2)
{
if (d1->cylinders.nr != d2->cylinders.nr)
return false;
for (int i = 0; i < d1->cylinders.nr; ++i) {
if (!same_cylinder(d1->cylinders.cylinders[i], d2->cylinders.cylinders[i]))
return false;
}
return true;
}
void MainTab::rejectChanges()
{
EditMode lastMode = editMode;
if (lastMode != NONE && current_dive &&
(modified ||
memcmp(&current_dive->cylinder[0], &displayed_dive.cylinder[0], sizeof(cylinder_t) * MAX_CYLINDERS) ||
!cylinders_equal(current_dive, &displayed_dive) ||
!weightsystems_equal(current_dive, &displayed_dive))) {
if (QMessageBox::warning(MainWindow::instance(), TITLE_OR_TEXT(tr("Discard the changes?"),
tr("You are about to discard your changes.")),

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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()));
}

View file

@ -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

View file

@ -131,10 +131,10 @@ static QVariant percent_string(fraction_t fraction)
QVariant CylindersModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= MAX_CYLINDERS)
if (!index.isValid() || index.row() >= rows)
return QVariant();
const cylinder_t *cyl = &displayed_dive.cylinder[index.row()];
const cylinder_t *cyl = &displayed_dive.cylinders.cylinders[index.row()];
switch (role) {
case Qt::BackgroundRole: {
@ -259,7 +259,7 @@ QVariant CylindersModel::data(const QModelIndex &index, int role) const
cylinder_t *CylindersModel::cylinderAt(const QModelIndex &index)
{
return &displayed_dive.cylinder[index.row()];
return &displayed_dive.cylinders.cylinders[index.row()];
}
// this is our magic 'pass data in' function that allows the delegate to get
@ -420,16 +420,14 @@ int CylindersModel::rowCount(const QModelIndex&) const
void CylindersModel::add()
{
if (rows >= MAX_CYLINDERS) {
return;
}
int row = rows;
fill_default_cylinder(&displayed_dive, row);
displayed_dive.cylinder[row].start = displayed_dive.cylinder[row].type.workingpressure;
displayed_dive.cylinder[row].manually_added = true;
displayed_dive.cylinder[row].cylinder_use = OC_GAS;
cylinder_t cyl = { 0 };
fill_default_cylinder(&displayed_dive, &cyl);
cyl.start = cyl.type.workingpressure;
cyl.manually_added = true;
cyl.cylinder_use = OC_GAS;
beginInsertRows(QModelIndex(), row, row);
add_to_cylinder_table(&displayed_dive.cylinders, row, cyl);
rows++;
changed = true;
endInsertRows();
@ -446,12 +444,12 @@ void CylindersModel::clear()
static bool show_cylinder(struct dive *dive, int i)
{
cylinder_t *cyl = dive->cylinder + i;
if (i < 0 || i >= dive->cylinders.nr)
return false;
if (is_cylinder_used(dive, i))
return true;
if (cylinder_none(cyl))
return false;
cylinder_t *cyl = dive->cylinders.cylinders + i;
if (cyl->start.mbar || cyl->sample_start.mbar ||
cyl->end.mbar || cyl->sample_end.mbar)
return true;
@ -467,34 +465,18 @@ static bool show_cylinder(struct dive *dive, int i)
void CylindersModel::updateDive()
{
clear();
rows = 0;
#ifdef DEBUG_CYL
dump_cylinders(&displayed_dive, true);
#endif
for (int i = 0; i < MAX_CYLINDERS; i++) {
if (show_cylinder(&displayed_dive, i))
rows = i + 1;
}
if (rows > 0) {
beginInsertRows(QModelIndex(), 0, rows - 1);
endInsertRows();
}
}
void CylindersModel::copyFromDive(dive *d)
{
if (!d)
return;
beginResetModel();
// TODO: this is fundamentally broken - it assumes that unused cylinders are at
// the end. Fix by using a QSortFilterProxyModel.
rows = 0;
for (int i = 0; i < MAX_CYLINDERS; i++) {
if (show_cylinder(d, i))
rows = i + 1;
}
if (rows > 0) {
beginInsertRows(QModelIndex(), 0, rows - 1);
endInsertRows();
for (int i = 0; i < displayed_dive.cylinders.nr; ++i) {
if (show_cylinder(&displayed_dive, i))
++rows;
}
endResetModel();
}
Qt::ItemFlags CylindersModel::flags(const QModelIndex &index) const
@ -506,7 +488,6 @@ Qt::ItemFlags CylindersModel::flags(const QModelIndex &index) const
void CylindersModel::remove(const QModelIndex &index)
{
std::vector<int> mapping(MAX_CYLINDERS);
if (index.column() == USE) {
cylinder_t *cyl = cylinderAt(index);
@ -518,48 +499,53 @@ void CylindersModel::remove(const QModelIndex &index)
dataChanged(index, index);
return;
}
if (index.column() != REMOVE) {
if (index.column() != REMOVE)
return;
}
if ((in_planner() && DivePlannerPointsModel::instance()->tankInUse(index.row())) ||
(!in_planner() && is_cylinder_prot(&displayed_dive, index.row())))
return;
beginRemoveRows(QModelIndex(), index.row(), index.row()); // yah, know, ugly.
beginRemoveRows(QModelIndex(), index.row(), index.row());
rows--;
remove_cylinder(&displayed_dive, index.row());
for (int i = 0; i < index.row(); i++)
mapping[i] = i;
// No mapping for removed gas, set to -1
changed = true;
endRemoveRows();
// Create a mapping of cylinder indexes:
// 1) Fill mapping[0]..mapping[index-1] with 0..index
// 2) Set mapping[index] to -1
// 3) Fill mapping[index+1]..mapping[end] with index..
std::vector<int> mapping(displayed_dive.cylinders.nr + 1);
std::iota(mapping.begin(), mapping.begin() + index.row(), 0);
mapping[index.row()] = -1;
for (int i = index.row() + 1; i < MAX_CYLINDERS; i++)
mapping[i] = i - 1;
std::iota(mapping.begin() + index.row() + 1, mapping.end(), index.row());
cylinder_renumber(&displayed_dive, &mapping[0]);
if (in_planner())
DivePlannerPointsModel::instance()->cylinderRenumber(&mapping[0]);
changed = true;
endRemoveRows();
dataChanged(index, index);
}
void CylindersModel::moveAtFirst(int cylid)
{
std::vector<int> mapping(MAX_CYLINDERS);
cylinder_t temp_cyl;
beginMoveRows(QModelIndex(), cylid, cylid, QModelIndex(), 0);
memmove(&temp_cyl, &displayed_dive.cylinder[cylid], sizeof(temp_cyl));
for (int i = cylid - 1; i >= 0; i--) {
memmove(&displayed_dive.cylinder[i + 1], &displayed_dive.cylinder[i], sizeof(temp_cyl));
mapping[i] = i + 1;
}
memmove(&displayed_dive.cylinder[0], &temp_cyl, sizeof(temp_cyl));
memmove(&temp_cyl, &displayed_dive.cylinders.cylinders[cylid], sizeof(temp_cyl));
for (int i = cylid - 1; i >= 0; i--)
memmove(&displayed_dive.cylinders.cylinders[i + 1], &displayed_dive.cylinders.cylinders[i], sizeof(temp_cyl));
memmove(&displayed_dive.cylinders.cylinders[0], &temp_cyl, sizeof(temp_cyl));
// Create a mapping of cylinder indexes:
// 1) Fill mapping[0]..mapping[cyl] with 0..index
// 2) Set mapping[cyl] to 0
// 3) Fill mapping[cyl+1]..mapping[end] with cyl..
std::vector<int> mapping(displayed_dive.cylinders.nr);
std::iota(mapping.begin(), mapping.begin() + cylid, 1);
mapping[cylid] = 0;
for (int i = cylid + 1; i < MAX_CYLINDERS; i++)
mapping[i] = i;
std::iota(mapping.begin() + (cylid + 1), mapping.end(), cylid);
cylinder_renumber(&displayed_dive, &mapping[0]);
if (in_planner())
DivePlannerPointsModel::instance()->cylinderRenumber(&mapping[0]);
@ -571,28 +557,28 @@ void CylindersModel::updateDecoDepths(pressure_t olddecopo2)
{
pressure_t decopo2;
decopo2.mbar = prefs.decopo2;
for (int i = 0; i < MAX_CYLINDERS; i++) {
cylinder_t *cyl = &displayed_dive.cylinder[i];
for (int i = 0; i < displayed_dive.cylinders.nr; i++) {
cylinder_t *cyl = &displayed_dive.cylinders.cylinders[i];
/* If the gas's deco MOD matches the old pO2, it will have been automatically calculated and should be updated.
* If they don't match, we should leave the user entered depth as it is */
if (cyl->depth.mm == gas_mod(cyl->gasmix, olddecopo2, &displayed_dive, M_OR_FT(3, 10)).mm) {
cyl->depth = gas_mod(cyl->gasmix, decopo2, &displayed_dive, M_OR_FT(3, 10));
}
}
emit dataChanged(createIndex(0, 0), createIndex(MAX_CYLINDERS - 1, COLUMNS - 1));
emit dataChanged(createIndex(0, 0), createIndex(displayed_dive.cylinders.nr - 1, COLUMNS - 1));
}
void CylindersModel::updateTrashIcon()
{
emit dataChanged(createIndex(0, 0), createIndex(MAX_CYLINDERS - 1, 0));
emit dataChanged(createIndex(0, 0), createIndex(displayed_dive.cylinders.nr - 1, 0));
}
bool CylindersModel::updateBestMixes()
{
// Check if any of the cylinders are best mixes, update if needed
bool gasUpdated = false;
for (int i = 0; i < MAX_CYLINDERS; i++) {
cylinder_t *cyl = &displayed_dive.cylinder[i];
for (int i = 0; i < displayed_dive.cylinders.nr; i++) {
cylinder_t *cyl = &displayed_dive.cylinders.cylinders[i];
if (cyl->bestmix_o2) {
cyl->gasmix.o2 = best_o2(displayed_dive.maxdepth, &displayed_dive);
// fO2 + fHe must not be greater than 1
@ -614,7 +600,7 @@ bool CylindersModel::updateBestMixes()
/* This slot is called when the bottom pO2 and END preferences are updated, we want to
* emit dataChanged so MOD and MND are refreshed, even if the gas mix hasn't been changed */
if (gasUpdated)
emit dataChanged(createIndex(0, 0), createIndex(MAX_CYLINDERS - 1, COLUMNS - 1));
emit dataChanged(createIndex(0, 0), createIndex(displayed_dive.cylinders.nr - 1, COLUMNS - 1));
return gasUpdated;
}
@ -626,7 +612,7 @@ void CylindersModel::cylindersReset(const QVector<dive *> &dives)
return;
// Copy the cylinders from the current dive to the displayed dive.
copy_cylinders(current_dive, &displayed_dive, false);
copy_cylinders(&current_dive->cylinders, &displayed_dive.cylinders);
// And update the model..
updateDive();

View file

@ -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);

View file

@ -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) {

View file

@ -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();
}

View file

@ -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:

View file

@ -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);

View file

@ -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);

View file

@ -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);