CC dive planning [was: Re: Plans [was: Re: Gconf or GSettings? - leading to a wider question]]

Dirk Hohndel dirk at hohndel.org
Mon Jan 28 21:56:10 PST 2013


I have committed the patch below as is and added a second commit that
fixes the issues with this. Please read through my code and make sure
that the changes all make sense - some semi-serious testing didn't find
any glaring issues; the dive plans seem sane.

/D

Jan Schubert <Jan.Schubert at GMX.li> writes:

> On 01/20/13 17:21, Dirk Hohndel wrote:
>> Just for the record - before we spend too much time on this I want to get Subsurface 3.0 out.
>>
>> On my list of things for this to happen are
>>
>> - a few loose ends:
>> -- Jan wants to add CC support to the dive planning
>
> Sorry for not coming up with a final proposal yet. For anyone interested 
> in, please find attached a patch which misses a single issue to be used 
> as a base for further discussion: The CC setpoint is used for the next 
> segment, not the one specified for. I also have in mind to modify the 
> existing code to use setpoints specified in mbar and plain integer 
> instead of float values.
>
> Dirk, this is the same patch I sent you 2 weeks ago. I'm sorry for not 
> having finally fixed it but will try to at the coming weakend. I also 
> did not think that much about alternative ways for specifing the 
> setpoints, Sorry.
>
> Just in case someone wants to play around with it...
>
> Thx,
> Jan
> diff --git a/dive.h b/dive.h
> index 2c8f18b..676c943 100644
> --- a/dive.h
> +++ b/dive.h
> @@ -608,6 +608,7 @@ struct divedatapoint {
>  	int depth;
>  	int o2;
>  	int he;
> +	int po2;
>  	gboolean entered;
>  	struct divedatapoint *next;
>  };
> @@ -621,7 +622,7 @@ struct diveplan {
>  };
>  
>  void plan(struct diveplan *diveplan, char **cache_datap, struct dive **divep);
> -void plan_add_segment(struct diveplan *diveplan, int duration, int depth, int o2, int he);
> +void plan_add_segment(struct diveplan *diveplan, int duration, int depth, int o2, int he, int po2);
>  void add_duration_to_nth_dp(struct diveplan *diveplan, int idx, int duration, gboolean is_rel);
>  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);
> diff --git a/divelist.c b/divelist.c
> index 554fb88..5b9a6fa 100644
> --- a/divelist.c
> +++ b/divelist.c
> @@ -746,7 +746,7 @@ static int calculate_otu(struct dive *dive, struct divecomputer *dc)
>  		struct sample *psample = sample - 1;
>  		t = sample->time.seconds - psample->time.seconds;
>  		if (sample->po2) {
> -			po2 = sample->po2;
> +			po2 = sample->po2 / 1000;
>  		} else {
>  			int o2 = active_o2(dive, dc, sample->time);
>  			po2 = o2 / 1000.0 * depth_to_mbar(sample->depth.mm, dive) / 1000.0;
> diff --git a/planner.c b/planner.c
> index e77fdb9..164228e 100644
> --- a/planner.c
> +++ b/planner.c
> @@ -112,7 +112,7 @@ double tissue_at_end(struct dive *dive, char **cached_datap)
>  		for (j = t0; j < t1; j++) {
>  			int depth = interpolate(lastdepth, sample->depth.mm, j - t0, t1 - t0);
>  			tissue_tolerance = add_segment(depth_to_mbar(depth, dive) / 1000.0,
> -						       &dive->cylinder[gasidx].gasmix, 1, sample->po2, dive);
> +						       &dive->cylinder[gasidx].gasmix, 1, sample->po2 / 1000, dive);
>  		}
>  		psample = sample;
>  		t0 = t1;
> @@ -139,7 +139,7 @@ int time_at_last_depth(struct dive *dive, int next_stop, char **cached_data_p)
>  	while (deco_allowed_depth(tissue_tolerance, surface_pressure, dive, 1) > next_stop) {
>  		wait++;
>  		tissue_tolerance = add_segment(depth_to_mbar(depth, dive) / 1000.0,
> -					       &dive->cylinder[gasidx].gasmix, 1, sample->po2, dive);
> +					       &dive->cylinder[gasidx].gasmix, 1, 1.1, dive);
>  	}
>  	return wait;
>  }
> @@ -197,6 +197,7 @@ struct dive *create_dive_from_plan(struct diveplan *diveplan)
>  	add_gas(dive, oldo2, oldhe);
>  	while (dp) {
>  		int o2 = dp->o2, he = dp->he;
> +		int po2 = dp->po2;
>  		int time = dp->time;
>  		int depth = dp->depth;
>  		struct sample *sample;
> @@ -223,6 +224,7 @@ struct dive *create_dive_from_plan(struct diveplan *diveplan)
>  
>  		/* Create sample */
>  		sample = prepare_sample(dc);
> +		sample->po2 = po2;
>  		sample->time.seconds = time;
>  		sample->depth.mm = depth;
>  		finish_sample(dc);
> @@ -250,7 +252,7 @@ void free_dps(struct divedatapoint *dp)
>  	}
>  }
>  
> -struct divedatapoint *create_dp(int time_incr, int depth, int o2, int he)
> +struct divedatapoint *create_dp(int time_incr, int depth, int o2, int he, int po2)
>  {
>  	struct divedatapoint *dp;
>  
> @@ -259,6 +261,7 @@ struct divedatapoint *create_dp(int time_incr, int depth, int o2, int he)
>  	dp->depth = depth;
>  	dp->o2 = o2;
>  	dp->he = he;
> +	dp->po2 = po2;
>  	dp->entered = FALSE;
>  	dp->next = NULL;
>  	return dp;
> @@ -275,7 +278,7 @@ struct divedatapoint *get_nth_dp(struct diveplan *diveplan, int idx)
>  		dp = dp->next;
>  	}
>  	while (i++ <= idx) {
> -		*ldpp = dp = create_dp(0, 0, 0, 0);
> +		*ldpp = dp = create_dp(0, 0, 0, 0, 0);
>  		ldpp = &((*ldpp)->next);
>  	}
>  	return dp;
> @@ -309,6 +312,13 @@ void add_gas_to_nth_dp(struct diveplan *diveplan, int idx, int o2, int he)
>  	dp->o2 = o2;
>  	dp->he = he;
>  }
> +
> +void add_po2_to_nth_dp(struct diveplan *diveplan, int idx, int po2)
> +{
> +	struct divedatapoint *dp = get_nth_dp(diveplan, idx);
> +	dp->po2 = po2;
> +}
> +
>  void add_to_end_of_diveplan(struct diveplan *diveplan, struct divedatapoint *dp)
>  {
>  	struct divedatapoint **lastdp = &diveplan->dp;
> @@ -325,9 +335,9 @@ void add_to_end_of_diveplan(struct diveplan *diveplan, struct divedatapoint *dp)
>  		dp->time += lasttime;
>  }
>  
> -void plan_add_segment(struct diveplan *diveplan, int duration, int depth, int o2, int he)
> +void plan_add_segment(struct diveplan *diveplan, int duration, int depth, int o2, int he, int po2)
>  {
> -	struct divedatapoint *dp = create_dp(duration, depth, o2, he);
> +	struct divedatapoint *dp = create_dp(duration, depth, o2, he, po2);
>  	add_to_end_of_diveplan(diveplan, dp);
>  }
>  
> @@ -528,7 +538,7 @@ void plan(struct diveplan *diveplan, char **cached_datap, struct dive **divep)
>  {
>  	struct dive *dive;
>  	struct sample *sample;
> -	int wait_time, o2, he;
> +	int wait_time, o2, he, po2;
>  	int ceiling, depth, transitiontime;
>  	int stopidx, gi;
>  	double tissue_tolerance;
> @@ -551,6 +561,7 @@ void plan(struct diveplan *diveplan, char **cached_datap, struct dive **divep)
>  	o2 = dive->cylinder[0].gasmix.o2.permille;
>  	he = dive->cylinder[0].gasmix.he.permille;
>  	get_gas_from_events(&dive->dc, sample->time.seconds, &o2, &he);
> +	po2 = dive->dc.sample[dive->dc.samples - 1].po2;
>  	depth = dive->dc.sample[dive->dc.samples - 1].depth.mm;
>  	tissue_tolerance = tissue_at_end(dive, cached_datap);
>  	ceiling = deco_allowed_depth(tissue_tolerance, diveplan->surface_pressure / 1000.0, dive, 1);
> @@ -581,7 +592,7 @@ void plan(struct diveplan *diveplan, char **cached_datap, struct dive **divep)
>  #if DEBUG_PLAN & 2
>  		printf("transitiontime %d:%02d to depth %5.2lfm\n", FRACTION(transitiontime, 60), stoplevels[stopidx] / 1000.0);
>  #endif
> -		plan_add_segment(diveplan, transitiontime, stoplevels[stopidx], o2, he);
> +		plan_add_segment(diveplan, transitiontime, stoplevels[stopidx], o2, he, po2);
>  		/* re-create the dive */
>  		delete_single_dive(dive_table.nr - 1);
>  		*divep = dive = create_dive_from_plan(diveplan);
> @@ -605,12 +616,12 @@ void plan(struct diveplan *diveplan, char **cached_datap, struct dive **divep)
>  		printf("waittime %d:%02d at depth %5.2lfm\n", FRACTION(wait_time, 60), stoplevels[stopidx] / 1000.0);
>  #endif
>  		if (wait_time)
> -			plan_add_segment(diveplan, wait_time, stoplevels[stopidx], o2, he);
> +			plan_add_segment(diveplan, wait_time, stoplevels[stopidx], o2, he, po2);
>  		transitiontime = (stoplevels[stopidx] - stoplevels[stopidx - 1]) / 150;
>  #if DEBUG_PLAN & 2
>  		printf("transitiontime %d:%02d to depth %5.2lfm\n", FRACTION(transitiontime, 60), stoplevels[stopidx - 1] / 1000.0);
>  #endif
> -		plan_add_segment(diveplan, transitiontime, stoplevels[stopidx - 1], o2, he);
> +		plan_add_segment(diveplan, transitiontime, stoplevels[stopidx - 1], o2, he, po2);
>  		/* re-create the dive */
>  		delete_single_dive(dive_table.nr - 1);
>  		*divep = dive = create_dive_from_plan(diveplan);
> @@ -827,6 +838,29 @@ static int validate_depth(const char *text, int *mm_p)
>  	return 1;
>  }
>  
> +static int validate_po2(const char *text, int *mbar_po2)
> +{
> +	int po2;
> +
> +	if (!text)
> +		return 0;
> +
> +	po2 = get_tenths(text, &text);
> +	if (po2 < 0)
> +		return 0;
> +
> +	while (isspace(*text))
> +		text++;
> +
> +	while (isspace(*text))
> +		text++;
> +	if (*text)
> +		return 0;
> +
> +	*mbar_po2 = po2 * 100;
> +	return 1;
> +}
> +
>  static int validate_volume(const char *text, int *sac)
>  {
>  	int volume, imperial;
> @@ -880,7 +914,7 @@ static GtkWidget *add_entry_to_box(GtkWidget *box, const char *label)
>  }
>  
>  #define MAX_WAYPOINTS 8
> -GtkWidget *entry_depth[MAX_WAYPOINTS], *entry_duration[MAX_WAYPOINTS], *entry_gas[MAX_WAYPOINTS];
> +GtkWidget *entry_depth[MAX_WAYPOINTS], *entry_duration[MAX_WAYPOINTS], *entry_gas[MAX_WAYPOINTS], *entry_po2[MAX_WAYPOINTS];
>  int nr_waypoints = 0;
>  static GtkListStore *gas_model = NULL;
>  struct diveplan diveplan = {};
> @@ -980,6 +1014,19 @@ static gboolean duration_focus_out_cb(GtkWidget *entry, GdkEvent * event, gpoint
>  	return FALSE;
>  }
>  
> +static gboolean po2_focus_out_cb(GtkWidget *entry, GdkEvent * event, gpointer data)
> +{
> +	const char *po2text;
> +	int po2;
> +	int idx = data - NULL;
> +
> +	po2text = gtk_entry_get_text(GTK_ENTRY(entry));
> +	if (validate_po2(po2text, &po2))
> +		add_po2_to_nth_dp(&diveplan, idx, po2);
> +	show_planned_dive();
> +	return FALSE;
> +}
> +
>  /* Subsurface follows the lead of most divecomputers to use times
>   * without timezone - so all times are implicitly assumed to be
>   * local time of the dive location; so in order to give the current
> @@ -1088,15 +1135,19 @@ static void add_waypoint_widgets(GtkWidget *box, int idx)
>  		entry_depth[idx] = add_entry_to_box(hbox, _("Ending Depth"));
>  		entry_duration[idx] = add_entry_to_box(hbox, _("Segment Time"));
>  		entry_gas[idx] = add_gas_combobox_to_box(hbox, _("Gas Used"), idx);
> +		entry_po2[idx] = add_entry_to_box(hbox, _("CC SetPoint"));
>  	} else {
>  		entry_depth[idx] = add_entry_to_box(hbox, NULL);
>  		entry_duration[idx] = add_entry_to_box(hbox, NULL);
>  		entry_gas[idx] = add_gas_combobox_to_box(hbox, NULL, idx);
> +		entry_po2[idx] = add_entry_to_box(hbox, NULL);
>  	}
>  	gtk_widget_add_events(entry_depth[idx], GDK_FOCUS_CHANGE_MASK);
>  	g_signal_connect(entry_depth[idx], "focus-out-event", G_CALLBACK(depth_focus_out_cb), NULL + idx);
>  	gtk_widget_add_events(entry_duration[idx], GDK_FOCUS_CHANGE_MASK);
>  	g_signal_connect(entry_duration[idx], "focus-out-event", G_CALLBACK(duration_focus_out_cb), NULL + idx);
> +	gtk_widget_add_events(entry_po2[idx], GDK_FOCUS_CHANGE_MASK);
> +	g_signal_connect(entry_po2[idx], "focus-out-event", G_CALLBACK(po2_focus_out_cb), NULL + idx);
>  }
>  
>  static void add_waypoint_cb(GtkButton *button, gpointer _data)
> @@ -1152,7 +1203,8 @@ void input_plan()
>  						"An empty gas means 'use previous gas' (or AIR if no gas was specified).\n"
>  						"An entry that has a depth and a gas given but no time is special; it "
>  						"informs the planner that the gas specified is available for the ascent "
> -						"once the depth given has been reached.</small>"));
> +						"once the depth given has been reached.\n"
> +						"CC SetPoint specifies CC dives, leave empty for OC.</small>"));
>  	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
>  	gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
>  	gtk_box_pack_start(GTK_BOX(outervbox), label, TRUE, TRUE, 0);
> _______________________________________________
> subsurface mailing list
> subsurface at hohndel.org
> http://lists.hohndel.org/cgi-bin/mailman/listinfo/subsurface


More information about the subsurface mailing list