diff options
-rw-r--r-- | core/dive.c | 137 | ||||
-rw-r--r-- | core/dive.h | 6 | ||||
-rw-r--r-- | core/planner.c | 7 | ||||
-rw-r--r-- | core/profile.c | 37 | ||||
-rw-r--r-- | core/save-git.c | 2 | ||||
-rw-r--r-- | core/save-xml.c | 2 | ||||
-rw-r--r-- | desktop-widgets/maintab.cpp | 4 |
7 files changed, 112 insertions, 83 deletions
diff --git a/core/dive.c b/core/dive.c index 6d4f8603c..915a04fe5 100644 --- a/core/dive.c +++ b/core/dive.c @@ -40,28 +40,6 @@ int event_is_gaschange(struct event *ev) ev->type == SAMPLE_EVENT_GASCHANGE2; } -/* - * Does the gas mix data match the legacy - * libdivecomputer event format? If so, - * we can skip saving it, in order to maintain - * the old save formats. We'll re-generate the - * gas mix when loading. - */ -int event_gasmix_redundant(struct event *ev) -{ - struct gasmix *mix = &ev->gas.mix; - int value = ev->value; - int o2, he; - - if (value == 21) - return gasmix_is_air(mix); - - o2 = (value & 0xffff) * 10; - he = (value >> 16) * 10; - return o2 == get_o2(mix) && - he == get_he(mix); -} - struct event *add_event(struct divecomputer *dc, unsigned int time, int type, int flags, int value, const char *name) { int gas_index = -1; @@ -178,7 +156,7 @@ void add_extra_data(struct divecomputer *dc, const char *key, const char *value) } /* this returns a pointer to static variable - so use it right away after calling */ -struct gasmix *get_gasmix_from_event(struct event *ev) +struct gasmix *get_gasmix_from_event(struct dive *dive, struct event *ev) { static struct gasmix dummy; if (ev && event_is_gaschange(ev)) @@ -849,7 +827,7 @@ int explicit_first_cylinder(struct dive *dive, struct divecomputer *dc) /* this gets called when the dive mode has changed (so OC vs. CC) * there are two places we might have setpoints... events or in the samples */ -void update_setpoint_events(struct divecomputer *dc) +void update_setpoint_events(struct dive *dive, struct divecomputer *dc) { struct event *ev; int new_setpoint = 0; @@ -867,14 +845,14 @@ void update_setpoint_events(struct divecomputer *dc) // So we make sure, this comes from a Predator or Petrel and we only remove // pO2 values we would have computed anyway. struct event *ev = get_next_event(dc->events, "gaschange"); - struct gasmix *gasmix = get_gasmix_from_event(ev); + struct gasmix *gasmix = get_gasmix_from_event(dive, ev); struct event *next = get_next_event(ev, "gaschange"); for (int i = 0; i < dc->samples; i++) { struct gas_pressures pressures; if (next && dc->sample[i].time.seconds >= next->time.seconds) { ev = next; - gasmix = get_gasmix_from_event(ev); + gasmix = get_gasmix_from_event(dive, ev); next = get_next_event(ev, "gaschange"); } fill_pressures(&pressures, calculate_depth_to_mbar(dc->sample[i].depth.mm, dc->surface_pressure, 0), gasmix ,0, OC); @@ -1401,6 +1379,92 @@ static void fixup_dive_pressures(struct dive *dive, struct divecomputer *dc) simplify_dc_pressures(dive, dc); } +int find_best_gasmix_match(struct gasmix *mix, cylinder_t array[], unsigned int used) +{ + int i; + int best = -1, score = INT_MAX; + + for (i = 0; i < MAX_CYLINDERS; i++) { + const cylinder_t *match; + int distance; + + if (used & (1 << i)) + continue; + match = array + i; + if (cylinder_nodata(match)) + continue; + distance = gasmix_distance(mix, &match->gasmix); + if (distance >= score) + continue; + best = i; + score = distance; + } + return best; +} + +/* + * Match a gas change event against the cylinders we have + */ +static bool validate_gaschange(struct dive *dive, struct divecomputer *dc, struct event *event) +{ + int index; + int o2, he, value; + + /* We'll get rid of the per-event gasmix, but for now sanitize it */ + if (gasmix_is_air(&event->gas.mix)) + event->gas.mix.o2.permille = 0; + + /* Do we already have a cylinder index for this gasmix? */ + if (event->gas.index >= 0) + return true; + + index = find_best_gasmix_match(&event->gas.mix, dive->cylinder, 0); + if (index < 0) + return false; + + /* Fix up the event to have the right information */ + event->gas.index = index; + event->gas.mix = dive->cylinder[index].gasmix; + + /* Convert to odd libdivecomputer format */ + o2 = get_o2(&event->gas.mix); + he = get_he(&event->gas.mix); + + o2 = (o2 + 5) / 10; + he = (he + 5) / 10; + value = o2 + (he << 16); + + event->value = value; + if (he) + event->type = SAMPLE_EVENT_GASCHANGE2; + + return true; +} + +/* Clean up event, return true if event is ok, false if it should be dropped as bogus */ +static bool validate_event(struct dive *dive, struct divecomputer *dc, struct event *event) +{ + if (event_is_gaschange(event)) + return validate_gaschange(dive, dc, event); + return true; +} + +static void fixup_dc_gasswitch(struct dive *dive, struct divecomputer *dc) +{ + struct event **evp, *event; + + evp = &dc->events; + while ((event = *evp) != NULL) { + if (validate_event(dive, dc, event)) { + evp = &event->next; + continue; + } + + /* Delete this event and try the next one */ + *evp = event->next; + } +} + static void fixup_dive_dc(struct dive *dive, struct divecomputer *dc) { int i; @@ -1418,6 +1482,9 @@ static void fixup_dive_dc(struct dive *dive, struct divecomputer *dc) /* Fix up dive temperatures based on dive computer samples */ fixup_dc_temp(dive, dc); + /* Fix up gas switch events */ + fixup_dc_gasswitch(dive, dc); + /* Fix up cylinder sensor data */ fixup_dc_cylinder_index(dive, dc); @@ -1804,25 +1871,9 @@ extern void fill_pressures(struct gas_pressures *pressures, const double amb_pre static int find_cylinder_match(cylinder_t *cyl, cylinder_t array[], unsigned int used) { - int i; - int best = -1, score = INT_MAX; - if (cylinder_nodata(cyl)) return -1; - for (i = 0; i < MAX_CYLINDERS; i++) { - const cylinder_t *match; - int distance; - - if (used & (1 << i)) - continue; - match = array + i; - distance = gasmix_distance(&cyl->gasmix, &match->gasmix); - if (distance >= score) - continue; - best = i; - score = distance; - } - return best; + return find_best_gasmix_match(&cyl->gasmix, array, used); } /* Force an initial gaschange event to the (old) gas #0 */ diff --git a/core/dive.h b/core/dive.h index e9dd4fb59..be721348c 100644 --- a/core/dive.h +++ b/core/dive.h @@ -115,7 +115,6 @@ struct event { }; extern int event_is_gaschange(struct event *ev); -extern int event_gasmix_redundant(struct event *ev); extern int get_pressure_units(int mb, const char **units); extern double get_depth_units(int mm, int *frac, const char **units); @@ -150,7 +149,7 @@ extern void fill_pressures(struct gas_pressures *pressures, const double amb_pre extern void sanitize_gasmix(struct gasmix *mix); extern int gasmix_distance(const struct gasmix *a, const struct gasmix *b); -extern struct gasmix *get_gasmix_from_event(struct event *ev); +extern int find_best_gasmix_match(struct gasmix *mix, cylinder_t array[], unsigned int used); static inline bool gasmix_is_air(const struct gasmix *gasmix) { @@ -757,6 +756,7 @@ extern void update_event_name(struct dive *d, struct event* event, char *name); extern void add_extra_data(struct divecomputer *dc, const char *key, const char *value); extern void per_cylinder_mean_depth(struct dive *dive, struct divecomputer *dc, int *mean, int *duration); extern int get_cylinder_index(struct dive *dive, struct event *ev); +extern struct gasmix *get_gasmix_from_event(struct dive *, struct event *ev); extern int nr_cylinders(struct dive *dive); extern int nr_weightsystems(struct dive *dive); @@ -896,7 +896,7 @@ extern void set_userid(char *user_id); extern void set_informational_units(char *units); extern const char *get_dive_date_c_string(timestamp_t when); -extern void update_setpoint_events(struct divecomputer *dc); +extern void update_setpoint_events(struct dive *dive, struct divecomputer *dc); #ifdef __cplusplus } #endif diff --git a/core/planner.c b/core/planner.c index 705aad1cb..a58c698ab 100644 --- a/core/planner.c +++ b/core/planner.c @@ -94,12 +94,7 @@ void get_gas_at_time(struct dive *dive, struct divecomputer *dc, duration_t time int get_gasidx(struct dive *dive, struct gasmix *mix) { - int gasidx = -1; - - while (++gasidx < MAX_CYLINDERS) - if (gasmix_distance(&dive->cylinder[gasidx].gasmix, mix) < 100) - return gasidx; - return -1; + return find_best_gasmix_match(mix, dive->cylinder, 0); } void interpolate_transition(struct dive *dive, duration_t t0, duration_t t1, depth_t d0, depth_t d1, const struct gasmix *gasmix, o2pressure_t po2) diff --git a/core/profile.c b/core/profile.c index 6576f6453..72c5e0298 100644 --- a/core/profile.c +++ b/core/profile.c @@ -318,40 +318,23 @@ struct plot_info *analyze_plot_info(struct plot_info *pi) */ int get_cylinder_index(struct dive *dive, struct event *ev) { - int i; - int best = 0, score = INT_MAX; - int target_o2, target_he; - struct gasmix *g; + int best; + struct gasmix *mix; if (ev->gas.index >= 0) return ev->gas.index; - g = get_gasmix_from_event(ev); - target_o2 = get_o2(g); - target_he = get_he(g); - /* - * Try to find a cylinder that best matches the target gas - * mix. + * This should no longer happen! + * + * We now match up gas change events with their cylinders at dive + * event fixup time. */ - for (i = 0; i < MAX_CYLINDERS; i++) { - cylinder_t *cyl = dive->cylinder + i; - int delta_o2, delta_he, distance; + fprintf(stderr, "Still looking up cylinder based on gas mix in get_cylinder_index()!\n"); - if (cylinder_nodata(cyl)) - continue; - - delta_o2 = get_o2(&cyl->gasmix) - target_o2; - delta_he = get_he(&cyl->gasmix) - target_he; - distance = delta_o2 * delta_o2; - distance += delta_he * delta_he; - - if (distance >= score) - continue; - score = distance; - best = i; - } - return best; + mix = get_gasmix_from_event(dive, ev); + best = find_best_gasmix_match(mix, dive->cylinder, 0); + return best < 0 ? 0 : best; } struct event *get_next_event(struct event *event, const char *name) diff --git a/core/save-git.c b/core/save-git.c index e22019ab0..ed91debf4 100644 --- a/core/save-git.c +++ b/core/save-git.c @@ -325,7 +325,7 @@ static void save_one_event(struct membuffer *b, struct event *ev) if (ev->gas.index >= 0) { show_index(b, ev->gas.index, "cylinder=", ""); put_gasmix(b, &ev->gas.mix); - } else if (!event_gasmix_redundant(ev)) + } else put_gasmix(b, &ev->gas.mix); } put_string(b, "\n"); diff --git a/core/save-xml.c b/core/save-xml.c index 2335637e8..045e47c55 100644 --- a/core/save-xml.c +++ b/core/save-xml.c @@ -269,7 +269,7 @@ static void save_one_event(struct membuffer *b, struct event *ev) if (ev->gas.index >= 0) { show_index(b, ev->gas.index, "cylinder='", "'"); put_gasmix(b, &ev->gas.mix); - } else if (!event_gasmix_redundant(ev)) + } else put_gasmix(b, &ev->gas.mix); } put_format(b, " />\n"); diff --git a/desktop-widgets/maintab.cpp b/desktop-widgets/maintab.cpp index 180814c9c..a3cc151ef 100644 --- a/desktop-widgets/maintab.cpp +++ b/desktop-widgets/maintab.cpp @@ -946,7 +946,7 @@ void MainTab::acceptChanges() get_dive_dc(mydive, dc_number)->divemode = displayed_dc->divemode; } ); - MODIFY_SELECTED_DIVES(update_setpoint_events(get_dive_dc(mydive, dc_number))); + MODIFY_SELECTED_DIVES(update_setpoint_events(mydive, get_dive_dc(mydive, dc_number))); do_replot = true; } if (displayed_dive.watertemp.mkelvin != cd->watertemp.mkelvin) @@ -1237,7 +1237,7 @@ void MainTab::divetype_Changed(int index) return; struct divecomputer *displayed_dc = get_dive_dc(&displayed_dive, dc_number); displayed_dc->divemode = (enum dive_comp_type) index; - update_setpoint_events(displayed_dc); + update_setpoint_events(&displayed_dive, displayed_dc); markChangedWidget(ui.DiveType); MainWindow::instance()->graphics()->recalcCeiling(); } |