diff options
Diffstat (limited to 'opendeco.c')
-rw-r--r-- | opendeco.c | 156 |
1 files changed, 143 insertions, 13 deletions
@@ -1,7 +1,10 @@ /* SPDX-License-Identifier: MIT-0 */ +#include <argp.h> #include <locale.h> #include <math.h> +#include <stdlib.h> +#include <string.h> #include <wchar.h> #include "deco.h" @@ -10,6 +13,77 @@ #define MOD_OXY (abs_depth(msw_to_bar(6))) +#ifndef VERSION +#define VERSION "unknown version" +#endif + +/* argp settings */ +static char args_doc[] = ""; +static char doc[] = "Implementation of Buhlmann ZH-L16 with Gradient Factors:" + "\vExamples:\n\n" + "\t./opendeco -d 18 -t 60 -g Air\n" + "\t./opendeco -d 30 -t 60 -g EAN32\n" + "\t./opendeco -d 40 -t 120 -g 21/35 -l 20 -h 80 --decogasses Oxygen,EAN50\n"; +const char *argp_program_bug_address = "<~tsegers/opendeco@lists.sr.ht>"; +const char *argp_program_version = "opendeco " VERSION; + +static struct argp_option options[] = { + {"depth", 'd', "NUMBER", 0, "Set the depth of the dive in meters", 0}, + {"time", 't', "NUMBER", 0, "Set the time of the dive in minutes", 1}, + {"gas", 'g', "STRING", 0, "Set the bottom gas used during the dive, defaults to Air", 2}, + {"gflow", 'l', "NUMBER", 0, "Set the gradient factor at the first stop, defaults to 30", 3}, + {"gfhigh", 'h', "NUMBER", 0, "Set the gradient factor at the surface, defaults to 75", 4}, + {"decogasses", 'G', "LIST", 0, "Set the gasses available for deco", 5}, + {0, 0, 0, 0, 0, 0} +}; + +struct arguments { + double depth; + double time; + char *gas; + int gflow; + int gfhigh; + char *decogasses; +}; + +static error_t parse_opt(int key, char *arg, struct argp_state *state) +{ + struct arguments *arguments = state->input; + + switch (key) { + case 'd': + arguments->depth = arg ? atof(arg) : 0; + break; + case 't': + arguments->time = arg ? atof(arg) : 0; + break; + case 'g': + arguments->gas = arg; + break; + case 'G': + arguments->decogasses = arg; + break; + case 'l': + arguments->gflow = arg ? atoi(arg) : 100; + break; + case 'h': + arguments->gfhigh = arg ? atoi(arg) : 100; + break; + case ARGP_KEY_END: + if (arguments->depth == 0 || arguments->time == 0) { + argp_state_help(state, stderr, ARGP_HELP_USAGE); + argp_failure(state, 1, 0, "Options -d and -t are required. See --help for more information"); + exit(ARGP_ERR_UNKNOWN); + } + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +static struct argp argp = {options, parse_opt, args_doc, doc, 0, 0, 0}; + void print_segment_callback(const decostate_t *ds, const waypoint_t wp, segtype_t type) { static double last_depth; @@ -32,20 +106,82 @@ void print_segment_callback(const decostate_t *ds, const waypoint_t wp, segtype_ last_depth = wp.depth; } -int main(int argc, const char *argv[]) +int parse_gasses(gas_t **gasses, char *str) +{ + if (!str) { + *gasses = NULL; + return 0; + } + + /* count number of gasses in string */ + int nof_gasses = 1; + + for (int c = 0; str[c]; c++) + if (str[c] == ',') + nof_gasses++; + + /* allocate gas array */ + gas_t *deco_gasses = malloc(nof_gasses * sizeof(gas_t)); + + /* fill gas array */ + char *gas_str = NULL; + int gas_idx = 0; + + while (1) { + if (!gas_str) + gas_str = strtok(str, ","); + else + gas_str = strtok(NULL, ","); + + if (!gas_str) + break; + + scan_gas(&deco_gasses[gas_idx], gas_str); + gas_idx++; + } + + *gasses = deco_gasses; + return nof_gasses; +} + +int main(int argc, char *argv[]) { setlocale(LC_ALL, "en_US.utf8"); + /* argp */ + struct arguments arguments; + + arguments.depth = 0; + arguments.time = 0; + arguments.gas = "Air"; + arguments.gflow = 30; + arguments.gfhigh = 75; + arguments.decogasses = ""; + + argp_parse(&argp, argc, argv, 0, 0, &arguments); + /* setup */ decostate_t ds; - init_decostate(&ds, 30, 75, msw_to_bar(3)); + init_decostate(&ds, arguments.gflow, arguments.gfhigh, msw_to_bar(3)); + double dec_per_min = msw_to_bar(9); + + gas_t bottom_gas; + scan_gas(&bottom_gas, arguments.gas); + + gas_t *deco_gasses; + int nof_gasses = parse_gasses(&deco_gasses, arguments.decogasses); - const gas_t ean32 = gas_new(32, 0, MOD_AUTO); + /* override oxygen mod */ + for (int i = 0; i < nof_gasses; i++) + if (gas_o2(&deco_gasses[i]) == 100) + deco_gasses[i].mod = MOD_OXY; /* simulate dive */ + double descent_time = msw_to_bar(arguments.depth) / dec_per_min; + waypoint_t waypoints[] = { - {.depth = abs_depth(msw_to_bar(30)), .time = 3.333, &ean32}, - {.depth = abs_depth(msw_to_bar(30)), .time = 116.666, &ean32}, + {.depth = abs_depth(msw_to_bar(arguments.depth)), .time = descent_time, &bottom_gas}, + {.depth = abs_depth(msw_to_bar(arguments.depth)), .time = arguments.time - descent_time, &bottom_gas}, }; print_planhead(); @@ -55,19 +191,13 @@ int main(int argc, const char *argv[]) double depth = waypoints[len(waypoints) - 1].depth; const gas_t *gas = waypoints[len(waypoints) - 1].gas; - gas_t deco_gasses[] = { - /* gas_new(40, 0, MOD_AUTO), */ - gas_new(50, 0, MOD_AUTO), - /* gas_new(100, 0, MOD_OXY), */ - }; - /* determine @+5 TTS */ decostate_t ds_ = ds; add_segment_const(&ds_, depth, 5, gas); - decoinfo_t di_plus5 = calc_deco(&ds_, depth, gas, deco_gasses, len(deco_gasses), NULL); + decoinfo_t di_plus5 = calc_deco(&ds_, depth, gas, deco_gasses, nof_gasses, NULL); /* print actual deco schedule */ - decoinfo_t di = calc_deco(&ds, depth, gas, deco_gasses, len(deco_gasses), &print_segment_callback); + decoinfo_t di = calc_deco(&ds, depth, gas, deco_gasses, nof_gasses, &print_segment_callback); /* output deco info and disclaimer */ wprintf(L"\nNDL: %i TTS: %i TTS @+5: %i\n", (int) floor(di.ndl), (int) ceil(di.tts), (int) ceil(di_plus5.tts)); |