From 70d7bb650ad46a4237afd27cfd595812eb040701 Mon Sep 17 00:00:00 2001 From: Tim Segers Date: Wed, 4 Jan 2023 12:58:59 +0100 Subject: Add support for imperial units Implements: https://todo.sr.ht/~tsegers/opendeco/1 --- opendeco.toml | 1 + src/deco.c | 32 ++++++++++++++++++++++++++++++++ src/deco.h | 12 ++++++++++++ src/opendeco-cli.c | 4 ++++ src/opendeco-conf.c | 5 +++++ src/opendeco-conf.h | 3 +++ src/opendeco.c | 14 ++++++++------ src/output.c | 9 +++++---- 8 files changed, 70 insertions(+), 10 deletions(-) diff --git a/opendeco.toml b/opendeco.toml index 4884ee5..e549e03 100644 --- a/opendeco.toml +++ b/opendeco.toml @@ -2,6 +2,7 @@ gas = "Air" # Bottom gas used during the dive surface_pressure = 1.01325 # Surface air pressure [bar] rmv = 20 # RMV during the dive portion of the dive [l/min] +imperial = false # Use imperial units [deco] gflow = 30 # Gradient factor at the first stop diff --git a/src/deco.c b/src/deco.c index e1ea401..349c8e5 100644 --- a/src/deco.c +++ b/src/deco.c @@ -9,6 +9,7 @@ #define RND(x) (round((x) *10000) / 10000) enum ALGO ALGO_VER = ALGO_VER_DEFAULT; +enum UNITS UNITS = UNITS_DEFAULT; double SURFACE_PRESSURE = SURFACE_PRESSURE_DEFAULT; double P_WV = P_WV_DEFAULT; @@ -77,6 +78,37 @@ double msw_to_bar(double msw) return msw / 10; } +double bar_to_fsw(double bar) +{ + return (bar / 1.01325) * 33.0; +} + +double fsw_to_bar(double fsw) +{ + return (fsw * 1.01325) / 33.0; +} + +double msw_or_fsw(double msw, double fsw) +{ + assert(UNITS == METRIC || UNITS == IMPERIAL); + + return (UNITS == METRIC) ? msw : fsw; +} + +double xsw_to_bar(double xsw) +{ + assert(UNITS == METRIC || UNITS == IMPERIAL); + + return (UNITS == METRIC) ? msw_to_bar(xsw) : fsw_to_bar(xsw); +} + +double bar_to_xsw(double bar) +{ + assert(UNITS == METRIC || UNITS == IMPERIAL); + + return (UNITS == METRIC) ? bar_to_msw(bar) : bar_to_fsw(bar); +} + double abs_depth(double gd) { return gd + SURFACE_PRESSURE; diff --git a/src/deco.h b/src/deco.h index 35905ca..2500580 100644 --- a/src/deco.h +++ b/src/deco.h @@ -14,6 +14,7 @@ #define P_WV_SCHR 0.0493 /* Schreiner value, Rq = 0.8, most conservative */ #define ALGO_VER_DEFAULT ZHL_16C +#define UNITS_DEFAULT METRIC #define SURFACE_PRESSURE_DEFAULT 1.01325 #define P_WV_DEFAULT P_WV_BUHL @@ -25,6 +26,11 @@ #define MOD_AUTO 0 /* types */ +enum UNITS { + METRIC, + IMPERIAL, +}; + enum ALGO { ZHL_16A = 0, ZHL_16B = 1, @@ -50,6 +56,7 @@ typedef struct gas_t { /* global variables */ extern enum ALGO ALGO_VER; +extern enum UNITS UNITS; extern double SURFACE_PRESSURE; extern double P_WV; @@ -61,6 +68,11 @@ extern int LAST_STOP_AT_SIX; /* functions */ double bar_to_msw(double bar); double msw_to_bar(double msw); +double bar_to_fsw(double bar); +double fsw_to_bar(double msw); +double msw_or_fsw(double msw, double fsw); +double xsw_to_bar(double xsw); +double bar_to_xsw(double bar); double abs_depth(double gd); double gauge_depth(double ad); diff --git a/src/opendeco-cli.c b/src/opendeco-cli.c index 5f6b627..d8da388 100644 --- a/src/opendeco-cli.c +++ b/src/opendeco-cli.c @@ -26,6 +26,7 @@ static struct argp_option options[] = { {"gas", 'g', "STRING", 0, "Set the bottom gas used during the dive, defaults to Air", 2 }, {"pressure", 'p', "NUMBER", 0, "Set the surface air pressure, defaults to 1.01325bar or 1atm", 3 }, {"rmv", 'r', "NUMBER", 0, "Set the RMV during the dive portion of the dive, defaults to 20", 4 }, + {"imperial", 'i', 0, 0, "Use imperial units (fsw)", 5 }, {0, 0, 0, 0, "Deco options:", 0 }, {"gflow", 'L', "NUMBER", 0, "Set the gradient factor at the first stop, defaults to 30", 5 }, @@ -83,6 +84,9 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) case 'r': arguments->RMV_DIVE = arg ? atof(arg) : -1; break; + case 'i': + arguments->UNITS = IMPERIAL; + break; case 'L': arguments->gflow = arg ? atoi(arg) : -1; break; diff --git a/src/opendeco-conf.c b/src/opendeco-conf.c index e044c90..977bfc5 100644 --- a/src/opendeco-conf.c +++ b/src/opendeco-conf.c @@ -49,6 +49,11 @@ int opendeco_conf_parse(const char *confpath, struct arguments *arguments) if (r.ok) arguments->RMV_DIVE = r.u.d; + + toml_datum_t i = toml_bool_in(dive, "imperial"); + + if (i.ok) + arguments->UNITS = i.u.b ? IMPERIAL : METRIC; } toml_table_t *deco = toml_table_in(od_conf, "deco"); diff --git a/src/opendeco-conf.h b/src/opendeco-conf.h index 8845409..359889a 100644 --- a/src/opendeco-conf.h +++ b/src/opendeco-conf.h @@ -3,6 +3,8 @@ #ifndef OPENDECOCONF_H #define OPENDECOCONF_H +#include "deco.h" + #ifndef VERSION #define VERSION "unknown version" #endif @@ -21,6 +23,7 @@ struct arguments { double RMV_DIVE; double RMV_DECO; int SHOW_TRAVEL; + enum UNITS UNITS; }; int opendeco_conf_parse(const char *confpath, struct arguments *arguments); diff --git a/src/opendeco.c b/src/opendeco.c index 029a81f..fe9a1d1 100644 --- a/src/opendeco.c +++ b/src/opendeco.c @@ -12,7 +12,7 @@ #include "output.h" #include "schedule.h" -#define MOD_OXY (abs_depth(msw_to_bar(6))) +#define MOD_OXY (abs_depth(xsw_to_bar(msw_or_fsw(6, 20)))) #define RMV_DIVE_DEFAULT 20 #define RMV_DECO_DEFAULT 15 @@ -154,6 +154,7 @@ int main(int argc, char *argv[]) .RMV_DIVE = RMV_DIVE_DEFAULT, .RMV_DECO = RMV_DECO_DEFAULT, .SHOW_TRAVEL = SHOW_TRAVEL_DEFAULT, + .UNITS = UNITS_DEFAULT, }; opendeco_conf_parse("opendeco.toml", &arguments); @@ -166,11 +167,12 @@ int main(int argc, char *argv[]) RMV_DIVE = arguments.RMV_DIVE; RMV_DECO = arguments.RMV_DECO; SHOW_TRAVEL = arguments.SHOW_TRAVEL; + UNITS = arguments.UNITS; /* setup */ decostate_t ds; - init_decostate(&ds, arguments.gflow, arguments.gfhigh, msw_to_bar(3)); - double dec_per_min = msw_to_bar(9); + init_decostate(&ds, arguments.gflow, arguments.gfhigh, xsw_to_bar(msw_or_fsw(3, 10))); + double dec_per_min = xsw_to_bar(msw_or_fsw(9, 30)); gas_t bottom_gas; scan_gas(&bottom_gas, arguments.gas); @@ -184,12 +186,12 @@ int main(int argc, char *argv[]) deco_gasses[i].mod = MOD_OXY; /* simulate dive */ - double descent_time = msw_to_bar(arguments.depth) / dec_per_min; + double descent_time = xsw_to_bar(arguments.depth) / dec_per_min; double bottom_time = max(1, arguments.time - descent_time); waypoint_t waypoints[] = { - {.depth = abs_depth(msw_to_bar(arguments.depth)), .time = descent_time, &bottom_gas}, - {.depth = abs_depth(msw_to_bar(arguments.depth)), .time = bottom_time, &bottom_gas}, + {.depth = abs_depth(xsw_to_bar(arguments.depth)), .time = descent_time, &bottom_gas}, + {.depth = abs_depth(xsw_to_bar(arguments.depth)), .time = bottom_time, &bottom_gas}, }; waypoint_callback_t print_segment_callback = { diff --git a/src/output.c b/src/output.c index 52b45dd..5997f31 100644 --- a/src/output.c +++ b/src/output.c @@ -69,8 +69,8 @@ void print_planline(wchar_t sign, double depth, double time, double runtime, con static gas_t last_gas; - const int depth_m = round(bar_to_msw(gauge_depth(depth))); - const int ead_m = round(bar_to_msw(max(0, gauge_depth(ead(depth, gas))))); + const int depth_x = round(bar_to_xsw(gauge_depth(depth))); + const int ead_x = round(bar_to_xsw(max(0, gauge_depth(ead(depth, gas))))); wchar_t swi = L' '; @@ -86,14 +86,15 @@ void print_planline(wchar_t sign, double depth, double time, double runtime, con /* only print ead and pO2 on stops */ if (sign == LVL) { - snprintf(eadbuf, 4, "%3i", ead_m); + snprintf(eadbuf, 4, "%3i", ead_x); snprintf(pO2buf, 5, "%4.2f", ppO2(depth, gas)); } else { snprintf(eadbuf, 4, "%3s", "-"); snprintf(pO2buf, 5, "%4s", "-"); } - wprintf(L" %lc %4im %8s %-7s %lc %-9s %s %s\n", sign, depth_m, timbuf, runbuf, swi, gasbuf, pO2buf, eadbuf); + wprintf(L" %lc %4i%s %8s %-7s %lc %-9s %s %s\n", sign, depth_x, (UNITS == METRIC) ? "m" : "ft", timbuf, + runbuf, swi, gasbuf, pO2buf, eadbuf); } void print_planfoot(const decostate_t *ds) -- cgit v1.2.3-70-g09d2