mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-01 05:53:24 +00:00
Simplify dive planning code
This simplifies the dive planning code by: - allowing empty gas mixes (which means "pick previous gas") - avoiding unnecessary strdup/free calls (this requires us to handle "const char *" in the parsers, but that was already true from a code standpoint, just not a type one) - re-use the "plan()" function for a successful dive plan, rather than open-coding the dive plan segment handling. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
parent
e47e37e5a6
commit
ab7aecf16e
1 changed files with 68 additions and 123 deletions
191
planner.c
191
planner.c
|
@ -124,10 +124,7 @@ struct dive *create_dive_from_plan(struct diveplan *diveplan)
|
||||||
struct dive *dive;
|
struct dive *dive;
|
||||||
struct divedatapoint *dp;
|
struct divedatapoint *dp;
|
||||||
struct divecomputer *dc;
|
struct divecomputer *dc;
|
||||||
struct sample *sample;
|
int oldo2 = AIR_PERMILLE, oldhe = 0;
|
||||||
int gasused = 0;
|
|
||||||
int t = 0;
|
|
||||||
int lastdepth = 0;
|
|
||||||
|
|
||||||
if (!diveplan || !diveplan->dp)
|
if (!diveplan || !diveplan->dp)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -137,35 +134,39 @@ struct dive *create_dive_from_plan(struct diveplan *diveplan)
|
||||||
dc = &dive->dc;
|
dc = &dive->dc;
|
||||||
dc->model = "Simulated Dive";
|
dc->model = "Simulated Dive";
|
||||||
dp = diveplan->dp;
|
dp = diveplan->dp;
|
||||||
/* let's start with the gas given on the first segment */
|
|
||||||
if(dp)
|
|
||||||
add_gas(dive, dp->o2, dp->he);
|
|
||||||
while (dp && dp->time) {
|
|
||||||
int i, depth;
|
|
||||||
|
|
||||||
if (dp->o2 != dive->cylinder[gasused].gasmix.o2.permille ||
|
/* let's start with the gas given on the first segment */
|
||||||
dp->he != dive->cylinder[gasused].gasmix.he.permille) {
|
if (dp->o2 || dp->he) {
|
||||||
int value;
|
oldo2 = dp->o2;
|
||||||
gasused = add_gas(dive, dp->o2, dp->he);
|
oldhe = dp->he;
|
||||||
value = dp->o2 / 10 | (dp->he / 10) << 16;
|
}
|
||||||
add_event(dc, dp->time, 11, 0, value, "gaschange");
|
add_gas(dive, oldo2, oldhe);
|
||||||
|
while (dp) {
|
||||||
|
int o2 = dp->o2, he = dp->he;
|
||||||
|
int time = dp->time;
|
||||||
|
int depth = dp->depth;
|
||||||
|
struct sample *sample;
|
||||||
|
|
||||||
|
if (!o2 && !he) {
|
||||||
|
o2 = oldo2;
|
||||||
|
he = oldhe;
|
||||||
}
|
}
|
||||||
for (i = t; i < dp->time; i += 10) {
|
|
||||||
depth = lastdepth + (i - t) * (dp->depth - lastdepth) / (dp->time - t);
|
/* Create new gas, and gas change event if necessary */
|
||||||
sample = prepare_sample(dc);
|
if (o2 != oldo2 || he != oldhe) {
|
||||||
sample->time.seconds = i;
|
int value = (o2 / 10) | (he / 10 << 16);
|
||||||
sample->depth.mm = depth;
|
add_gas(dive, o2, he);
|
||||||
sample->sensor = gasused;
|
add_event(dc, time, 11, 0, value, "gaschange");
|
||||||
dc->samples++;
|
oldo2 = o2; oldhe = he;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create sample */
|
||||||
sample = prepare_sample(dc);
|
sample = prepare_sample(dc);
|
||||||
sample->time.seconds = dp->time;
|
sample->time.seconds = time;
|
||||||
sample->depth.mm = dp->depth;
|
sample->depth.mm = depth;
|
||||||
sample->sensor = gasused;
|
finish_sample(dc);
|
||||||
lastdepth = dp->depth;
|
|
||||||
t = dp->time;
|
|
||||||
dp = dp->next;
|
dp = dp->next;
|
||||||
dc->samples++;
|
|
||||||
}
|
}
|
||||||
if (dc->samples == 0) {
|
if (dc->samples == 0) {
|
||||||
/* not enough there yet to create a dive - most likely the first time is missing */
|
/* not enough there yet to create a dive - most likely the first time is missing */
|
||||||
|
@ -233,13 +234,8 @@ void add_depth_to_nth_dp(struct diveplan *diveplan, int idx, int depth)
|
||||||
void add_gas_to_nth_dp(struct diveplan *diveplan, int idx, int o2, int he)
|
void add_gas_to_nth_dp(struct diveplan *diveplan, int idx, int o2, int he)
|
||||||
{
|
{
|
||||||
struct divedatapoint *dp = get_nth_dp(diveplan, idx);
|
struct divedatapoint *dp = get_nth_dp(diveplan, idx);
|
||||||
if (o2 > 206 && o2 < 213 && he == 0) {
|
dp->o2 = o2;
|
||||||
/* we treat air in a special case */
|
dp->he = he;
|
||||||
dp->o2 = dp->he = 0;
|
|
||||||
} else {
|
|
||||||
dp->o2 = o2;
|
|
||||||
dp->he = he;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void add_to_end_of_diveplan(struct diveplan *diveplan, struct divedatapoint *dp)
|
void add_to_end_of_diveplan(struct diveplan *diveplan, struct divedatapoint *dp)
|
||||||
{
|
{
|
||||||
|
@ -322,27 +318,30 @@ void plan(struct diveplan *diveplan, char **cached_datap, struct dive **divep)
|
||||||
*
|
*
|
||||||
* Return negative for errors.
|
* Return negative for errors.
|
||||||
*/
|
*/
|
||||||
static int get_tenths(char *begin, char **end)
|
static int get_tenths(const char *begin, const char **endp)
|
||||||
{
|
{
|
||||||
int value = strtol(begin, end, 10);
|
char *end;
|
||||||
if (begin == *end)
|
int value = strtol(begin, &end, 10);
|
||||||
|
|
||||||
|
*endp = end;
|
||||||
|
if (begin == end)
|
||||||
return -1;
|
return -1;
|
||||||
value *= 10;
|
value *= 10;
|
||||||
|
|
||||||
/* Fraction? We only look at the first digit */
|
/* Fraction? We only look at the first digit */
|
||||||
if (**end == '.') {
|
if (*end == '.') {
|
||||||
++*end;
|
++*end;
|
||||||
if (!isdigit(**end))
|
if (!isdigit(*end))
|
||||||
return -1;
|
return -1;
|
||||||
value += **end - '0';
|
value += *end - '0';
|
||||||
do {
|
do {
|
||||||
++*end;
|
++*end;
|
||||||
} while (isdigit(**end));
|
} while (isdigit(*end));
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_permille(char *begin, char **end)
|
static int get_permille(const char *begin, const char **end)
|
||||||
{
|
{
|
||||||
int value = get_tenths(begin, end);
|
int value = get_tenths(begin, end);
|
||||||
if (value >= 0) {
|
if (value >= 0) {
|
||||||
|
@ -353,7 +352,7 @@ static int get_permille(char *begin, char **end)
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int validate_gas(char *text, int *o2_p, int *he_p)
|
static int validate_gas(const char *text, int *o2_p, int *he_p)
|
||||||
{
|
{
|
||||||
int o2, he;
|
int o2, he;
|
||||||
|
|
||||||
|
@ -363,9 +362,10 @@ static int validate_gas(char *text, int *o2_p, int *he_p)
|
||||||
while (isspace(*text))
|
while (isspace(*text))
|
||||||
text++;
|
text++;
|
||||||
|
|
||||||
if (!*text) {
|
if (!*text)
|
||||||
o2 = AIR_PERMILLE; he = 0;
|
return 0;
|
||||||
} else if (!strcasecmp(text, "air")) {
|
|
||||||
|
if (!strcasecmp(text, "air")) {
|
||||||
o2 = AIR_PERMILLE; he = 0; text += 3;
|
o2 = AIR_PERMILLE; he = 0; text += 3;
|
||||||
} else if (!strncasecmp(text, "ean", 3)) {
|
} else if (!strncasecmp(text, "ean", 3)) {
|
||||||
o2 = get_permille(text+3, &text); he = 0;
|
o2 = get_permille(text+3, &text); he = 0;
|
||||||
|
@ -391,7 +391,7 @@ static int validate_gas(char *text, int *o2_p, int *he_p)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int validate_time(char *text, int *sec_p, int *rel_p)
|
static int validate_time(const char *text, int *sec_p, int *rel_p)
|
||||||
{
|
{
|
||||||
int min, sec, rel;
|
int min, sec, rel;
|
||||||
char *end;
|
char *end;
|
||||||
|
@ -453,7 +453,7 @@ static int validate_time(char *text, int *sec_p, int *rel_p)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int validate_depth(char *text, int *mm_p)
|
static int validate_depth(const char *text, int *mm_p)
|
||||||
{
|
{
|
||||||
int depth, imperial;
|
int depth, imperial;
|
||||||
|
|
||||||
|
@ -542,48 +542,43 @@ void show_planned_dive(void)
|
||||||
|
|
||||||
static gboolean gas_focus_out_cb(GtkWidget *entry, GdkEvent *event, gpointer data)
|
static gboolean gas_focus_out_cb(GtkWidget *entry, GdkEvent *event, gpointer data)
|
||||||
{
|
{
|
||||||
char *gastext;
|
const char *gastext;
|
||||||
int o2, he;
|
int o2, he;
|
||||||
int idx = data - NULL;
|
int idx = data - NULL;
|
||||||
|
|
||||||
gastext = strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
|
gastext = gtk_entry_get_text(GTK_ENTRY(entry));
|
||||||
if (validate_gas(gastext, &o2, &he)) {
|
o2 = he = 0;
|
||||||
|
if (validate_gas(gastext, &o2, &he))
|
||||||
add_string_list_entry(gastext, gas_model);
|
add_string_list_entry(gastext, gas_model);
|
||||||
add_gas_to_nth_dp(&diveplan, idx, o2, he);
|
add_gas_to_nth_dp(&diveplan, idx, o2, he);
|
||||||
show_planned_dive();
|
show_planned_dive();
|
||||||
} else {
|
|
||||||
/* we need to instead change the color of the input field or something */
|
|
||||||
printf("invalid gas for row %d\n",idx);
|
|
||||||
}
|
|
||||||
free(gastext);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gas_changed_cb(GtkWidget *combo, gpointer data)
|
static void gas_changed_cb(GtkWidget *combo, gpointer data)
|
||||||
{
|
{
|
||||||
char *gastext;
|
const char *gastext;
|
||||||
int o2, he;
|
int o2, he;
|
||||||
int idx = data - NULL;
|
int idx = data - NULL;
|
||||||
|
|
||||||
gastext = strdup(gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo)));
|
gastext = gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo));
|
||||||
if (validate_gas(gastext, &o2, &he)) {
|
o2 = he = 0;
|
||||||
add_gas_to_nth_dp(&diveplan, idx, o2, he);
|
if (!validate_gas(gastext, &o2, &he)) {
|
||||||
show_planned_dive();
|
|
||||||
} else {
|
|
||||||
/* this should never happen as only validated texts should be
|
/* this should never happen as only validated texts should be
|
||||||
* in the dropdown */
|
* in the dropdown */
|
||||||
printf("invalid gas for row %d\n",idx);
|
printf("invalid gas for row %d\n",idx);
|
||||||
}
|
}
|
||||||
free(gastext);
|
add_gas_to_nth_dp(&diveplan, idx, o2, he);
|
||||||
|
show_planned_dive();
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean depth_focus_out_cb(GtkWidget *entry, GdkEvent *event, gpointer data)
|
static gboolean depth_focus_out_cb(GtkWidget *entry, GdkEvent *event, gpointer data)
|
||||||
{
|
{
|
||||||
char *depthtext;
|
const char *depthtext;
|
||||||
int depth;
|
int depth;
|
||||||
int idx = data - NULL;
|
int idx = data - NULL;
|
||||||
|
|
||||||
depthtext = strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
|
depthtext = gtk_entry_get_text(GTK_ENTRY(entry));
|
||||||
if (validate_depth(depthtext, &depth)) {
|
if (validate_depth(depthtext, &depth)) {
|
||||||
add_depth_to_nth_dp(&diveplan, idx, depth);
|
add_depth_to_nth_dp(&diveplan, idx, depth);
|
||||||
show_planned_dive();
|
show_planned_dive();
|
||||||
|
@ -591,17 +586,16 @@ static gboolean depth_focus_out_cb(GtkWidget *entry, GdkEvent *event, gpointer d
|
||||||
/* we need to instead change the color of the input field or something */
|
/* we need to instead change the color of the input field or something */
|
||||||
printf("invalid depth for row %d\n", idx);
|
printf("invalid depth for row %d\n", idx);
|
||||||
}
|
}
|
||||||
free(depthtext);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean duration_focus_out_cb(GtkWidget *entry, GdkEvent * event, gpointer data)
|
static gboolean duration_focus_out_cb(GtkWidget *entry, GdkEvent * event, gpointer data)
|
||||||
{
|
{
|
||||||
char *durationtext;
|
const char *durationtext;
|
||||||
int duration, is_rel;
|
int duration, is_rel;
|
||||||
int idx = data - NULL;
|
int idx = data - NULL;
|
||||||
|
|
||||||
durationtext = strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
|
durationtext = gtk_entry_get_text(GTK_ENTRY(entry));
|
||||||
if (validate_time(durationtext, &duration, &is_rel)) {
|
if (validate_time(durationtext, &duration, &is_rel)) {
|
||||||
add_duration_to_nth_dp(&diveplan, idx, duration, is_rel);
|
add_duration_to_nth_dp(&diveplan, idx, duration, is_rel);
|
||||||
show_planned_dive();
|
show_planned_dive();
|
||||||
|
@ -609,16 +603,15 @@ static gboolean duration_focus_out_cb(GtkWidget *entry, GdkEvent * event, gpoint
|
||||||
/* we need to instead change the color of the input field or something */
|
/* we need to instead change the color of the input field or something */
|
||||||
printf("invalid duration for row %d\n", idx);
|
printf("invalid duration for row %d\n", idx);
|
||||||
}
|
}
|
||||||
free(durationtext);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean starttime_focus_out_cb(GtkWidget *entry, GdkEvent * event, gpointer data)
|
static gboolean starttime_focus_out_cb(GtkWidget *entry, GdkEvent * event, gpointer data)
|
||||||
{
|
{
|
||||||
char *starttimetext;
|
const char *starttimetext;
|
||||||
int starttime, is_rel;
|
int starttime, is_rel;
|
||||||
|
|
||||||
starttimetext = strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
|
starttimetext = gtk_entry_get_text(GTK_ENTRY(entry));
|
||||||
if (validate_time(starttimetext, &starttime, &is_rel)) {
|
if (validate_time(starttimetext, &starttime, &is_rel)) {
|
||||||
/* we alway make this relative for now */
|
/* we alway make this relative for now */
|
||||||
diveplan.when = time(NULL) + starttime;
|
diveplan.when = time(NULL) + starttime;
|
||||||
|
@ -626,7 +619,6 @@ static gboolean starttime_focus_out_cb(GtkWidget *entry, GdkEvent * event, gpoin
|
||||||
/* we need to instead change the color of the input field or something */
|
/* we need to instead change the color of the input field or something */
|
||||||
printf("invalid starttime\n");
|
printf("invalid starttime\n");
|
||||||
}
|
}
|
||||||
free(starttimetext);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -705,7 +697,6 @@ static void add_waypoint_cb(GtkButton *button, gpointer _data)
|
||||||
void input_plan()
|
void input_plan()
|
||||||
{
|
{
|
||||||
GtkWidget *planner, *content, *vbox, *outervbox, *add_row, *deltat;
|
GtkWidget *planner, *content, *vbox, *outervbox, *add_row, *deltat;
|
||||||
int lasttime = 0;
|
|
||||||
char starttimebuf[64] = "+60:00";
|
char starttimebuf[64] = "+60:00";
|
||||||
|
|
||||||
if (diveplan.dp)
|
if (diveplan.dp)
|
||||||
|
@ -740,53 +731,7 @@ void input_plan()
|
||||||
gtk_box_pack_start(GTK_BOX(outervbox), add_row, FALSE, FALSE, 0);
|
gtk_box_pack_start(GTK_BOX(outervbox), add_row, FALSE, FALSE, 0);
|
||||||
gtk_widget_show_all(planner);
|
gtk_widget_show_all(planner);
|
||||||
if (gtk_dialog_run(GTK_DIALOG(planner)) == GTK_RESPONSE_ACCEPT) {
|
if (gtk_dialog_run(GTK_DIALOG(planner)) == GTK_RESPONSE_ACCEPT) {
|
||||||
int i;
|
plan(&diveplan, &cache_data, &planned_dive);
|
||||||
const char *deltattext;
|
|
||||||
|
|
||||||
deltattext = gtk_entry_get_text(GTK_ENTRY(deltat));
|
|
||||||
diveplan.when = time(NULL) + 60 * atoi(deltattext);
|
|
||||||
free_dps(diveplan.dp);
|
|
||||||
diveplan.dp = 0;
|
|
||||||
for (i = 0; i < nr_waypoints; i++) {
|
|
||||||
char *depthtext, *durationtext, *gastext;
|
|
||||||
int depth, duration, o2, he, is_rel;
|
|
||||||
GtkWidget *entry;
|
|
||||||
|
|
||||||
depthtext = strdup(gtk_entry_get_text(GTK_ENTRY(entry_depth[i])));
|
|
||||||
if (!validate_depth(depthtext, &depth)) {
|
|
||||||
// mark error and redo?
|
|
||||||
free(depthtext);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
durationtext = strdup(gtk_entry_get_text(GTK_ENTRY(entry_duration[i])));
|
|
||||||
if (!validate_time(durationtext, &duration, &is_rel)) {
|
|
||||||
// mark error and redo?
|
|
||||||
free(durationtext);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!is_rel)
|
|
||||||
duration -= lasttime;
|
|
||||||
entry = gtk_bin_get_child(GTK_BIN(entry_gas[i]));
|
|
||||||
gastext = strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
|
|
||||||
if (!validate_gas(gastext, &o2, &he)) {
|
|
||||||
// mark error and redo?
|
|
||||||
free(gastext);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* just in case this didn't get added by the callback */
|
|
||||||
add_string_list_entry(gastext, gas_model);
|
|
||||||
|
|
||||||
// still need to handle desired pO2 and a setpoint (for CC)
|
|
||||||
|
|
||||||
if (duration == 0)
|
|
||||||
break;
|
|
||||||
plan_add_segment(&diveplan, duration, depth, o2, he);
|
|
||||||
lasttime += duration;
|
|
||||||
free(depthtext);
|
|
||||||
free(durationtext);
|
|
||||||
free(gastext);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
show_planned_dive();
|
|
||||||
gtk_widget_destroy(planner);
|
gtk_widget_destroy(planner);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue