aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/opendeco.c
diff options
context:
space:
mode:
Diffstat (limited to 'opendeco.c')
-rw-r--r--opendeco.c156
1 files changed, 143 insertions, 13 deletions
diff --git a/opendeco.c b/opendeco.c
index 59c9892..7047e8f 100644
--- a/opendeco.c
+++ b/opendeco.c
@@ -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));