core: use std::vector<> to store divecomputer samples

This is a hairy one, because the sample code is rather tricky.

There was a pattern of looping through pairs of adjacent samples,
for interpolation purposes. Add an range adapter to generalize
such loops.

Removes the finish_sample() function: The code would call
prepare_sample() to start parsing of samples and then
finish_sample() to actuall add it. I.e. a kind of commit().

Since, with one exception, all users of prepare_sample()
called finish_sample() in all code paths, we might just add
the sample in the first place. The exception was sample_end()
in parse.cpp. This brings a small change: samples are now
added, even if they could only be parsed partially. I doubt
that this makes any difference, since it will only happen
for broken divelogs anyway.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2024-05-19 12:38:38 +02:00 committed by bstoeger
parent bc761344d4
commit f120fecccb
28 changed files with 588 additions and 715 deletions

View file

@ -276,7 +276,6 @@ void export_depths(const char *filename, bool selected_only)
{
FILE *f;
struct dive *dive;
depth_t depth;
int i;
const char *unit = NULL;
@ -287,12 +286,11 @@ void export_depths(const char *filename, bool selected_only)
continue;
FOR_EACH_PICTURE (dive) {
int n = dive->dc.samples;
struct sample *s = dive->dc.sample;
depth.mm = 0;
while (--n >= 0 && (int32_t)s->time.seconds <= picture->offset.seconds) {
depth.mm = s->depth.mm;
s++;
depth_t depth;
for (auto &s: dive->dc.samples) {
if ((int32_t)s.time.seconds > picture->offset.seconds)
break;
depth = s.depth;
}
put_format(&buf, "%s\t%.1f", picture->filename, get_depth_units(depth.mm, NULL, &unit));
put_format(&buf, "%s\n", unit);

View file

@ -308,7 +308,7 @@ void EditDuration::set(struct dive *d, int value) const
d->dc.duration.seconds = value;
d->duration = d->dc.duration;
d->dc.meandepth.mm = 0;
d->dc.samples = 0;
d->dc.samples.clear();
fake_dc(&d->dc);
}
@ -328,7 +328,7 @@ void EditDepth::set(struct dive *d, int value) const
d->dc.maxdepth.mm = value;
d->maxdepth = d->dc.maxdepth;
d->dc.meandepth.mm = 0;
d->dc.samples = 0;
d->dc.samples.clear();
fake_dc(&d->dc);
}
@ -897,7 +897,7 @@ EditProfile::EditProfile(const dive *source, int dcNr, EditProfileType type, int
meandepth = source->meandepth;
duration = source->duration;
copy_samples(sdc, &dc);
dc.samples = sdc->samples;
copy_events(sdc, &dc);
setText(editProfileTypeToString(type, count) + " " + diveNumberOrDate(d));
@ -919,8 +919,6 @@ void EditProfile::undo()
if (!sdc)
return;
std::swap(sdc->samples, dc.samples);
std::swap(sdc->alloc_samples, dc.alloc_samples);
std::swap(sdc->sample, dc.sample);
std::swap(sdc->events, dc.events);
std::swap(sdc->maxdepth, dc.maxdepth);
std::swap(d->maxdepth, maxdepth);
@ -1339,13 +1337,13 @@ EditSensors::EditSensors(int toCylinderIn, int fromCylinderIn, int dcNr)
void EditSensors::mapSensors(int toCyl, int fromCyl)
{
for (int i = 0; i < dc->samples; ++i) {
for (auto &sample: dc->samples) {
for (int s = 0; s < MAX_SENSORS; ++s) {
if (dc->sample[i].pressure[s].mbar && dc->sample[i].sensor[s] == fromCyl)
dc->sample[i].sensor[s] = toCyl;
if (sample.pressure[s].mbar && sample.sensor[s] == fromCyl)
sample.sensor[s] = toCyl;
// In case the cylinder we are moving to has a sensor attached, move it to the other cylinder
else if (dc->sample[i].pressure[s].mbar && dc->sample[i].sensor[s] == toCyl)
dc->sample[i].sensor[s] = fromCyl;
else if (sample.pressure[s].mbar && sample.sensor[s] == toCyl)
sample.sensor[s] = fromCyl;
}
}
emit diveListNotifier.diveComputerEdited(dc);

View file

@ -494,10 +494,6 @@ static void cochran_parse_samples(struct dive *dive, const unsigned char *log,
while (offset + config.sample_size < size) {
s = samples + offset;
// Start with an empty sample
sample = prepare_sample(dc);
sample->time.seconds = sample_cnt * profile_period;
// Check for event
if (s[0] & 0x80) {
cochran_dive_event(dc, s, sample_cnt * profile_period, &in_deco, &deco_ceiling, &deco_time);
@ -505,6 +501,10 @@ static void cochran_parse_samples(struct dive *dive, const unsigned char *log,
continue;
}
// Start with an empty sample
sample = prepare_sample(dc);
sample->time.seconds = sample_cnt * profile_period;
// Depth is in every sample
depth_sample = (double)(s[0] & 0x3F) / 4 * (s[0] & 0x40 ? -1 : 1);
depth += depth_sample;
@ -591,8 +591,6 @@ static void cochran_parse_samples(struct dive *dive, const unsigned char *log,
sample->sensor[0] = 0;
sample->pressure[0].mbar = lrint(psi * PSI / 100);
finish_sample(dc);
offset += config.sample_size;
sample_cnt++;
}

View file

@ -52,6 +52,9 @@ dive::~dive()
free_dive_structures(this);
}
dive::dive(dive &&) = default;
dive &dive::operator=(const dive &) = default;
/*
* The legacy format for sample pressures has a single pressure
* for each sample that can have any sensor, plus a possible
@ -65,16 +68,15 @@ dive::~dive()
*/
int legacy_format_o2pressures(const struct dive *dive, const struct divecomputer *dc)
{
int i, o2sensor;
int o2sensor;
o2sensor = (dc->divemode == CCR) ? get_cylinder_idx_by_use(dive, OXYGEN) : -1;
for (i = 0; i < dc->samples; i++) {
const struct sample *s = dc->sample + i;
for (const auto &s: dc->samples) {
int seen_pressure = 0, idx;
for (idx = 0; idx < MAX_SENSORS; idx++) {
int sensor = s->sensor[idx];
pressure_t p = s->pressure[idx];
int sensor = s.sensor[idx];
pressure_t p = s.pressure[idx];
if (!p.mbar)
continue;
@ -180,7 +182,6 @@ int dive_getUniqID()
static void copy_dc(const struct divecomputer *sdc, struct divecomputer *ddc)
{
*ddc = *sdc;
copy_samples(sdc, ddc);
copy_events(sdc, ddc);
}
@ -515,14 +516,13 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i
return;
}
if (!dc->samples)
if (dc->samples.empty())
fake_dc(dc);
const struct event *ev = get_next_event(dc->events, "gaschange");
std::vector<int> depthtime(dive->cylinders.nr, 0);
for (i = 0; i < dc->samples; i++) {
struct sample *sample = dc->sample + i;
int32_t time = sample->time.seconds;
int depth = sample->depth.mm;
for (auto it = dc->samples.begin(); it != dc->samples.end(); ++it) {
int32_t time = it->time.seconds;
int depth = it->depth.mm;
/* Make sure to move the event past 'lasttime' */
while (ev && lasttime >= ev->time.seconds) {
@ -531,13 +531,13 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i
}
/* Do we need to fake a midway sample at an event? */
if (ev && time > ev->time.seconds) {
if (ev && it != dc->samples.begin() && time > ev->time.seconds) {
int newtime = ev->time.seconds;
int newdepth = interpolate(lastdepth, depth, newtime - lasttime, time - lasttime);
time = newtime;
depth = newdepth;
i--;
--it;
}
/* We ignore segments at the surface */
if (depth > SURFACE_THRESHOLD || lastdepth > SURFACE_THRESHOLD) {
@ -586,7 +586,7 @@ int explicit_first_cylinder(const struct dive *dive, const struct divecomputer *
return -1;
if (dc) {
const struct event *ev = get_next_event(dc->events, "gaschange");
if (ev && ((dc->sample && ev->time.seconds == dc->sample[0].time.seconds) || ev->time.seconds <= 1))
if (ev && ((!dc->samples.empty() && ev->time.seconds == dc->samples[0].time.seconds) || ev->time.seconds <= 1))
res = get_cylinder_index(dive, ev);
else if (dc->divemode == CCR)
res = std::max(get_cylinder_idx_by_use(dive, DILUENT), res);
@ -618,15 +618,15 @@ void update_setpoint_events(const struct dive *dive, struct divecomputer *dc)
struct gasmix gasmix = get_gasmix_from_event(dive, ev);
const struct event *next = get_next_event(ev, "gaschange");
for (int i = 0; i < dc->samples; i++) {
if (next && dc->sample[i].time.seconds >= next->time.seconds) {
for (auto &sample: dc->samples) {
if (next && sample.time.seconds >= next->time.seconds) {
ev = next;
gasmix = get_gasmix_from_event(dive, ev);
next = get_next_event(ev, "gaschange");
}
gas_pressures pressures = fill_pressures(lrint(calculate_depth_to_mbarf(dc->sample[i].depth.mm, dc->surface_pressure, 0)), gasmix ,0, dc->divemode);
if (abs(dc->sample[i].setpoint.mbar - (int)(1000 * pressures.o2)) <= 50)
dc->sample[i].setpoint.mbar = 0;
gas_pressures pressures = fill_pressures(lrint(calculate_depth_to_mbarf(sample.depth.mm, dc->surface_pressure, 0)), gasmix ,0, dc->divemode);
if (abs(sample.setpoint.mbar - (int)(1000 * pressures.o2)) <= 50)
sample.setpoint.mbar = 0;
}
}
@ -906,16 +906,14 @@ static void fixup_dc_events(struct divecomputer *dc)
static int interpolate_depth(struct divecomputer *dc, int idx, int lastdepth, int lasttime, int now)
{
int i;
int nextdepth = lastdepth;
int nexttime = now;
for (i = idx+1; i < dc->samples; i++) {
struct sample *sample = dc->sample + i;
if (sample->depth.mm < 0)
for (auto it = dc->samples.begin() + idx; it != dc->samples.end(); ++it) {
if (it->depth.mm < 0)
continue;
nextdepth = sample->depth.mm;
nexttime = sample->time.seconds;
nextdepth = it->depth.mm;
nexttime = it->time.seconds;
break;
}
return interpolate(lastdepth, nextdepth, now-lasttime, nexttime-lasttime);
@ -923,18 +921,16 @@ static int interpolate_depth(struct divecomputer *dc, int idx, int lastdepth, in
static void fixup_dc_depths(struct dive *dive, struct divecomputer *dc)
{
int i;
int maxdepth = dc->maxdepth.mm;
int lasttime = 0, lastdepth = 0;
for (i = 0; i < dc->samples; i++) {
struct sample *sample = dc->sample + i;
int time = sample->time.seconds;
int depth = sample->depth.mm;
for (const auto [idx, sample]: enumerated_range(dc->samples)) {
int time = sample.time.seconds;
int depth = sample.depth.mm;
if (depth < 0) {
depth = interpolate_depth(dc, i, lastdepth, lasttime, time);
sample->depth.mm = depth;
if (depth < 0 && idx + 2 < static_cast<int>(dc->samples.size())) {
depth = interpolate_depth(dc, idx, lastdepth, lasttime, time);
sample.depth.mm = depth;
}
if (depth > SURFACE_THRESHOLD) {
@ -944,8 +940,8 @@ static void fixup_dc_depths(struct dive *dive, struct divecomputer *dc)
lastdepth = depth;
lasttime = time;
if (sample->cns > dive->maxcns)
dive->maxcns = sample->cns;
if (sample.cns > dive->maxcns)
dive->maxcns = sample.cns;
}
update_depth(&dc->maxdepth, maxdepth);
@ -956,25 +952,20 @@ static void fixup_dc_depths(struct dive *dive, struct divecomputer *dc)
static void fixup_dc_ndl(struct divecomputer *dc)
{
int i;
for (i = 0; i < dc->samples; i++) {
struct sample *sample = dc->sample + i;
if (sample->ndl.seconds != 0)
for (auto &sample: dc->samples) {
if (sample.ndl.seconds != 0)
break;
if (sample->ndl.seconds == 0)
sample->ndl.seconds = -1;
if (sample.ndl.seconds == 0)
sample.ndl.seconds = -1;
}
}
static void fixup_dc_temp(struct dive *dive, struct divecomputer *dc)
{
int i;
int mintemp = 0, lasttemp = 0;
for (i = 0; i < dc->samples; i++) {
struct sample *sample = dc->sample + i;
int temp = sample->temperature.mkelvin;
for (auto &sample: dc->samples) {
int temp = sample.temperature.mkelvin;
if (temp) {
/*
@ -983,7 +974,7 @@ static void fixup_dc_temp(struct dive *dive, struct divecomputer *dc)
* the redundant ones.
*/
if (lasttemp == temp)
sample->temperature.mkelvin = 0;
sample.temperature.mkelvin = 0;
else
lasttemp = temp;
@ -991,7 +982,7 @@ static void fixup_dc_temp(struct dive *dive, struct divecomputer *dc)
mintemp = temp;
}
update_min_max_temperatures(dive, sample->temperature);
update_min_max_temperatures(dive, sample.temperature);
}
update_temperature(&dc->watertemp, mintemp);
update_min_max_temperatures(dive, dc->watertemp);
@ -1000,22 +991,20 @@ static void fixup_dc_temp(struct dive *dive, struct divecomputer *dc)
/* Remove redundant pressure information */
static void simplify_dc_pressures(struct divecomputer *dc)
{
int i;
int lastindex[2] = { -1, -1 };
int lastpressure[2] = { 0 };
for (i = 0; i < dc->samples; i++) {
for (auto &sample: dc->samples) {
int j;
struct sample *sample = dc->sample + i;
for (j = 0; j < MAX_SENSORS; j++) {
int pressure = sample->pressure[j].mbar;
int index = sample->sensor[j];
int pressure = sample.pressure[j].mbar;
int index = sample.sensor[j];
if (index == lastindex[j]) {
/* Remove duplicate redundant pressure information */
if (pressure == lastpressure[j])
sample->pressure[j].mbar = 0;
sample.pressure[j].mbar = 0;
}
lastindex[j] = index;
lastpressure[j] = pressure;
@ -1057,30 +1046,22 @@ static void fixup_end_pressure(struct dive *dive, int idx, pressure_t p)
*/
static void fixup_dive_pressures(struct dive *dive, struct divecomputer *dc)
{
int i;
/* Walk the samples from the beginning to find starting pressures.. */
for (i = 0; i < dc->samples; i++) {
int idx;
struct sample *sample = dc->sample + i;
if (sample->depth.mm < SURFACE_THRESHOLD)
for (auto &sample: dc->samples) {
if (sample.depth.mm < SURFACE_THRESHOLD)
continue;
for (idx = 0; idx < MAX_SENSORS; idx++)
fixup_start_pressure(dive, sample->sensor[idx], sample->pressure[idx]);
for (int idx = 0; idx < MAX_SENSORS; idx++)
fixup_start_pressure(dive, sample.sensor[idx], sample.pressure[idx]);
}
/* ..and from the end for ending pressures */
for (i = dc->samples; --i >= 0; ) {
int idx;
struct sample *sample = dc->sample + i;
if (sample->depth.mm < SURFACE_THRESHOLD)
for (auto it = dc->samples.rbegin(); it != dc->samples.rend(); ++it) {
if (it->depth.mm < SURFACE_THRESHOLD)
continue;
for (idx = 0; idx < MAX_SENSORS; idx++)
fixup_end_pressure(dive, sample->sensor[idx], sample->pressure[idx]);
for (int idx = 0; idx < MAX_SENSORS; idx++)
fixup_end_pressure(dive, it->sensor[idx], it->pressure[idx]);
}
simplify_dc_pressures(dc);
@ -1155,13 +1136,12 @@ static void fixup_no_o2sensors(struct divecomputer *dc)
if (dc->no_o2sensors != 0 || !(dc->divemode == CCR || dc->divemode == PSCR))
return;
for (int i = 0; i < dc->samples; i++) {
int nsensor = 0, j;
struct sample *s = dc->sample + i;
for (const auto &sample: dc->samples) {
int nsensor = 0;
// How many o2 sensors can we find in this sample?
for (j = 0; j < MAX_O2_SENSORS; j++)
if (s->o2sensor[j].mbar)
for (int j = 0; j < MAX_O2_SENSORS; j++)
if (sample.o2sensor[j].mbar)
nsensor++;
// If we fond more than the previous found max, record it.
@ -1178,21 +1158,20 @@ static void fixup_dc_sample_sensors(struct dive *dive, struct divecomputer *dc)
{
unsigned long sensor_mask = 0;
for (int i = 0; i < dc->samples; i++) {
struct sample *s = dc->sample + i;
for (auto &sample: dc->samples) {
for (int j = 0; j < MAX_SENSORS; j++) {
int sensor = s->sensor[j];
int sensor = sample.sensor[j];
// No invalid sensor ID's, please
if (sensor < 0 || sensor > MAX_SENSORS) {
s->sensor[j] = NO_SENSOR;
s->pressure[j].mbar = 0;
sample.sensor[j] = NO_SENSOR;
sample.pressure[j].mbar = 0;
continue;
}
// Don't bother tracking sensors with no data
if (!s->pressure[j].mbar) {
s->sensor[j] = NO_SENSOR;
if (!sample.pressure[j].mbar) {
sample.sensor[j] = NO_SENSOR;
continue;
}
@ -1240,7 +1219,7 @@ static void fixup_dive_dc(struct dive *dive, struct divecomputer *dc)
fixup_no_o2sensors(dc);
/* If there are no samples, generate a fake profile based on depth and time */
if (!dc->samples)
if (dc->samples.empty())
fake_dc(dc);
}
@ -1304,13 +1283,12 @@ struct dive *fixup_dive(struct dive *dive)
* that the time in between the dives is at the surface, not some "last
* sample that happened to be at a depth of 1.2m".
*/
static void merge_one_sample(const struct sample *sample, int time, struct divecomputer *dc)
static void merge_one_sample(const struct sample &sample, int time, struct divecomputer *dc)
{
int last = dc->samples - 1;
if (last >= 0) {
struct sample *prev = dc->sample + last;
int last_time = prev->time.seconds;
int last_depth = prev->depth.mm;
if (!dc->samples.empty()) {
const struct sample &prev = dc->samples.back();
int last_time = prev.time.seconds;
int last_depth = prev.depth.mm;
/*
* Only do surface events if the samples are more than
@ -1320,18 +1298,18 @@ static void merge_one_sample(const struct sample *sample, int time, struct divec
struct sample surface;
/* Init a few values from prev sample to avoid useless info in XML */
surface.bearing.degrees = prev->bearing.degrees;
surface.ndl.seconds = prev->ndl.seconds;
surface.bearing.degrees = prev.bearing.degrees;
surface.ndl.seconds = prev.ndl.seconds;
add_sample(&surface, last_time + 20, dc);
add_sample(&surface, time - 20, dc);
}
}
add_sample(sample, time, dc);
add_sample(&sample, time, dc);
}
static void renumber_last_sample(struct divecomputer *dc, const int mapping[]);
static void sample_renumber(struct sample *s, int i, const int mapping[]);
static void sample_renumber(struct sample &s, const struct sample *next, const int mapping[]);
/*
* Merge samples. Dive 'a' is "offset" seconds before Dive 'b'
@ -1341,10 +1319,10 @@ static void merge_samples(struct divecomputer *res,
const int *cylinders_map_a, const int *cylinders_map_b,
int offset)
{
int asamples = a->samples;
int bsamples = b->samples;
struct sample *as = a->sample;
struct sample *bs = b->sample;
auto as = a->samples.begin();
auto bs = b->samples.begin();
auto a_end = a->samples.end();
auto b_end = b->samples.end();
/*
* We want a positive sample offset, so that sample
@ -1354,27 +1332,18 @@ static void merge_samples(struct divecomputer *res,
* the reverse offset.
*/
if (offset < 0) {
const int *cylinders_map_tmp;
offset = -offset;
asamples = bsamples;
bsamples = a->samples;
as = bs;
bs = a->sample;
cylinders_map_tmp = cylinders_map_a;
cylinders_map_a = cylinders_map_b;
cylinders_map_b = cylinders_map_tmp;
std::swap(as, bs);
std::swap(a_end, b_end);
std::swap(cylinders_map_a, cylinders_map_b);
}
for (;;) {
int j;
int at, bt;
struct sample sample;
if (!res)
return;
at = asamples ? as->time.seconds : -1;
bt = bsamples ? bs->time.seconds + offset : -1;
int at = as != a_end ? as->time.seconds : -1;
int bt = bs != b_end ? bs->time.seconds + offset : -1;
/* No samples? All done! */
if (at < 0 && bt < 0)
@ -1383,20 +1352,18 @@ static void merge_samples(struct divecomputer *res,
/* Only samples from a? */
if (bt < 0) {
add_sample_a:
merge_one_sample(as, at, res);
merge_one_sample(*as, at, res);
renumber_last_sample(res, cylinders_map_a);
as++;
asamples--;
continue;
}
/* Only samples from b? */
if (at < 0) {
add_sample_b:
merge_one_sample(bs, bt, res);
merge_one_sample(*bs, bt, res);
renumber_last_sample(res, cylinders_map_b);
bs++;
bsamples--;
continue;
}
@ -1406,13 +1373,13 @@ static void merge_samples(struct divecomputer *res,
goto add_sample_b;
/* same-time sample: add a merged sample. Take the non-zero ones */
sample = *bs;
sample_renumber(&sample, 0, cylinders_map_b);
struct sample sample = *bs;
sample_renumber(sample, nullptr, cylinders_map_b);
if (as->depth.mm)
sample.depth = as->depth;
if (as->temperature.mkelvin)
sample.temperature = as->temperature;
for (j = 0; j < MAX_SENSORS; ++j) {
for (int j = 0; j < MAX_SENSORS; ++j) {
int sensor_id;
sensor_id = cylinders_map_a[as->sensor[j]];
@ -1437,12 +1404,10 @@ static void merge_samples(struct divecomputer *res,
if (as->in_deco)
sample.in_deco = true;
merge_one_sample(&sample, at, res);
merge_one_sample(sample, at, res);
as++;
bs++;
asamples--;
bsamples--;
}
}
@ -1636,38 +1601,34 @@ static void add_initial_gaschange(struct dive *dive, struct divecomputer *dc, in
add_gas_switch_event(dive, dc, offset, idx);
}
static void sample_renumber(struct sample *s, int i, const int mapping[])
static void sample_renumber(struct sample &s, const struct sample *prev, const int mapping[])
{
int j;
for (j = 0; j < MAX_SENSORS; j++) {
for (int j = 0; j < MAX_SENSORS; j++) {
int sensor = -1;
if (s->sensor[j] != NO_SENSOR)
sensor = mapping[s->sensor[j]];
if (s.sensor[j] != NO_SENSOR)
sensor = mapping[s.sensor[j]];
if (sensor == -1) {
// Remove sensor and gas pressure info
if (i == 0) {
s->sensor[j] = 0;
s->pressure[j].mbar = 0;
if (!prev) {
s.sensor[j] = 0;
s.pressure[j].mbar = 0;
} else {
s->sensor[j] = s[-1].sensor[j];
s->pressure[j].mbar = s[-1].pressure[j].mbar;
s.sensor[j] = prev->sensor[j];
s.pressure[j].mbar = prev->pressure[j].mbar;
}
} else {
s->sensor[j] = sensor;
s.sensor[j] = sensor;
}
}
}
static void renumber_last_sample(struct divecomputer *dc, const int mapping[])
{
int idx;
if (dc->samples <= 0)
if (dc->samples.empty())
return;
idx = dc->samples - 1;
sample_renumber(dc->sample + idx, idx, mapping);
sample *prev = dc->samples.size() > 1 ? &dc->samples[dc->samples.size() - 2] : nullptr;
sample_renumber(dc->samples.back(), prev, mapping);
}
static void event_renumber(struct event *ev, const int mapping[])
@ -1681,12 +1642,11 @@ static void event_renumber(struct event *ev, const int mapping[])
static void dc_cylinder_renumber(struct dive *dive, struct divecomputer *dc, const int mapping[])
{
int i;
struct event *ev;
/* Remap or delete the sensor indices */
for (i = 0; i < dc->samples; i++)
sample_renumber(dc->sample + i, i, mapping);
for (auto [i, sample]: enumerated_range(dc->samples))
sample_renumber(sample, i > 0 ? &dc->samples[i-1] : nullptr, mapping);
/* Remap the gas change indices */
for (ev = dc->events; ev; ev = ev->next)
@ -2008,17 +1968,17 @@ static struct dive_trip *get_preferred_trip(const struct dive *a, const struct d
/*
* Sample 's' is between samples 'a' and 'b'. It is 'offset' seconds before 'b'.
*
* If 's' and 'a' are at the same time, offset is 0, and b is NULL.
* If 's' and 'a' are at the same time, offset is 0.
*/
static int compare_sample(struct sample *s, struct sample *a, struct sample *b, int offset)
static int compare_sample(const struct sample &s, const struct sample &a, const struct sample &b, int offset)
{
unsigned int depth = a->depth.mm;
unsigned int depth = a.depth.mm;
int diff;
if (offset) {
unsigned int interval = b->time.seconds - a->time.seconds;
unsigned int depth_a = a->depth.mm;
unsigned int depth_b = b->depth.mm;
unsigned int interval = b.time.seconds - a.time.seconds;
unsigned int depth_a = a.depth.mm;
unsigned int depth_b = b.depth.mm;
if (offset > interval)
return -1;
@ -2027,7 +1987,7 @@ static int compare_sample(struct sample *s, struct sample *a, struct sample *b,
depth = (depth_a * offset) + (depth_b * (interval - offset));
depth /= interval;
}
diff = s->depth.mm - depth;
diff = s.depth.mm - depth;
if (diff < 0)
diff = -diff;
/* cut off at one meter difference */
@ -2043,10 +2003,9 @@ static int compare_sample(struct sample *s, struct sample *a, struct sample *b,
*/
static unsigned long sample_difference(struct divecomputer *a, struct divecomputer *b, int offset)
{
int asamples = a->samples;
int bsamples = b->samples;
struct sample *as = a->sample;
struct sample *bs = b->sample;
if (a->samples.empty() || b->samples.empty())
return;
unsigned long error = 0;
int start = -1;
@ -2057,45 +2016,36 @@ static unsigned long sample_difference(struct divecomputer *a, struct divecomput
* skip the first sample - this way we know can always look at
* as/bs[-1] to look at the samples around it in the loop.
*/
as++;
bs++;
asamples--;
bsamples--;
auto as = a->samples.begin() + 1;
auto bs = a->samples.begin() + 1;
for (;;) {
int at, bt, diff;
/* If we run out of samples, punt */
if (!asamples)
if (as == a->samples.end())
return INT_MAX;
if (!bsamples)
if (bs == b->samples.end())
return INT_MAX;
at = as->time.seconds;
bt = bs->time.seconds + offset;
int at = as->time.seconds;
int bt = bs->time.seconds + offset;
/* b hasn't started yet? Ignore it */
if (bt < 0) {
bs++;
bsamples--;
++bs;
continue;
}
int diff;
if (at < bt) {
diff = compare_sample(as, bs - 1, bs, bt - at);
as++;
asamples--;
diff = compare_sample(*as, *std::prev(bs), *bs, bt - at);
++as;
} else if (at > bt) {
diff = compare_sample(bs, as - 1, as, at - bt);
bs++;
bsamples--;
diff = compare_sample(*bs, *std::prev(as), *as, at - bt);
++bs;
} else {
diff = compare_sample(as, bs, NULL, 0);
as++;
bs++;
asamples--;
bsamples--;
diff = compare_sample(*as, *bs, *bs, 0);
++as;
++bs;
}
/* Invalid comparison point? */
@ -2130,13 +2080,10 @@ static unsigned long sample_difference(struct divecomputer *a, struct divecomput
*/
static int find_sample_offset(struct divecomputer *a, struct divecomputer *b)
{
int offset, best;
unsigned long max;
/* No samples? Merge at any time (0 offset) */
if (!a->samples)
if (a->samples.empty())
return 0;
if (!b->samples)
if (b->samples.empty())
return 0;
/*
@ -2145,8 +2092,8 @@ static int find_sample_offset(struct divecomputer *a, struct divecomputer *b)
* Check this first, without wasting time trying to find
* some minimal offset case.
*/
best = 0;
max = sample_difference(a, b, 0);
int best = 0;
unsigned long max = sample_difference(a, b, 0);
if (!max)
return 0;
@ -2154,10 +2101,10 @@ static int find_sample_offset(struct divecomputer *a, struct divecomputer *b)
* Otherwise, look if we can find anything better within
* a thirty second window..
*/
for (offset = -30; offset <= 30; offset++) {
for (int offset = -30; offset <= 30; offset++) {
unsigned long diff;
diff = sample_difference(a, b, offset);
int diff = sample_difference(a, b, offset);
if (diff > max)
continue;
best = offset;
@ -2320,17 +2267,17 @@ struct dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_downloaded
return res;
}
static int same_sample(struct sample *a, struct sample *b)
static bool operator==(const sample &a, const sample &b)
{
if (a->time.seconds != b->time.seconds)
return 0;
if (a->depth.mm != b->depth.mm)
return 0;
if (a->temperature.mkelvin != b->temperature.mkelvin)
return 0;
if (a->pressure[0].mbar != b->pressure[0].mbar)
return 0;
return a->sensor[0] == b->sensor[0];
if (a.time.seconds != b.time.seconds)
return false;
if (a.depth.mm != b.depth.mm)
return false;
if (a.temperature.mkelvin != b.temperature.mkelvin)
return false;
if (a.pressure[0].mbar != b.pressure[0].mbar)
return false;
return a.sensor[0] == b.sensor[0];
}
static int same_dc(struct divecomputer *a, struct divecomputer *b)
@ -2346,9 +2293,6 @@ static int same_dc(struct divecomputer *a, struct divecomputer *b)
return 0;
if (a->samples != b->samples)
return 0;
for (i = 0; i < a->samples; i++)
if (!same_sample(a->sample + i, b->sample + i))
return 0;
eva = a->events;
evb = b->events;
while (eva && evb) {
@ -2416,8 +2360,7 @@ static const struct divecomputer *find_matching_computer(const struct divecomput
static void copy_dive_computer(struct divecomputer *res, const struct divecomputer *a)
{
*res = *a;
res->samples = res->alloc_samples = 0;
res->sample = NULL;
res->samples.clear();
res->events = NULL;
res->next = NULL;
}
@ -2694,7 +2637,7 @@ static void force_fixup_dive(struct dive *d)
*/
static int split_dive_at(const struct dive *dive, int a, int b, struct dive **out1, struct dive **out2)
{
int i, nr;
int nr;
int32_t t;
struct dive *d1, *d2;
struct divecomputer *dc1, *dc2;
@ -2705,7 +2648,7 @@ static int split_dive_at(const struct dive *dive, int a, int b, struct dive **ou
return -1;
/* Splitting should leave at least 3 samples per dive */
if (a < 3 || b > dive->dc.samples - 4)
if (a < 3 || static_cast<size_t>(b + 4) > dive->dc.samples.size())
return -1;
/* We're not trying to be efficient here.. */
@ -2724,26 +2667,22 @@ static int split_dive_at(const struct dive *dive, int a, int b, struct dive **ou
* Cut off the samples of d1 at the beginning
* of the interval.
*/
dc1->samples = a;
dc1->samples.resize(a);
/* And get rid of the 'b' first samples of d2 */
dc2->samples -= b;
memmove(dc2->sample, dc2->sample+b, dc2->samples * sizeof(struct sample));
dc2->samples.erase(dc2->samples.begin(), dc2->samples.begin() + b);
/* Now the secondary dive computers */
t = dc2->sample[0].time.seconds;
while ((dc1 = dc1->next)) {
i = 0;
while (dc1->samples < i && dc1->sample[i].time.seconds <= t)
++i;
dc1->samples = i;
t = dc2->samples[0].time.seconds;
while ((dc1 = dc1->next)) {
auto it = std::find_if(dc1->samples.begin(), dc1->samples.end(),
[t](auto &sample) { return sample.time.seconds >= t; });
dc1->samples.erase(it, dc1->samples.end());
}
while ((dc2 = dc2->next)) {
i = 0;
while (dc2->samples < i && dc2->sample[i].time.seconds < t)
++i;
dc2->samples -= i;
memmove(dc2->sample, dc2->sample + i, dc2->samples * sizeof(struct sample));
auto it = std::find_if(dc2->samples.begin(), dc2->samples.end(),
[t](auto &sample) { return sample.time.seconds >= t; });
dc2->samples.erase(dc2->samples.begin(), it);
}
dc1 = &d1->dc;
dc2 = &d2->dc;
@ -2754,8 +2693,8 @@ static int split_dive_at(const struct dive *dive, int a, int b, struct dive **ou
d2->when += t;
while (dc1 && dc2) {
dc2->when += t;
for (i = 0; i < dc2->samples; i++)
dc2->sample[i].time.seconds -= t;
for (auto &sample: dc2->samples)
sample.time.seconds -= t;
/* Remove the events past 't' from d1 */
evp = &dc1->events;
@ -2823,20 +2762,17 @@ static bool should_split(const struct divecomputer *dc, int t1, int t2)
*/
int split_dive(const struct dive *dive, struct dive **new1, struct dive **new2)
{
int i;
int at_surface, surface_start;
const struct divecomputer *dc;
*new1 = *new2 = NULL;
if (!dive)
return -1;
dc = &dive->dc;
surface_start = 0;
at_surface = 1;
for (i = 1; i < dc->samples; i++) {
struct sample *sample = dc->sample+i;
int surface_sample = sample->depth.mm < SURFACE_THRESHOLD;
const struct divecomputer *dc = &dive->dc;
bool at_surface = true;
if (dc->samples.empty())
return -1;
auto surface_start = dc->samples.begin();
for (auto it = dc->samples.begin() + 1; it != dc->samples.end(); ++it) {
bool surface_sample = it->depth.mm < SURFACE_THRESHOLD;
/*
* We care about the transition from and to depth 0,
@ -2848,38 +2784,35 @@ int split_dive(const struct dive *dive, struct dive **new1, struct dive **new2)
// Did it become surface after having been non-surface? We found the start
if (at_surface) {
surface_start = i;
surface_start = it;
continue;
}
// Going down again? We want at least a minute from
// the surface start.
if (!surface_start)
if (surface_start == dc->samples.begin())
continue;
if (!should_split(dc, dc->sample[surface_start].time.seconds, sample[-1].time.seconds))
if (!should_split(dc, surface_start->time.seconds, std::prev(it)->time.seconds))
continue;
return split_dive_at(dive, surface_start, i-1, new1, new2);
return split_dive_at(dive, surface_start - dc->samples.begin(), it - dc->samples.begin() - 1, new1, new2);
}
return -1;
}
int split_dive_at_time(const struct dive *dive, duration_t time, struct dive **new1, struct dive **new2)
{
int i = 0;
if (!dive)
return -1;
struct sample *sample = dive->dc.sample;
*new1 = *new2 = NULL;
while(sample->time.seconds < time.seconds) {
++sample;
++i;
if (dive->dc.samples == i)
return -1;
}
return split_dive_at(dive, i, i - 1, new1, new2);
auto it = std::find_if(dive->dc.samples.begin(), dive->dc.samples.end(),
[time](auto &sample) { return sample.time.seconds >= time.seconds; });
if (it == dive->dc.samples.end())
return -1;
size_t idx = it - dive->dc.samples.begin();
if (idx < 1)
return -1;
return split_dive_at(dive, static_cast<int>(idx), static_cast<int>(idx - 1), new1, new2);
}
/*
@ -2893,12 +2826,10 @@ int split_dive_at_time(const struct dive *dive, duration_t time, struct dive **n
static inline int dc_totaltime(const struct divecomputer *dc)
{
int time = dc->duration.seconds;
int nr = dc->samples;
while (nr--) {
struct sample *s = dc->sample + nr;
time = s->time.seconds;
if (s->depth.mm >= SURFACE_THRESHOLD)
for (auto it = dc->samples.rbegin(); it != dc->samples.rend(); ++it) {
time = it->time.seconds;
if (it->depth.mm >= SURFACE_THRESHOLD)
break;
}
return time;
@ -3464,12 +3395,11 @@ struct gasmix get_gasmix_at_time(const struct dive *d, const struct divecomputer
bool cylinder_with_sensor_sample(const struct dive *dive, int cylinder_id)
{
for (const struct divecomputer *dc = &dive->dc; dc; dc = dc->next) {
for (int i = 0; i < dc->samples; ++i) {
struct sample *sample = dc->sample + i;
for (const auto &sample: dc->samples) {
for (int j = 0; j < MAX_SENSORS; ++j) {
if (!sample->pressure[j].mbar)
if (!sample.pressure[j].mbar)
continue;
if (sample->sensor[j] == cylinder_id)
if (sample.sensor[j] == cylinder_id)
return true;
}
}

View file

@ -59,6 +59,8 @@ struct dive {
dive();
~dive();
dive(dive &&);
dive &operator=(const dive &);
};
/* For the top-level list: an entry is either a dive or a trip */

View file

@ -21,6 +21,7 @@ divecomputer::~divecomputer()
}
divecomputer::divecomputer(divecomputer &&) = default;
divecomputer &divecomputer::operator=(const divecomputer &) = default;
/*
* Good fake dive profiles are hard.
@ -81,7 +82,7 @@ divecomputer::divecomputer(divecomputer &&) = default;
* In general, we have more free variables than we have constraints,
* but we can aim for certain basics, like a good ascent slope.
*/
static int fill_samples(struct sample *s, int max_d, int avg_d, int max_t, double slope, double d_frac)
static int fill_samples(std::vector<sample> &s, int max_d, int avg_d, int max_t, double slope, double d_frac)
{
double t_frac = max_t * (1 - avg_d / (double)max_d);
int t1 = lrint(max_d / slope);
@ -108,7 +109,7 @@ static int fill_samples(struct sample *s, int max_d, int avg_d, int max_t, doubl
* we should assume either a PADI rectangular profile (for short and/or
* shallow dives) or more reasonably a six point profile with a 3 minute
* safety stop at 5m */
static void fill_samples_no_avg(struct sample *s, int max_d, int max_t, double slope)
static void fill_samples_no_avg(std::vector<sample> &s, int max_d, int max_t, double slope)
{
// shallow or short dives are just trapecoids based on the given slope
if (max_d < 10000 || max_t < 600) {
@ -130,27 +131,24 @@ static void fill_samples_no_avg(struct sample *s, int max_d, int max_t, double s
void fake_dc(struct divecomputer *dc)
{
alloc_samples(dc, 6);
struct sample *fake = dc->sample;
int i;
dc->samples = 6;
/* The dive has no samples, so create a few fake ones */
int max_t = dc->duration.seconds;
int max_d = dc->maxdepth.mm;
int avg_d = dc->meandepth.mm;
memset(fake, 0, 6 * sizeof(struct sample));
if (!max_t || !max_d) {
dc->samples.clear();
return;
}
std::vector<struct sample> &fake = dc->samples;
fake.resize(6);
fake[5].time.seconds = max_t;
for (i = 0; i < 6; i++) {
for (int i = 0; i < 6; i++) {
fake[i].bearing.degrees = -1;
fake[i].ndl.seconds = -1;
}
if (!max_t || !max_d) {
dc->samples = 0;
return;
}
/* Set last manually entered time to the total dive length */
dc->last_manual_time = dc->duration;
@ -167,7 +165,7 @@ void fake_dc(struct divecomputer *dc)
* the user supplied data */
fill_samples_no_avg(fake, max_d, max_t, std::max(2.0 * max_d / max_t, (double)prefs.ascratelast6m));
if (fake[3].time.seconds == 0) { // just a 4 point profile
dc->samples = 4;
dc->samples.resize(4);
fake[3].time.seconds = max_t;
}
return;
@ -235,16 +233,16 @@ enum divemode_t get_current_divemode(const struct divecomputer *dc, int time, co
int get_depth_at_time(const struct divecomputer *dc, unsigned int time)
{
int depth = 0;
if (dc && dc->sample)
for (int i = 0; i < dc->samples; i++) {
if (dc->sample[i].time.seconds > (int)time)
if (dc) {
for (const auto &sample: dc->samples) {
if (sample.time.seconds > (int)time)
break;
depth = dc->sample[i].depth.mm;
depth = sample.depth.mm;
}
}
return depth;
}
static void free_dc(struct divecomputer *dc)
{
delete dc;
@ -257,60 +255,28 @@ void free_dive_dcs(struct divecomputer *dc)
STRUCTURED_LIST_FREE(struct divecomputer, dc->next, free_dc);
}
/* make room for num samples; if not enough space is available, the sample
* array is reallocated and the existing samples are copied. */
void alloc_samples(struct divecomputer *dc, int num)
{
if (num > dc->alloc_samples) {
dc->alloc_samples = (num * 3) / 2 + 10;
dc->sample = (struct sample *)realloc(dc->sample, dc->alloc_samples * sizeof(struct sample));
if (!dc->sample)
dc->samples = dc->alloc_samples = 0;
}
}
void free_samples(struct divecomputer *dc)
{
if (dc) {
free(dc->sample);
dc->sample = 0;
dc->samples = 0;
dc->alloc_samples = 0;
}
}
struct sample *prepare_sample(struct divecomputer *dc)
{
if (dc) {
int nr = dc->samples;
struct sample *sample;
alloc_samples(dc, nr + 1);
if (!dc->sample)
return NULL;
sample = dc->sample + nr;
memset(sample, 0, sizeof(*sample));
dc->samples.emplace_back();
auto &sample = dc->samples.back();
// Copy the sensor numbers - but not the pressure values
// from the previous sample if any.
if (nr) {
if (dc->samples.size() >= 2) {
auto &prev = dc->samples[dc->samples.size() - 2];
for (int idx = 0; idx < MAX_SENSORS; idx++)
sample->sensor[idx] = sample[-1].sensor[idx];
sample.sensor[idx] = prev.sensor[idx];
}
// Init some values with -1
sample->bearing.degrees = -1;
sample->ndl.seconds = -1;
sample.bearing.degrees = -1;
sample.ndl.seconds = -1;
return sample;
return &sample;
}
return NULL;
}
void finish_sample(struct divecomputer *dc)
{
dc->samples++;
}
struct sample *add_sample(const struct sample *sample, int time, struct divecomputer *dc)
{
struct sample *p = prepare_sample(dc);
@ -318,7 +284,6 @@ struct sample *add_sample(const struct sample *sample, int time, struct divecomp
if (p) {
*p = *sample;
p->time.seconds = time;
finish_sample(dc);
}
return p;
}
@ -331,17 +296,12 @@ struct sample *add_sample(const struct sample *sample, int time, struct divecomp
*/
void fixup_dc_duration(struct divecomputer *dc)
{
int duration, i;
int lasttime, lastdepth, depthtime;
int duration = 0;
int lasttime = 0, lastdepth = 0, depthtime = 0;
duration = 0;
lasttime = 0;
lastdepth = 0;
depthtime = 0;
for (i = 0; i < dc->samples; i++) {
struct sample *sample = dc->sample + i;
int time = sample->time.seconds;
int depth = sample->depth.mm;
for (const auto &sample: dc->samples) {
int time = sample.time.seconds;
int depth = sample.depth.mm;
/* We ignore segments at the surface */
if (depth > SURFACE_THRESHOLD || lastdepth > SURFACE_THRESHOLD) {
@ -357,7 +317,6 @@ void fixup_dc_duration(struct divecomputer *dc)
}
}
/*
* What do the dive computers say the water temperature is?
* (not in the samples, but as dc property for dcs that support that)
@ -413,28 +372,6 @@ void copy_events(const struct divecomputer *s, struct divecomputer *d)
*pev = NULL;
}
void copy_samples(const struct divecomputer *s, struct divecomputer *d)
{
/* instead of carefully copying them one by one and calling add_sample
* over and over again, let's just copy the whole blob */
if (!s || !d)
return;
int nr = s->samples;
d->samples = nr;
d->alloc_samples = nr;
// We expect to be able to read the memory in the other end of the pointer
// if its a valid pointer, so don't expect malloc() to return NULL for
// zero-sized malloc, do it ourselves.
d->sample = NULL;
if(!nr)
return;
d->sample = (struct sample *)malloc(nr * sizeof(struct sample));
if (d->sample)
memcpy(d->sample, s->sample, nr * sizeof(struct sample));
}
void add_event_to_dc(struct divecomputer *dc, struct event *ev)
{
struct event **p;
@ -528,7 +465,6 @@ int match_one_dc(const struct divecomputer *a, const struct divecomputer *b)
void free_dc_contents(struct divecomputer *dc)
{
free(dc->sample);
free_events(dc->events);
}

View file

@ -37,8 +37,7 @@ struct divecomputer {
int salinity = 0; // kg per 10000 l
std::string model, serial, fw_version;
uint32_t deviceid = 0, diveid = 0;
int samples = 0, alloc_samples = 0;
struct sample *sample = nullptr;
std::vector<struct sample> samples;
struct event *events = nullptr;
std::vector<struct extra_data> extra_data;
struct divecomputer *next = nullptr;
@ -46,6 +45,7 @@ struct divecomputer {
divecomputer();
~divecomputer();
divecomputer(divecomputer &&);
divecomputer &operator=(const divecomputer &);
};
extern void fake_dc(struct divecomputer *dc);
@ -53,17 +53,13 @@ extern void free_dc_contents(struct divecomputer *dc);
extern enum divemode_t get_current_divemode(const struct divecomputer *dc, int time, const struct event **evp, enum divemode_t *divemode);
extern int get_depth_at_time(const struct divecomputer *dc, unsigned int time);
extern void free_dive_dcs(struct divecomputer *dc);
extern void alloc_samples(struct divecomputer *dc, int num);
extern void free_samples(struct divecomputer *dc);
extern struct sample *prepare_sample(struct divecomputer *dc);
extern void finish_sample(struct divecomputer *dc);
extern struct sample *add_sample(const struct sample *sample, int time, struct divecomputer *dc);
extern void fixup_dc_duration(struct divecomputer *dc);
extern unsigned int dc_airtemp(const struct divecomputer *dc);
extern unsigned int dc_watertemp(const struct divecomputer *dc);
extern void copy_events(const struct divecomputer *s, struct divecomputer *d);
extern void swap_event(struct divecomputer *dc, struct event *from, struct event *to);
extern void copy_samples(const struct divecomputer *s, struct divecomputer *d);
extern void add_event_to_dc(struct divecomputer *dc, struct event *ev);
extern struct event *add_event(struct divecomputer *dc, unsigned int time, int type, int flags, int value, const std::string &name);
extern void remove_event_from_dc(struct divecomputer *dc, struct event *event);

View file

@ -15,6 +15,7 @@
#include "interpolate.h"
#include "planner.h"
#include "qthelper.h"
#include "range.h"
#include "gettext.h"
#include "git-access.h"
#include "selection.h"
@ -80,26 +81,25 @@ static int active_o2(const struct dive *dive, const struct divecomputer *dc, dur
}
// Do not call on first sample as it acccesses the previous sample
static int get_sample_o2(const struct dive *dive, const struct divecomputer *dc, const struct sample *sample)
static int get_sample_o2(const struct dive *dive, const struct divecomputer *dc, const struct sample &sample, const struct sample &psample)
{
int po2i, po2f, po2;
const struct sample *psample = sample - 1;
// Use sensor[0] if available
if ((dc->divemode == CCR || dc->divemode == PSCR) && sample->o2sensor[0].mbar) {
po2i = psample->o2sensor[0].mbar;
po2f = sample->o2sensor[0].mbar; // then use data from the first o2 sensor
if ((dc->divemode == CCR || dc->divemode == PSCR) && sample.o2sensor[0].mbar) {
po2i = psample.o2sensor[0].mbar;
po2f = sample.o2sensor[0].mbar; // then use data from the first o2 sensor
po2 = (po2f + po2i) / 2;
} else if (sample->setpoint.mbar > 0) {
po2 = std::min((int) sample->setpoint.mbar,
depth_to_mbar(sample->depth.mm, dive));
} else if (sample.setpoint.mbar > 0) {
po2 = std::min((int) sample.setpoint.mbar,
depth_to_mbar(sample.depth.mm, dive));
} else {
double amb_presure = depth_to_bar(sample->depth.mm, dive);
double pamb_pressure = depth_to_bar(psample->depth.mm , dive);
double amb_presure = depth_to_bar(sample.depth.mm, dive);
double pamb_pressure = depth_to_bar(psample.depth.mm , dive);
if (dc->divemode == PSCR) {
po2i = pscr_o2(pamb_pressure, get_gasmix_at_time(dive, dc, psample->time));
po2f = pscr_o2(amb_presure, get_gasmix_at_time(dive, dc, sample->time));
po2i = pscr_o2(pamb_pressure, get_gasmix_at_time(dive, dc, psample.time));
po2f = pscr_o2(amb_presure, get_gasmix_at_time(dive, dc, sample.time));
} else {
int o2 = active_o2(dive, dc, psample->time); // ... calculate po2 from depth and FiO2.
int o2 = active_o2(dive, dc, psample.time); // ... calculate po2 from depth and FiO2.
po2i = lrint(o2 * pamb_pressure); // (initial) po2 at start of segment
po2f = lrint(o2 * amb_presure); // (final) po2 at end of segment
}
@ -117,37 +117,34 @@ static int get_sample_o2(const struct dive *dive, const struct divecomputer *dc,
oxygen tolerance curves. Inst. env. Med. Report 1-70, University of Pennsylvania, Philadelphia, USA. */
static int calculate_otu(const struct dive *dive)
{
int i;
double otu = 0.0;
const struct divecomputer *dc = &dive->dc;
for (i = 1; i < dc->samples; i++) {
for (auto [psample, sample]: pairwise_range(dc->samples)) {
int t;
int po2i, po2f;
double pm;
struct sample *sample = dc->sample + i;
struct sample *psample = sample - 1;
t = sample->time.seconds - psample->time.seconds;
t = sample.time.seconds - psample.time.seconds;
// if there is sensor data use sensor[0]
if ((dc->divemode == CCR || dc->divemode == PSCR) && sample->o2sensor[0].mbar) {
po2i = psample->o2sensor[0].mbar;
po2f = sample->o2sensor[0].mbar; // ... use data from the first o2 sensor
if ((dc->divemode == CCR || dc->divemode == PSCR) && sample.o2sensor[0].mbar) {
po2i = psample.o2sensor[0].mbar;
po2f = sample.o2sensor[0].mbar; // ... use data from the first o2 sensor
} else {
if (sample->setpoint.mbar > 0) {
po2f = std::min((int) sample->setpoint.mbar,
depth_to_mbar(sample->depth.mm, dive));
if (psample->setpoint.mbar > 0)
po2i = std::min((int) psample->setpoint.mbar,
depth_to_mbar(psample->depth.mm, dive));
if (sample.setpoint.mbar > 0) {
po2f = std::min((int) sample.setpoint.mbar,
depth_to_mbar(sample.depth.mm, dive));
if (psample.setpoint.mbar > 0)
po2i = std::min((int) psample.setpoint.mbar,
depth_to_mbar(psample.depth.mm, dive));
else
po2i = po2f;
} else { // For OC and rebreather without o2 sensor/setpoint
double amb_presure = depth_to_bar(sample->depth.mm, dive);
double pamb_pressure = depth_to_bar(psample->depth.mm , dive);
double amb_presure = depth_to_bar(sample.depth.mm, dive);
double pamb_pressure = depth_to_bar(psample.depth.mm , dive);
if (dc->divemode == PSCR) {
po2i = pscr_o2(pamb_pressure, get_gasmix_at_time(dive, dc, psample->time));
po2f = pscr_o2(amb_presure, get_gasmix_at_time(dive, dc, sample->time));
po2i = pscr_o2(pamb_pressure, get_gasmix_at_time(dive, dc, psample.time));
po2f = pscr_o2(amb_presure, get_gasmix_at_time(dive, dc, sample.time));
} else {
int o2 = active_o2(dive, dc, psample->time); // ... calculate po2 from depth and FiO2.
int o2 = active_o2(dive, dc, psample.time); // ... calculate po2 from depth and FiO2.
po2i = lrint(o2 * pamb_pressure); // (initial) po2 at start of segment
po2f = lrint(o2 * amb_presure); // (final) po2 at end of segment
}
@ -182,18 +179,13 @@ static int calculate_otu(const struct dive *dive)
to the end of the segment, assuming a constant rate of change in po2 (i.e. depth) with time. */
static double calculate_cns_dive(const struct dive *dive)
{
int n;
const struct divecomputer *dc = &dive->dc;
double cns = 0.0;
double rate;
/* Calculate the CNS for each sample in this dive and sum them */
for (n = 1; n < dc->samples; n++) {
int t;
int po2;
struct sample *sample = dc->sample + n;
struct sample *psample = sample - 1;
t = sample->time.seconds - psample->time.seconds;
po2 = get_sample_o2(dive, dc, sample);
for (auto [psample, sample]: pairwise_range(dc->samples)) {
int t = sample.time.seconds - psample.time.seconds;
int po2 = get_sample_o2(dive, dc, sample, psample);
/* Don't increase CNS when po2 below 500 matm */
if (po2 <= 500)
continue;
@ -340,13 +332,12 @@ static int calculate_cns(struct dive *dive)
static double calculate_airuse(const struct dive *dive)
{
int airuse = 0;
int i;
// SAC for a CCR dive does not make sense.
if (dive->dc.divemode == CCR)
return 0.0;
for (i = 0; i < dive->cylinders.nr; i++) {
for (int i = 0; i < dive->cylinders.nr; i++) {
pressure_t start, end;
const cylinder_t *cyl = get_cylinder(dive, i);
@ -400,24 +391,21 @@ static void add_dive_to_deco(struct deco_state *ds, struct dive *dive, bool in_p
{
struct divecomputer *dc = &dive->dc;
struct gasmix gasmix = gasmix_air;
int i;
const struct event *ev = NULL, *evd = NULL;
enum divemode_t current_divemode = UNDEF_COMP_TYPE;
if (!dc)
return;
for (i = 1; i < dc->samples; i++) {
struct sample *psample = dc->sample + i - 1;
struct sample *sample = dc->sample + i;
int t0 = psample->time.seconds;
int t1 = sample->time.seconds;
for (auto [psample, sample]: pairwise_range(dc->samples)) {
int t0 = psample.time.seconds;
int t1 = sample.time.seconds;
int j;
for (j = t0; j < t1; j++) {
int depth = interpolate(psample->depth.mm, sample->depth.mm, j - t0, t1 - t0);
int depth = interpolate(psample.depth.mm, sample.depth.mm, j - t0, t1 - t0);
gasmix = get_gasmix(dive, dc, j, &ev, gasmix);
add_segment(ds, depth_to_bar(depth, dive), gasmix, 1, sample->setpoint.mbar,
add_segment(ds, depth_to_bar(depth, dive), gasmix, 1, sample.setpoint.mbar,
get_current_divemode(&dive->dc, j, &evd, &current_divemode), dive->sac,
in_planner);
}
@ -645,10 +633,10 @@ static int comp_dc(const struct divecomputer *dc1, const struct divecomputer *dc
* trip-time is defined such that dives that do not belong to
* a trip are sorted *after* dives that do. Thus, in the default
* chronologically-descending sort order, they are shown *before*.
* "id" is a stable, strictly increasing unique number, that
* is handed out when a dive is added to the system.
* "id" is a stable, strictly increasing unique number, which
* is generated when a dive is added to the system.
* We might also consider sorting by end-time and other criteria,
* but see the caveat above (editing means rearrangement of the dives).
* but see the caveat above (editing means reordering of the dives).
*/
int comp_dives(const struct dive *a, const struct dive *b)
{

View file

@ -436,7 +436,6 @@ int try_to_open_csv(std::string &mem, enum csv_format type, struct divelog *log)
sample = prepare_sample(dc);
sample->time.seconds = time;
add_sample_data(sample, type, val);
finish_sample(dc);
time++;
dc->duration.seconds = time;
@ -741,7 +740,6 @@ int parse_txt_file(const char *filename, const char *csv, struct divelog *log)
add_sample_data(sample, POSEIDON_SETPOINT, prev_setpoint);
if (!has_ndl && prev_ndl >= 0)
add_sample_data(sample, POSEIDON_NDL, prev_ndl);
finish_sample(dc);
if (!lineptr || !*lineptr)
break;

View file

@ -309,7 +309,7 @@ static dc_status_t parse_gasmixes(device_data_t *devdata, struct dive *dive, dc_
return DC_STATUS_SUCCESS;
}
static void handle_event(struct divecomputer *dc, struct sample *sample, dc_sample_value_t value)
static void handle_event(struct divecomputer *dc, const struct sample &sample, dc_sample_value_t value)
{
int type, time;
struct event *ev;
@ -360,20 +360,19 @@ static void handle_event(struct divecomputer *dc, struct sample *sample, dc_samp
#endif
time = value.event.time;
if (sample)
time += sample->time.seconds;
time += sample.time.seconds;
ev = add_event(dc, time, type, value.event.flags, value.event.value, name);
if (event_is_gaschange(ev) && ev->gas.index >= 0)
current_gas_index = ev->gas.index;
}
static void handle_gasmix(struct divecomputer *dc, struct sample *sample, int idx)
static void handle_gasmix(struct divecomputer *dc, const struct sample &sample, int idx)
{
/* 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");
add_event(dc, sample.time.seconds, SAMPLE_EVENT_GASCHANGE2, idx+1, 0, "gaschange");
current_gas_index = idx;
}
@ -381,30 +380,19 @@ void
sample_cb(dc_sample_type_t type, const dc_sample_value_t *pvalue, void *userdata)
{
static unsigned int nsensor = 0;
dc_sample_value_t value = *pvalue;
struct divecomputer *dc = (divecomputer *)userdata;
struct sample *sample;
dc_sample_value_t value = *pvalue;
/*
* We fill in the "previous" sample - except for DC_SAMPLE_TIME,
* which creates a new one.
* DC_SAMPLE_TIME is special: it creates a new sample.
* Other types fill in an existing sample.
*/
sample = dc->samples ? dc->sample + dc->samples - 1 : NULL;
/*
* Ok, sanity check.
* If first sample is not a DC_SAMPLE_TIME, Allocate a sample for us
*/
if (sample == NULL && type != DC_SAMPLE_TIME)
sample = prepare_sample(dc);
switch (type) {
case DC_SAMPLE_TIME:
if (type == DC_SAMPLE_TIME) {
nsensor = 0;
// Create a new sample.
// Mark depth as negative
sample = prepare_sample(dc);
struct sample *sample = prepare_sample(dc);
sample->time.seconds = value.time / 1000;
sample->depth.mm = -1;
// The current sample gets some sticky values
@ -418,40 +406,46 @@ sample_cb(dc_sample_type_t type, const dc_sample_value_t *pvalue, void *userdata
sample->cns = cns;
sample->heartbeat = heartbeat;
sample->bearing.degrees = bearing;
finish_sample(dc);
break;
return;
}
if (dc->samples.empty())
prepare_sample(dc);
struct sample &sample = dc->samples.back();
switch (type) {
case DC_SAMPLE_DEPTH:
sample->depth.mm = lrint(value.depth * 1000);
sample.depth.mm = lrint(value.depth * 1000);
break;
case DC_SAMPLE_PRESSURE:
add_sample_pressure(sample, value.pressure.tank, lrint(value.pressure.value * 1000));
add_sample_pressure(&sample, value.pressure.tank, lrint(value.pressure.value * 1000));
break;
case DC_SAMPLE_GASMIX:
handle_gasmix(dc, sample, value.gasmix);
break;
case DC_SAMPLE_TEMPERATURE:
sample->temperature.mkelvin = C_to_mkelvin(value.temperature);
sample.temperature.mkelvin = C_to_mkelvin(value.temperature);
break;
case DC_SAMPLE_EVENT:
handle_event(dc, sample, value);
break;
case DC_SAMPLE_RBT:
sample->rbt.seconds = (!strncasecmp(dc->model.c_str(), "suunto", 6)) ? value.rbt : value.rbt * 60;
sample.rbt.seconds = (!strncasecmp(dc->model.c_str(), "suunto", 6)) ? value.rbt : value.rbt * 60;
break;
#ifdef DC_SAMPLE_TTS
case DC_SAMPLE_TTS:
sample->tts.seconds = value.time;
sample.tts.seconds = value.time;
break;
#endif
case DC_SAMPLE_HEARTBEAT:
sample->heartbeat = heartbeat = value.heartbeat;
sample.heartbeat = heartbeat = value.heartbeat;
break;
case DC_SAMPLE_BEARING:
sample->bearing.degrees = bearing = value.bearing;
sample.bearing.degrees = bearing = value.bearing;
break;
#ifdef DEBUG_DC_VENDOR
case DC_SAMPLE_VENDOR:
printf(" <vendor time='%u:%02u' type=\"%u\" size=\"%u\">", FRACTION_TUPLE(sample->time.seconds, 60),
printf(" <vendor time='%u:%02u' type=\"%u\" size=\"%u\">", FRACTION_TUPLE(sample.time.seconds, 60),
value.vendor.type, value.vendor.size);
for (int i = 0; i < value.vendor.size; ++i)
printf("%02X", ((unsigned char *)value.vendor.data)[i]);
@ -460,11 +454,11 @@ sample_cb(dc_sample_type_t type, const dc_sample_value_t *pvalue, void *userdata
#endif
case DC_SAMPLE_SETPOINT:
/* for us a setpoint means constant pO2 from here */
sample->setpoint.mbar = po2 = lrint(value.setpoint * 1000);
sample.setpoint.mbar = po2 = lrint(value.setpoint * 1000);
break;
case DC_SAMPLE_PPO2:
if (nsensor < MAX_O2_SENSORS)
sample->o2sensor[nsensor].mbar = lrint(value.ppo2.value * 1000);
sample.o2sensor[nsensor].mbar = lrint(value.ppo2.value * 1000);
else
report_error("%d is more o2 sensors than we can handle", nsensor);
nsensor++;
@ -473,25 +467,25 @@ sample_cb(dc_sample_type_t type, const dc_sample_value_t *pvalue, void *userdata
dc->no_o2sensors = nsensor;
break;
case DC_SAMPLE_CNS:
sample->cns = cns = lrint(value.cns * 100);
sample.cns = cns = lrint(value.cns * 100);
break;
case DC_SAMPLE_DECO:
if (value.deco.type == DC_DECO_NDL) {
sample->ndl.seconds = ndl = value.deco.time;
sample->stopdepth.mm = stopdepth = lrint(value.deco.depth * 1000.0);
sample->in_deco = in_deco = false;
sample.ndl.seconds = ndl = value.deco.time;
sample.stopdepth.mm = stopdepth = lrint(value.deco.depth * 1000.0);
sample.in_deco = in_deco = false;
} else if (value.deco.type == DC_DECO_DECOSTOP ||
value.deco.type == DC_DECO_DEEPSTOP) {
sample->stopdepth.mm = stopdepth = lrint(value.deco.depth * 1000.0);
sample->stoptime.seconds = stoptime = value.deco.time;
sample->in_deco = in_deco = stopdepth > 0;
sample.stopdepth.mm = stopdepth = lrint(value.deco.depth * 1000.0);
sample.stoptime.seconds = stoptime = value.deco.time;
sample.in_deco = in_deco = stopdepth > 0;
ndl = 0;
} else if (value.deco.type == DC_DECO_SAFETYSTOP) {
sample->in_deco = in_deco = false;
sample->stopdepth.mm = stopdepth = lrint(value.deco.depth * 1000.0);
sample->stoptime.seconds = stoptime = value.deco.time;
sample.in_deco = in_deco = false;
sample.stopdepth.mm = stopdepth = lrint(value.deco.depth * 1000.0);
sample.stoptime.seconds = stoptime = value.deco.time;
}
sample->tts.seconds = value.deco.tts;
sample.tts.seconds = value.deco.tts;
default:
break;
}
@ -870,18 +864,18 @@ static int dive_cb(const unsigned char *data, unsigned int size,
}
/* Various libdivecomputer interface fixups */
if (dive->dc.airtemp.mkelvin == 0 && first_temp_is_air && dive->dc.samples) {
dive->dc.airtemp = dive->dc.sample[0].temperature;
dive->dc.sample[0].temperature.mkelvin = 0;
if (dive->dc.airtemp.mkelvin == 0 && first_temp_is_air && !dive->dc.samples.empty()) {
dive->dc.airtemp = dive->dc.samples[0].temperature;
dive->dc.samples[0].temperature.mkelvin = 0;
}
/* special case for bug in Tecdiving DiveComputer.eu
* often the first sample has a water temperature of 0C, followed by the correct
* temperature in the next sample */
if (dive->dc.model == "Tecdiving DiveComputer.eu" &&
dive->dc.sample[0].temperature.mkelvin == ZERO_C_IN_MKELVIN &&
dive->dc.sample[1].temperature.mkelvin > dive->dc.sample[0].temperature.mkelvin)
dive->dc.sample[0].temperature.mkelvin = dive->dc.sample[1].temperature.mkelvin;
if (dive->dc.model == "Tecdiving DiveComputer.eu" && !dive->dc.samples.empty() &&
dive->dc.samples[0].temperature.mkelvin == ZERO_C_IN_MKELVIN &&
dive->dc.samples[1].temperature.mkelvin > dive->dc.samples[0].temperature.mkelvin)
dive->dc.samples[0].temperature.mkelvin = dive->dc.samples[1].temperature.mkelvin;
record_dive_to_table(dive.release(), devdata->log->dives.get());
return true;

View file

@ -334,7 +334,6 @@ static void parse_dives(int log_version, const unsigned char *buf, unsigned int
sample->depth.mm = array_uint16_le(ds + (d - 1) * 2) * 10; // cm->mm
sample->temperature.mkelvin = C_to_mkelvin((float) array_uint16_le(ts + (d - 1) * 2) / 10); // dC->mK
add_sample_pressure(sample, event.pressure.sensor, event.pressure.mbar);
finish_sample(dc);
break;
} else if (event.time > sample_time) {
@ -342,7 +341,6 @@ static void parse_dives(int log_version, const unsigned char *buf, unsigned int
sample->time.seconds = sample_time;
sample->depth.mm = depth_mm;
sample->temperature.mkelvin = temp_mk;
finish_sample(dc);
d++;
continue;
@ -351,7 +349,6 @@ static void parse_dives(int log_version, const unsigned char *buf, unsigned int
sample->depth.mm = depth_mm;
sample->temperature.mkelvin = temp_mk;
add_sample_pressure(sample, event.pressure.sensor, event.pressure.mbar);
finish_sample(dc);
d++;
break;
@ -370,7 +367,6 @@ static void parse_dives(int log_version, const unsigned char *buf, unsigned int
sample->temperature.mkelvin = last_temp + (temp_mk - last_temp)
* ((int)event.time - (int)last_time) / sample_interval;
}
finish_sample(dc);
break;
}
@ -385,7 +381,6 @@ static void parse_dives(int log_version, const unsigned char *buf, unsigned int
sample->depth.mm = array_uint16_le(ds + d * 2) * 10; // cm->mm
sample->temperature.mkelvin =
C_to_mkelvin((float)array_uint16_le(ts + d * 2) / 10);
finish_sample(dc);
}
if (log_version == 3 && model == 4) {

View file

@ -679,8 +679,9 @@ static int sanitize_sensor_id(const struct dive *d, int nr)
static struct sample *new_sample(struct git_parser_state *state)
{
struct sample *sample = prepare_sample(state->active_dc);
if (sample != state->active_dc->sample) {
memcpy(sample, sample - 1, sizeof(struct sample));
size_t num_samples = state->active_dc->samples.size();
if (num_samples >= 2) {
*sample = state->active_dc->samples[num_samples - 2];
sample->pressure[0].mbar = 0;
sample->pressure[1].mbar = 0;
} else {
@ -721,7 +722,6 @@ static void sample_parser(char *line, struct git_parser_state *state)
line = parse_sample_unit(sample, val, line);
}
}
finish_sample(state->active_dc);
}
static void parse_dc_airtemp(char *line, struct git_parser_state *state)
@ -1649,7 +1649,7 @@ static struct divecomputer *create_new_dc(struct dive *dive)
while (dc->next)
dc = dc->next;
/* Did we already fill that in? */
if (dc->samples || !dc->model.empty() || dc->when) {
if (!dc->samples.empty() || !dc->model.empty() || dc->when) {
struct divecomputer *newdc = new divecomputer;
dc->next = newdc;
dc = newdc;

View file

@ -118,7 +118,7 @@ void event_end(struct parser_state *state)
bool is_dive(struct parser_state *state)
{
return state->cur_dive &&
(state->cur_dive->dive_site || state->cur_dive->when || state->cur_dive->dc.samples);
(state->cur_dive->dive_site || state->cur_dive->when || !state->cur_dive->dc.samples.empty());
}
void reset_dc_info(struct divecomputer *, struct parser_state *state)
@ -361,8 +361,8 @@ void sample_start(struct parser_state *state)
struct divecomputer *dc = get_dc(state);
struct sample *sample = prepare_sample(dc);
if (sample != dc->sample) {
memcpy(sample, sample-1, sizeof(struct sample));
if (dc->samples.size() > 1) {
*sample = dc->samples[dc->samples.size() - 2];
sample->pressure[0].mbar = 0;
sample->pressure[1].mbar = 0;
} else {
@ -378,7 +378,6 @@ void sample_end(struct parser_state *state)
if (!state->cur_dive)
return;
finish_sample(get_dc(state));
state->cur_sample = NULL;
}
@ -392,7 +391,7 @@ void divecomputer_start(struct parser_state *state)
dc = dc->next;
/* Did we already fill that in? */
if (dc->samples || !dc->model.empty() || dc->when) {
if (!dc->samples.empty() || !dc->model.empty() || dc->when) {
struct divecomputer *newdc = new divecomputer;
if (newdc) {
dc->next = newdc;

View file

@ -112,11 +112,8 @@ static void interpolate_transition(struct deco_state *ds, struct dive *dive, dur
/* returns the tissue tolerance at the end of this (partial) dive */
static int tissue_at_end(struct deco_state *ds, struct dive *dive, const struct divecomputer *dc, deco_state_cache &cache)
{
struct sample *sample, *psample;
int i;
depth_t lastdepth = {};
duration_t t0 = {}, t1 = {};
struct gasmix gas;
depth_t lastdepth;
duration_t t0;
int surface_interval = 0;
if (!dive)
@ -127,24 +124,20 @@ static int tissue_at_end(struct deco_state *ds, struct dive *dive, const struct
surface_interval = init_decompression(ds, dive, true);
cache.cache(ds);
}
if (!dc->samples)
if (dc->samples.empty())
return 0;
psample = sample = dc->sample;
const struct event *evdm = NULL;
enum divemode_t divemode = UNDEF_COMP_TYPE;
for (i = 0; i < dc->samples; i++, sample++) {
o2pressure_t setpoint;
const struct sample *psample = nullptr;
for (auto &sample: dc->samples) {
o2pressure_t setpoint = psample ? psample->setpoint
: sample.setpoint;
if (i)
setpoint = sample[-1].setpoint;
else
setpoint = sample[0].setpoint;
t1 = sample->time;
gas = get_gasmix_at_time(dive, dc, t0);
if (i > 0)
duration_t t1 = sample.time;
struct gasmix gas = get_gasmix_at_time(dive, dc, t0);
if (psample)
lastdepth = psample->depth;
/* The ceiling in the deeper portion of a multilevel dive is sometimes critical for the VPM-B
@ -156,7 +149,7 @@ static int tissue_at_end(struct deco_state *ds, struct dive *dive, const struct
* portion of the dive.
* Remember the value for later.
*/
if ((decoMode(true) == VPMB) && (lastdepth.mm > sample->depth.mm)) {
if ((decoMode(true) == VPMB) && (lastdepth.mm > sample.depth.mm)) {
pressure_t ceiling_pressure;
nuclear_regeneration(ds, t0.seconds);
vpmb_start_gradient(ds);
@ -171,8 +164,8 @@ static int tissue_at_end(struct deco_state *ds, struct dive *dive, const struct
}
divemode = get_current_divemode(&dive->dc, t0.seconds + 1, &evdm, &divemode);
interpolate_transition(ds, dive, t0, t1, lastdepth, sample->depth, gas, setpoint, divemode);
psample = sample;
interpolate_transition(ds, dive, t0, t1, lastdepth, sample.depth, gas, setpoint, divemode);
psample = &sample;
t0 = t1;
}
return surface_interval;
@ -208,7 +201,6 @@ static void update_cylinder_pressure(struct dive *d, int old_depth, int new_dept
static void create_dive_from_plan(struct diveplan *diveplan, struct dive *dive, struct divecomputer *dc, bool track_gas)
{
struct divedatapoint *dp;
struct sample *sample;
struct event *ev;
cylinder_t *cyl;
int oldpo2 = 0;
@ -230,7 +222,7 @@ static void create_dive_from_plan(struct diveplan *diveplan, struct dive *dive,
dc->when = dive->when = diveplan->when;
dc->surface_pressure.mbar = diveplan->surface_pressure;
dc->salinity = diveplan->salinity;
free_samples(dc);
dc->samples.clear();
while ((ev = dc->events)) {
dc->events = dc->events->next;
delete ev;
@ -240,12 +232,11 @@ static void create_dive_from_plan(struct diveplan *diveplan, struct dive *dive,
* 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 = get_or_create_cylinder(dive, 0);
sample = prepare_sample(dc);
struct sample *sample = prepare_sample(dc);
sample->sac.mliter = prefs.bottomsac;
if (track_gas && cyl->type.workingpressure.mbar)
sample->pressure[0].mbar = cyl->end.mbar;
sample->manually_entered = true;
finish_sample(dc);
lastcylid = 0;
while (dp) {
int po2 = dp->setpoint;
@ -286,7 +277,6 @@ static void create_dive_from_plan(struct diveplan *diveplan, struct dive *dive,
sample->depth = lastdepth;
sample->manually_entered = dp->entered;
sample->sac.mliter = dp->entered ? prefs.bottomsac : prefs.decosac;
finish_sample(dc);
lastcylid = dp->cylinderid;
}
if (dp->divemode != type) {
@ -311,7 +301,6 @@ static void create_dive_from_plan(struct diveplan *diveplan, struct dive *dive,
if (cyl->type.workingpressure.mbar)
sample->pressure[0].mbar = cyl->end.mbar;
}
finish_sample(dc);
dp = dp->next;
}
dc->last_manual_time.seconds = last_manual_point;
@ -660,7 +649,6 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
int bottom_time;
int previous_deco_time;
deco_state_cache bottom_cache;
struct sample *sample;
int po2;
int transitiontime, gi;
int current_cylinder, stop_cylinder;
@ -727,20 +715,20 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
*(decostoplevels + 1) = M_OR_FT(3,10);
/* Let's start at the last 'sample', i.e. the last manually entered waypoint. */
sample = &dc->sample[dc->samples - 1];
const struct sample &sample = dc->samples.back();
/* Keep time during the ascend */
bottom_time = clock = previous_point_time = dc->sample[dc->samples - 1].time.seconds;
bottom_time = clock = previous_point_time = sample.time.seconds;
current_cylinder = get_cylinderid_at_time(dive, dc, sample->time);
current_cylinder = get_cylinderid_at_time(dive, dc, sample.time);
// Find the divemode at the end of the dive
const struct event *ev = NULL;
divemode = UNDEF_COMP_TYPE;
divemode = get_current_divemode(dc, bottom_time, &ev, &divemode);
gas = get_cylinder(dive, current_cylinder)->gasmix;
po2 = sample->setpoint.mbar;
depth = dc->sample[dc->samples - 1].depth.mm;
po2 = sample.setpoint.mbar;
depth = sample.depth.mm;
average_max_depth(diveplan, &avg_depth, &max_depth);
last_ascend_rate = ascent_velocity(depth, avg_depth, bottom_time);

View file

@ -305,9 +305,7 @@ static void calculate_max_limits_new(const struct dive *dive, const struct divec
do {
if (dc == given_dc)
seen = true;
int i = dc->samples;
int lastdepth = 0;
struct sample *s = dc->sample;
struct event *ev;
/* Make sure we can fit all events */
@ -318,13 +316,13 @@ static void calculate_max_limits_new(const struct dive *dive, const struct divec
ev = ev->next;
}
while (--i >= 0) {
int depth = s->depth.mm;
int temperature = s->temperature.mkelvin;
int heartbeat = s->heartbeat;
for (auto &s: dc->samples) {
int depth = s.depth.mm;
int temperature = s.temperature.mkelvin;
int heartbeat = s.heartbeat;
for (int sensor = 0; sensor < MAX_SENSORS; ++sensor) {
int pressure = s->pressure[sensor].mbar;
int pressure = s.pressure[sensor].mbar;
if (pressure && pressure < minpressure)
minpressure = pressure;
if (pressure > maxpressure)
@ -342,17 +340,16 @@ static void calculate_max_limits_new(const struct dive *dive, const struct divec
minhr = heartbeat;
if (depth > maxdepth)
maxdepth = s->depth.mm;
maxdepth = s.depth.mm;
/* Make sure that we get the first sample beyond the last event.
* If maxtime is somewhere in the middle of the last segment,
* populate_plot_entries() gets confused leading to display artifacts. */
if ((depth > SURFACE_THRESHOLD || lastdepth > SURFACE_THRESHOLD || in_planner || !found_sample_beyond_last_event) &&
s->time.seconds > maxtime) {
s.time.seconds > maxtime) {
found_sample_beyond_last_event = true;
maxtime = s->time.seconds;
maxtime = s.time.seconds;
}
lastdepth = depth;
s++;
}
dc = dc->next;
@ -416,7 +413,7 @@ static void populate_plot_entries(const struct dive *dive, const struct divecomp
* that has time > maxtime (because there can be surface samples
* past "maxtime" in the original sample data)
*/
size_t nr = dc->samples + 6 + pi.maxtime / 10 + count_events(dc);
size_t nr = dc->samples.size() + 6 + pi.maxtime / 10 + count_events(dc);
pi.entry.reserve(nr);
pi.pressures.reserve(nr * pi.nr_cylinders);
@ -430,8 +427,7 @@ static void populate_plot_entries(const struct dive *dive, const struct divecomp
/* skip events at time = 0 */
while (ev && ev->time.seconds == 0)
ev = ev->next;
for (int i = 0; i < dc->samples; i++) {
const struct sample &sample = dc->sample[i];
for (const auto &sample: dc->samples) {
int time = sample.time.seconds;
int offset, delta;
int depth = sample.depth.mm;
@ -708,8 +704,9 @@ static void populate_secondary_sensor_data(const struct divecomputer *dc, struct
++seen[c]; // Count instances so we can differentiate a real sensor from just start and end pressure
int idx = 0;
/* We should try to see if it has interesting pressure data here */
for (int i = 0; i < dc->samples && idx < pi.nr; i++) {
const struct sample &sample = dc->sample[i];
for (const auto &sample: dc->samples) {
if (idx >= pi.nr)
break;
for (; idx < pi.nr; ++idx) {
if (idx == pi.nr - 1 || pi.entry[idx].sec >= sample.time.seconds)
// We've either found the entry at or just after the sample's time,

View file

@ -32,7 +32,79 @@ void move_in_range(Range &v, int rangeBegin, int rangeEnd, int destination)
std::rotate(it + destination, it + rangeBegin, it + rangeEnd);
}
// A rudimentary adaptor for looping over ranges with an index:
// Small helper base class for iterator adapters.
template <typename Base>
class iterator_adapter {
protected:
Base it;
public:
iterator_adapter(Base it) : it(it)
{
}
bool operator==(const iterator_adapter &it2) const {
return it == it2.it;
}
bool operator!=(const iterator_adapter &it2) const
{
return it != it2.it;
}
};
// A rudimentary adapter for looping over pairs of elements in ranges:
// for (auto [it1, it2]: pairwise_range(v)) ...
// The pairs are overlapping, i.e. there is one less pair than elements:
// { 1, 2, 3, 4 } -> (1,2), (2,3), (3,4)
template <typename Range>
class pairwise_range
{
Range &base;
public:
using base_iterator = decltype(std::begin(std::declval<Range &>()));
using item_type = decltype(*std::begin(base));
class iterator : public iterator_adapter<base_iterator> {
public:
using iterator_adapter<base_iterator>::iterator_adapter;
std::pair<item_type &, item_type &> operator*() const
{
return { *this->it, *std::next(this->it) };
}
iterator &operator++()
{
++this->it;
return *this;
}
iterator &operator--()
{
--this->it;
return *this;
}
iterator operator++(int)
{
return iterator(this->it++);
}
iterator operator--(int)
{
return iterator(this->it--);
}
};
iterator begin()
{
return iterator(std::begin(base));
}
iterator end()
{
return std::begin(base) == std::end(base) ?
iterator(std::begin(base)) :
iterator(std::prev(std::end(base)));
}
pairwise_range(Range &base): base(base)
{
}
};
// A rudimentary adapter for looping over ranges with an index:
// for (auto [idx, item]: enumerated_range(v)) ...
// The index is a signed integer, since this is what we use more often.
template <typename Range>
@ -41,30 +113,31 @@ class enumerated_range
Range &base;
public:
using base_iterator = decltype(std::begin(std::declval<Range &>()));
class iterator {
class iterator : public iterator_adapter<base_iterator>{
int idx;
base_iterator it;
public:
std::pair<int, decltype(*it)> operator*() const
using iterator_adapter<base_iterator>::iterator_adapter;
using item_type = decltype(*std::begin(base));
std::pair<int, item_type &> operator*() const
{
return { idx, *it };
return { idx, *this->it };
}
iterator &operator++()
{
++idx;
++it;
++this->it;
return *this;
}
iterator(int idx, base_iterator it) : idx(idx), it(it)
iterator &operator--()
{
--idx;
--this->it;
return *this;
}
bool operator==(const iterator &it2) const
iterator &operator++(int) = delete; // Postfix increment/decrement not supported for now
iterator &operator--(int) = delete; // Postfix increment/decrement not supported for now
iterator(int idx, base_iterator it) : iterator_adapter<base_iterator>(it), idx(idx)
{
return it == it2.it;
}
bool operator!=(const iterator &it2) const
{
return it != it2.it;
}
};
@ -82,6 +155,7 @@ public:
}
};
// Find the index of an element in a range. Return -1 if not found
// Range must have a random access iterator.
template <typename Range, typename Element>

View file

@ -245,17 +245,17 @@ static void show_index(struct membuffer *b, int value, const char *pre, const ch
*
* For parsing, look at the units to figure out what the numbers are.
*/
static void save_sample(struct membuffer *b, struct sample *sample, struct sample *old, int o2sensor)
static void save_sample(struct membuffer *b, const struct sample &sample, struct sample &old, int o2sensor)
{
int idx;
put_format(b, "%3u:%02u", FRACTION_TUPLE(sample->time.seconds, 60));
put_milli(b, " ", sample->depth.mm, "m");
put_temperature(b, sample->temperature, " ", "°C");
put_format(b, "%3u:%02u", FRACTION_TUPLE(sample.time.seconds, 60));
put_milli(b, " ", sample.depth.mm, "m");
put_temperature(b, sample.temperature, " ", "°C");
for (idx = 0; idx < MAX_SENSORS; idx++) {
pressure_t p = sample->pressure[idx];
int sensor = sample->sensor[idx];
pressure_t p = sample.pressure[idx];
int sensor = sample.sensor[idx];
if (sensor == NO_SENSOR)
continue;
@ -266,7 +266,7 @@ static void save_sample(struct membuffer *b, struct sample *sample, struct sampl
/* Old-style "o2sensor" syntax for CCR dives? */
if (o2sensor >= 0) {
if (sensor == o2sensor) {
put_pressure(b, sample->pressure[1]," o2pressure=","bar");
put_pressure(b, sample.pressure[1]," o2pressure=","bar");
continue;
}
@ -275,11 +275,11 @@ static void save_sample(struct membuffer *b, struct sample *sample, struct sampl
/*
* Note: regardless of which index we used for the non-O2
* sensor, we know there is only one non-O2 sensor in legacy
* mode, and "old->sensor[0]" contains that index.
* mode, and "old.sensor[0]" contains that index.
*/
if (sensor != old->sensor[0]) {
if (sensor != old.sensor[0]) {
put_format(b, " sensor=%d", sensor);
old->sensor[0] = sensor;
old.sensor[0] = sensor;
}
continue;
}
@ -290,88 +290,86 @@ static void save_sample(struct membuffer *b, struct sample *sample, struct sampl
}
/* the deco/ndl values are stored whenever they change */
if (sample->ndl.seconds != old->ndl.seconds) {
put_format(b, " ndl=%u:%02u", FRACTION_TUPLE(sample->ndl.seconds, 60));
old->ndl = sample->ndl;
if (sample.ndl.seconds != old.ndl.seconds) {
put_format(b, " ndl=%u:%02u", FRACTION_TUPLE(sample.ndl.seconds, 60));
old.ndl = sample.ndl;
}
if (sample->tts.seconds != old->tts.seconds) {
put_format(b, " tts=%u:%02u", FRACTION_TUPLE(sample->tts.seconds, 60));
old->tts = sample->tts;
if (sample.tts.seconds != old.tts.seconds) {
put_format(b, " tts=%u:%02u", FRACTION_TUPLE(sample.tts.seconds, 60));
old.tts = sample.tts;
}
if (sample->in_deco != old->in_deco) {
put_format(b, " in_deco=%d", sample->in_deco ? 1 : 0);
old->in_deco = sample->in_deco;
if (sample.in_deco != old.in_deco) {
put_format(b, " in_deco=%d", sample.in_deco ? 1 : 0);
old.in_deco = sample.in_deco;
}
if (sample->stoptime.seconds != old->stoptime.seconds) {
put_format(b, " stoptime=%u:%02u", FRACTION_TUPLE(sample->stoptime.seconds, 60));
old->stoptime = sample->stoptime;
if (sample.stoptime.seconds != old.stoptime.seconds) {
put_format(b, " stoptime=%u:%02u", FRACTION_TUPLE(sample.stoptime.seconds, 60));
old.stoptime = sample.stoptime;
}
if (sample->stopdepth.mm != old->stopdepth.mm) {
put_milli(b, " stopdepth=", sample->stopdepth.mm, "m");
old->stopdepth = sample->stopdepth;
if (sample.stopdepth.mm != old.stopdepth.mm) {
put_milli(b, " stopdepth=", sample.stopdepth.mm, "m");
old.stopdepth = sample.stopdepth;
}
if (sample->cns != old->cns) {
put_format(b, " cns=%u%%", sample->cns);
old->cns = sample->cns;
if (sample.cns != old.cns) {
put_format(b, " cns=%u%%", sample.cns);
old.cns = sample.cns;
}
if (sample->rbt.seconds != old->rbt.seconds) {
put_format(b, " rbt=%u:%02u", FRACTION_TUPLE(sample->rbt.seconds, 60));
old->rbt.seconds = sample->rbt.seconds;
if (sample.rbt.seconds != old.rbt.seconds) {
put_format(b, " rbt=%u:%02u", FRACTION_TUPLE(sample.rbt.seconds, 60));
old.rbt.seconds = sample.rbt.seconds;
}
if (sample->o2sensor[0].mbar != old->o2sensor[0].mbar) {
put_milli(b, " sensor1=", sample->o2sensor[0].mbar, "bar");
old->o2sensor[0] = sample->o2sensor[0];
if (sample.o2sensor[0].mbar != old.o2sensor[0].mbar) {
put_milli(b, " sensor1=", sample.o2sensor[0].mbar, "bar");
old.o2sensor[0] = sample.o2sensor[0];
}
if ((sample->o2sensor[1].mbar) && (sample->o2sensor[1].mbar != old->o2sensor[1].mbar)) {
put_milli(b, " sensor2=", sample->o2sensor[1].mbar, "bar");
old->o2sensor[1] = sample->o2sensor[1];
if ((sample.o2sensor[1].mbar) && (sample.o2sensor[1].mbar != old.o2sensor[1].mbar)) {
put_milli(b, " sensor2=", sample.o2sensor[1].mbar, "bar");
old.o2sensor[1] = sample.o2sensor[1];
}
if ((sample->o2sensor[2].mbar) && (sample->o2sensor[2].mbar != old->o2sensor[2].mbar)) {
put_milli(b, " sensor3=", sample->o2sensor[2].mbar, "bar");
old->o2sensor[2] = sample->o2sensor[2];
if ((sample.o2sensor[2].mbar) && (sample.o2sensor[2].mbar != old.o2sensor[2].mbar)) {
put_milli(b, " sensor3=", sample.o2sensor[2].mbar, "bar");
old.o2sensor[2] = sample.o2sensor[2];
}
if ((sample->o2sensor[3].mbar) && (sample->o2sensor[3].mbar != old->o2sensor[3].mbar)) {
put_milli(b, " sensor4=", sample->o2sensor[3].mbar, "bar");
old->o2sensor[3] = sample->o2sensor[3];
if ((sample.o2sensor[3].mbar) && (sample.o2sensor[3].mbar != old.o2sensor[3].mbar)) {
put_milli(b, " sensor4=", sample.o2sensor[3].mbar, "bar");
old.o2sensor[3] = sample.o2sensor[3];
}
if ((sample->o2sensor[4].mbar) && (sample->o2sensor[4].mbar != old->o2sensor[4].mbar)) {
put_milli(b, " sensor5=", sample->o2sensor[4].mbar, "bar");
old->o2sensor[4] = sample->o2sensor[4];
if ((sample.o2sensor[4].mbar) && (sample.o2sensor[4].mbar != old.o2sensor[4].mbar)) {
put_milli(b, " sensor5=", sample.o2sensor[4].mbar, "bar");
old.o2sensor[4] = sample.o2sensor[4];
}
if ((sample->o2sensor[5].mbar) && (sample->o2sensor[5].mbar != old->o2sensor[5].mbar)) {
put_milli(b, " sensor6=", sample->o2sensor[5].mbar, "bar");
old->o2sensor[5] = sample->o2sensor[5];
if ((sample.o2sensor[5].mbar) && (sample.o2sensor[5].mbar != old.o2sensor[5].mbar)) {
put_milli(b, " sensor6=", sample.o2sensor[5].mbar, "bar");
old.o2sensor[5] = sample.o2sensor[5];
}
if (sample->setpoint.mbar != old->setpoint.mbar) {
put_milli(b, " po2=", sample->setpoint.mbar, "bar");
old->setpoint = sample->setpoint;
if (sample.setpoint.mbar != old.setpoint.mbar) {
put_milli(b, " po2=", sample.setpoint.mbar, "bar");
old.setpoint = sample.setpoint;
}
if (sample->heartbeat != old->heartbeat) {
show_index(b, sample->heartbeat, "heartbeat=", "");
old->heartbeat = sample->heartbeat;
if (sample.heartbeat != old.heartbeat) {
show_index(b, sample.heartbeat, "heartbeat=", "");
old.heartbeat = sample.heartbeat;
}
if (sample->bearing.degrees != old->bearing.degrees) {
show_index(b, sample->bearing.degrees, "bearing=", "°");
old->bearing.degrees = sample->bearing.degrees;
if (sample.bearing.degrees != old.bearing.degrees) {
show_index(b, sample.bearing.degrees, "bearing=", "°");
old.bearing.degrees = sample.bearing.degrees;
}
put_format(b, "\n");
}
static void save_samples(struct membuffer *b, struct dive *dive, struct divecomputer *dc)
{
int nr;
int o2sensor;
struct sample *s;
struct sample dummy;
/* Is this a CCR dive with the old-style "o2pressure" sensor? */
@ -381,12 +379,8 @@ static void save_samples(struct membuffer *b, struct dive *dive, struct divecomp
dummy.sensor[1] = o2sensor;
}
s = dc->sample;
nr = dc->samples;
while (--nr >= 0) {
save_sample(b, s, &dummy, o2sensor);
s++;
}
for (const auto &s: dc->samples)
save_sample(b, s, dummy, o2sensor);
}
static void save_one_event(struct membuffer *b, struct dive *dive, struct event *ev)

View file

@ -178,19 +178,16 @@ static void put_cylinder_HTML(struct membuffer *b, struct dive *dive)
static void put_HTML_samples(struct membuffer *b, struct dive *dive)
{
int i;
put_format(b, "\"maxdepth\":%d,", dive->dc.maxdepth.mm);
put_format(b, "\"duration\":%d,", dive->dc.duration.seconds);
struct sample *s = dive->dc.sample;
if (!dive->dc.samples)
if (dive->dc.samples.empty())
return;
const char *separator = "\"samples\":[";
for (i = 0; i < dive->dc.samples; i++) {
put_format(b, "%s[%d,%d,%d,%d]", separator, s->time.seconds, s->depth.mm, s->pressure[0].mbar, s->temperature.mkelvin);
for (auto &s: dive->dc.samples) {
put_format(b, "%s[%d,%d,%d,%d]", separator, s.time.seconds, s.depth.mm, s.pressure[0].mbar, s.temperature.mkelvin);
separator = ", ";
s++;
}
put_string(b, "],");
}

View file

@ -232,15 +232,15 @@ static void show_index(struct membuffer *b, int value, const char *pre, const ch
show_integer(b, value, pre, post);
}
static void save_sample(struct membuffer *b, struct sample *sample, struct sample *old, int o2sensor)
static void save_sample(struct membuffer *b, const struct sample &sample, struct sample &old, int o2sensor)
{
int idx;
put_format(b, " <sample time='%u:%02u min'", FRACTION_TUPLE(sample->time.seconds, 60));
put_milli(b, " depth='", sample->depth.mm, " m'");
if (sample->temperature.mkelvin && sample->temperature.mkelvin != old->temperature.mkelvin) {
put_temperature(b, sample->temperature, " temp='", " C'");
old->temperature = sample->temperature;
put_format(b, " <sample time='%u:%02u min'", FRACTION_TUPLE(sample.time.seconds, 60));
put_milli(b, " depth='", sample.depth.mm, " m'");
if (sample.temperature.mkelvin && sample.temperature.mkelvin != old.temperature.mkelvin) {
put_temperature(b, sample.temperature, " temp='", " C'");
old.temperature = sample.temperature;
}
/*
@ -248,8 +248,8 @@ static void save_sample(struct membuffer *b, struct sample *sample, struct sampl
* changed from the previous sensor we showed.
*/
for (idx = 0; idx < MAX_SENSORS; idx++) {
pressure_t p = sample->pressure[idx];
int sensor = sample->sensor[idx];
pressure_t p = sample.pressure[idx];
int sensor = sample.sensor[idx];
if (sensor == NO_SENSOR)
continue;
@ -264,9 +264,9 @@ static void save_sample(struct membuffer *b, struct sample *sample, struct sampl
continue;
}
put_pressure(b, p, " pressure='", " bar'");
if (sensor != old->sensor[0]) {
if (sensor != old.sensor[0]) {
put_format(b, " sensor='%d'", sensor);
old->sensor[0] = sensor;
old.sensor[0] = sensor;
}
continue;
}
@ -277,78 +277,78 @@ static void save_sample(struct membuffer *b, struct sample *sample, struct sampl
}
/* the deco/ndl values are stored whenever they change */
if (sample->ndl.seconds != old->ndl.seconds) {
put_format(b, " ndl='%u:%02u min'", FRACTION_TUPLE(sample->ndl.seconds, 60));
old->ndl = sample->ndl;
if (sample.ndl.seconds != old.ndl.seconds) {
put_format(b, " ndl='%u:%02u min'", FRACTION_TUPLE(sample.ndl.seconds, 60));
old.ndl = sample.ndl;
}
if (sample->tts.seconds != old->tts.seconds) {
put_format(b, " tts='%u:%02u min'", FRACTION_TUPLE(sample->tts.seconds, 60));
old->tts = sample->tts;
if (sample.tts.seconds != old.tts.seconds) {
put_format(b, " tts='%u:%02u min'", FRACTION_TUPLE(sample.tts.seconds, 60));
old.tts = sample.tts;
}
if (sample->rbt.seconds != old->rbt.seconds) {
put_format(b, " rbt='%u:%02u min'", FRACTION_TUPLE(sample->rbt.seconds, 60));
old->rbt = sample->rbt;
if (sample.rbt.seconds != old.rbt.seconds) {
put_format(b, " rbt='%u:%02u min'", FRACTION_TUPLE(sample.rbt.seconds, 60));
old.rbt = sample.rbt;
}
if (sample->in_deco != old->in_deco) {
put_format(b, " in_deco='%d'", sample->in_deco ? 1 : 0);
old->in_deco = sample->in_deco;
if (sample.in_deco != old.in_deco) {
put_format(b, " in_deco='%d'", sample.in_deco ? 1 : 0);
old.in_deco = sample.in_deco;
}
if (sample->stoptime.seconds != old->stoptime.seconds) {
put_format(b, " stoptime='%u:%02u min'", FRACTION_TUPLE(sample->stoptime.seconds, 60));
old->stoptime = sample->stoptime;
if (sample.stoptime.seconds != old.stoptime.seconds) {
put_format(b, " stoptime='%u:%02u min'", FRACTION_TUPLE(sample.stoptime.seconds, 60));
old.stoptime = sample.stoptime;
}
if (sample->stopdepth.mm != old->stopdepth.mm) {
put_milli(b, " stopdepth='", sample->stopdepth.mm, " m'");
old->stopdepth = sample->stopdepth;
if (sample.stopdepth.mm != old.stopdepth.mm) {
put_milli(b, " stopdepth='", sample.stopdepth.mm, " m'");
old.stopdepth = sample.stopdepth;
}
if (sample->cns != old->cns) {
put_format(b, " cns='%u%%'", sample->cns);
old->cns = sample->cns;
if (sample.cns != old.cns) {
put_format(b, " cns='%u%%'", sample.cns);
old.cns = sample.cns;
}
if ((sample->o2sensor[0].mbar) && (sample->o2sensor[0].mbar != old->o2sensor[0].mbar)) {
put_milli(b, " sensor1='", sample->o2sensor[0].mbar, " bar'");
old->o2sensor[0] = sample->o2sensor[0];
if ((sample.o2sensor[0].mbar) && (sample.o2sensor[0].mbar != old.o2sensor[0].mbar)) {
put_milli(b, " sensor1='", sample.o2sensor[0].mbar, " bar'");
old.o2sensor[0] = sample.o2sensor[0];
}
if ((sample->o2sensor[1].mbar) && (sample->o2sensor[1].mbar != old->o2sensor[1].mbar)) {
put_milli(b, " sensor2='", sample->o2sensor[1].mbar, " bar'");
old->o2sensor[1] = sample->o2sensor[1];
if ((sample.o2sensor[1].mbar) && (sample.o2sensor[1].mbar != old.o2sensor[1].mbar)) {
put_milli(b, " sensor2='", sample.o2sensor[1].mbar, " bar'");
old.o2sensor[1] = sample.o2sensor[1];
}
if ((sample->o2sensor[2].mbar) && (sample->o2sensor[2].mbar != old->o2sensor[2].mbar)) {
put_milli(b, " sensor3='", sample->o2sensor[2].mbar, " bar'");
old->o2sensor[2] = sample->o2sensor[2];
if ((sample.o2sensor[2].mbar) && (sample.o2sensor[2].mbar != old.o2sensor[2].mbar)) {
put_milli(b, " sensor3='", sample.o2sensor[2].mbar, " bar'");
old.o2sensor[2] = sample.o2sensor[2];
}
if ((sample->o2sensor[3].mbar) && (sample->o2sensor[3].mbar != old->o2sensor[3].mbar)) {
put_milli(b, " sensor4='", sample->o2sensor[3].mbar, " bar'");
old->o2sensor[3] = sample->o2sensor[3];
if ((sample.o2sensor[3].mbar) && (sample.o2sensor[3].mbar != old.o2sensor[3].mbar)) {
put_milli(b, " sensor4='", sample.o2sensor[3].mbar, " bar'");
old.o2sensor[3] = sample.o2sensor[3];
}
if ((sample->o2sensor[4].mbar) && (sample->o2sensor[4].mbar != old->o2sensor[4].mbar)) {
put_milli(b, " sensor5='", sample->o2sensor[4].mbar, " bar'");
old->o2sensor[4] = sample->o2sensor[4];
if ((sample.o2sensor[4].mbar) && (sample.o2sensor[4].mbar != old.o2sensor[4].mbar)) {
put_milli(b, " sensor5='", sample.o2sensor[4].mbar, " bar'");
old.o2sensor[4] = sample.o2sensor[4];
}
if ((sample->o2sensor[5].mbar) && (sample->o2sensor[5].mbar != old->o2sensor[5].mbar)) {
put_milli(b, " sensor6='", sample->o2sensor[5].mbar, " bar'");
old->o2sensor[5] = sample->o2sensor[5];
if ((sample.o2sensor[5].mbar) && (sample.o2sensor[5].mbar != old.o2sensor[5].mbar)) {
put_milli(b, " sensor6='", sample.o2sensor[5].mbar, " bar'");
old.o2sensor[5] = sample.o2sensor[5];
}
if (sample->setpoint.mbar != old->setpoint.mbar) {
put_milli(b, " po2='", sample->setpoint.mbar, " bar'");
old->setpoint = sample->setpoint;
if (sample.setpoint.mbar != old.setpoint.mbar) {
put_milli(b, " po2='", sample.setpoint.mbar, " bar'");
old.setpoint = sample.setpoint;
}
if (sample->heartbeat != old->heartbeat) {
show_index(b, sample->heartbeat, "heartbeat='", "'");
old->heartbeat = sample->heartbeat;
if (sample.heartbeat != old.heartbeat) {
show_index(b, sample.heartbeat, "heartbeat='", "'");
old.heartbeat = sample.heartbeat;
}
if (sample->bearing.degrees != old->bearing.degrees) {
show_index(b, sample->bearing.degrees, "bearing='", "'");
old->bearing.degrees = sample->bearing.degrees;
if (sample.bearing.degrees != old.bearing.degrees) {
show_index(b, sample.bearing.degrees, "bearing='", "'");
old.bearing.degrees = sample.bearing.degrees;
}
put_format(b, " />\n");
}
@ -423,9 +423,7 @@ static void show_date(struct membuffer *b, timestamp_t when)
static void save_samples(struct membuffer *b, struct dive *dive, struct divecomputer *dc)
{
int nr;
int o2sensor;
struct sample *s;
struct sample dummy;
/* Set up default pressure sensor indices */
@ -435,12 +433,8 @@ static void save_samples(struct membuffer *b, struct dive *dive, struct divecomp
dummy.sensor[1] = o2sensor;
}
s = dc->sample;
nr = dc->samples;
while (--nr >= 0) {
save_sample(b, s, &dummy, o2sensor);
s++;
}
for (const auto &s: dc->samples)
save_sample(b, s, dummy, o2sensor);
}
static void save_dc(struct membuffer *b, struct dive *dive, struct divecomputer *dc)

View file

@ -262,8 +262,8 @@ bool has_gaschange_event(const struct dive *dive, const struct divecomputer *dc,
bool first_gas_explicit = false;
const struct event *event = get_next_event(dc->events, "gaschange");
while (event) {
if (dc->sample && (event->time.seconds == 0 ||
(dc->samples && dc->sample[0].time.seconds == event->time.seconds)))
if (!dc->samples.empty() && (event->time.seconds == 0 ||
(dc->samples[0].time.seconds == event->time.seconds)))
first_gas_explicit = true;
if (get_cylinder_index(dive, event) == idx)
return true;

View file

@ -349,7 +349,6 @@ void uemis::parse_divelog_binary(std::string_view base64, struct dive *dive)
add_sample_pressure(sample, active, (u_sample->tank_pressure_high * 256 + u_sample->tank_pressure_low) * 10);
sample->cns = u_sample->cns;
event(dive, dc, sample, u_sample);
finish_sample(dc);
i += 0x25;
u_sample++;
}

View file

@ -298,8 +298,7 @@ QWidget *SensorDelegate::createEditor(QWidget *parent, const QStyleOptionViewIte
return comboBox;
std::vector<int16_t> sensors;
for (int i = 0; i < currentdc->samples; ++i) {
auto &sample = currentdc->sample[i];
for (const auto &sample: currentdc->samples) {
for (int s = 0; s < MAX_SENSORS; ++s) {
if (sample.pressure[s].mbar) {
if (std::find(sensors.begin(), sensors.end(), sample.sensor[s]) == sensors.end())

View file

@ -218,7 +218,7 @@ void ProfileWidget::plotDive(dive *dIn, int dcIn)
if (d && !editedDive &&
DivePlannerPointsModel::instance()->currentMode() == DivePlannerPointsModel::NOTHING) {
struct divecomputer *comp = get_dive_dc(d, dc);
if (comp && is_dc_manually_added_dive(comp) && comp->samples && comp->samples <= 50)
if (comp && is_dc_manually_added_dive(comp) && !comp->samples.empty() && comp->samples.size() <= 50)
editDive();
}

View file

@ -38,6 +38,7 @@
#include "core/subsurface-string.h"
#include "core/string-format.h"
#include "core/pref.h"
#include "core/sample.h"
#include "core/selection.h"
#include "core/save-profiledata.h"
#include "core/settings/qPrefLog.h"
@ -1135,7 +1136,7 @@ bool QMLManager::checkDuration(struct dive *d, QString duration)
}
d->dc.duration.seconds = d->duration.seconds = h * 3600 + m * 60 + s;
if (is_dc_manually_added_dive(&d->dc))
free_samples(&d->dc);
d->dc.samples.clear();
else
appendTextToLog("Cannot change the duration on a dive that wasn't manually added");
return true;
@ -1154,7 +1155,7 @@ bool QMLManager::checkDepth(dive *d, QString depth)
d->maxdepth.mm = depthValue;
if (is_dc_manually_added_dive(&d->dc)) {
d->dc.maxdepth.mm = d->maxdepth.mm;
free_samples(&d->dc);
d->dc.samples.clear();
}
return true;
}
@ -1358,7 +1359,7 @@ void QMLManager::commitChanges(QString diveId, QString number, QString date, QSt
if (d->maxdepth.mm == d->dc.maxdepth.mm &&
d->maxdepth.mm > 0 &&
is_dc_manually_added_dive(&d->dc) &&
d->dc.samples == 0) {
d->dc.samples.empty()) {
// so we have depth > 0, a manually added dive and no samples
// let's create an actual profile so the desktop version can work it
// first clear out the mean depth (or the fake_dc() function tries

View file

@ -201,10 +201,9 @@ bool DiveEventItem::isInteresting(const struct dive *d, const struct divecompute
* Some gas change events are special. Some dive computers just tell us the initial gas this way.
* Don't bother showing those
*/
const struct sample *first_sample = &dc->sample[0];
if (ev->name == "gaschange" &&
(ev->time.seconds == 0 ||
(first_sample && ev->time.seconds == first_sample->time.seconds) ||
(!dc->samples.empty() && ev->time.seconds == dc->samples[0].time.seconds) ||
depthAtTime(pi, ev->time) < SURFACE_THRESHOLD))
return false;

View file

@ -428,7 +428,7 @@ void ProfileScene::plotDive(const struct dive *dIn, int dcIn, DivePlannerPointsM
}
const struct divecomputer *currentdc = get_dive_dc_const(d, dc);
if (!currentdc || !currentdc->samples) {
if (!currentdc || currentdc->samples.empty()) {
clear();
return;
}

View file

@ -242,8 +242,7 @@ QVariant CylindersModel::data(const QModelIndex &index, int role) const
case SENSORS: {
std::vector<int16_t> sensors;
const struct divecomputer *currentdc = get_dive_dc(d, dcNr);
for (int i = 0; i < currentdc->samples; ++i) {
auto &sample = currentdc->sample[i];
for (const auto &sample: currentdc->samples) {
for (int s = 0; s < MAX_SENSORS; ++s) {
if (sample.pressure[s].mbar) {
if (sample.sensor[s] == index.row())

View file

@ -138,14 +138,14 @@ void DivePlannerPointsModel::loadFromDive(dive *dIn, int dcNrIn)
bool hasMarkedSamples = false;
if (dc->samples)
hasMarkedSamples = dc->sample[0].manually_entered;
if (!dc->samples.empty())
hasMarkedSamples = dc->samples[0].manually_entered;
else
fake_dc(dc);
// if this dive has more than 100 samples (so it is probably a logged dive),
// average samples so we end up with a total of 100 samples.
int plansamples = dc->samples <= 100 ? dc->samples : 100;
int plansamples = std::min(static_cast<int>(dc->samples.size()), 100);
int j = 0;
int cylinderid = 0;
@ -153,12 +153,12 @@ void DivePlannerPointsModel::loadFromDive(dive *dIn, int dcNrIn)
for (int i = 0; i < plansamples - 1; i++) {
if (dc->last_manual_time.seconds && dc->last_manual_time.seconds > 120 && lasttime.seconds >= dc->last_manual_time.seconds)
break;
while (j * plansamples <= i * dc->samples) {
const sample &s = dc->sample[j];
while (j * plansamples <= i * static_cast<int>(dc->samples.size())) {
const sample &s = dc->samples[j];
if (s.time.seconds != 0 && (!hasMarkedSamples || s.manually_entered)) {
depthsum += s.depth.mm;
if (j > 0)
last_sp = dc->sample[j-1].setpoint;
last_sp = dc->samples[j-1].setpoint;
++samplecount;
newtime = s.time;
}