mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-27 20:58:47 +00:00
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:
parent
bc761344d4
commit
f120fecccb
28 changed files with 588 additions and 715 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
434
core/dive.cpp
434
core/dive.cpp
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, ¤t_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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
100
core/range.h
100
core/range.h
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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, "],");
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue