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:
Linus Torvalds 2013-01-07 13:13:10 -08:00 committed by Dirk Hohndel
parent e47e37e5a6
commit ab7aecf16e

183
planner.c
View file

@ -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");
} }
for (i = t; i < dp->time; i += 10) { add_gas(dive, oldo2, oldhe);
depth = lastdepth + (i - t) * (dp->depth - lastdepth) / (dp->time - t); 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;
}
/* Create new gas, and gas change event if necessary */
if (o2 != oldo2 || he != oldhe) {
int value = (o2 / 10) | (he / 10 << 16);
add_gas(dive, o2, he);
add_event(dc, time, 11, 0, value, "gaschange");
oldo2 = o2; oldhe = he;
}
/* Create sample */
sample = prepare_sample(dc); sample = prepare_sample(dc);
sample->time.seconds = i; sample->time.seconds = time;
sample->depth.mm = depth; sample->depth.mm = depth;
sample->sensor = gasused; finish_sample(dc);
dc->samples++;
}
sample = prepare_sample(dc);
sample->time.seconds = dp->time;
sample->depth.mm = dp->depth;
sample->sensor = gasused;
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,14 +234,9 @@ 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) {
/* we treat air in a special case */
dp->o2 = dp->he = 0;
} else {
dp->o2 = o2; dp->o2 = o2;
dp->he = he; 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)
{ {
struct divedatapoint **lastdp = &diveplan->dp; struct divedatapoint **lastdp = &diveplan->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);
} }