diff --git a/examples/dctool_download.c b/examples/dctool_download.c index 4baa333..2c8f43d 100644 --- a/examples/dctool_download.c +++ b/examples/dctool_download.c @@ -246,6 +246,7 @@ dctool_download_run (int argc, char *argv[], dc_context_t *context, dc_descripto dc_status_t status = DC_STATUS_SUCCESS; dc_buffer_t *fingerprint = NULL; dctool_output_t *output = NULL; + dctool_units_t units = DCTOOL_UNITS_METRIC; // Default option values. unsigned int help = 0; @@ -256,7 +257,7 @@ dctool_download_run (int argc, char *argv[], dc_context_t *context, dc_descripto // Parse the command-line options. int opt = 0; - const char *optstring = "ho:p:c:f:"; + const char *optstring = "ho:p:c:f:u:"; #ifdef HAVE_GETOPT_LONG struct option options[] = { {"help", no_argument, 0, 'h'}, @@ -264,6 +265,7 @@ dctool_download_run (int argc, char *argv[], dc_context_t *context, dc_descripto {"fingerprint", required_argument, 0, 'p'}, {"cache", required_argument, 0, 'c'}, {"format", required_argument, 0, 'f'}, + {"units", required_argument, 0, 'u'}, {0, 0, 0, 0 } }; while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { @@ -286,6 +288,12 @@ dctool_download_run (int argc, char *argv[], dc_context_t *context, dc_descripto case 'f': format = optarg; break; + case 'u': + if (strcmp (optarg, "metric") == 0) + units = DCTOOL_UNITS_METRIC; + if (strcmp (optarg, "imperial") == 0) + units = DCTOOL_UNITS_IMPERIAL; + break; default: return EXIT_FAILURE; } @@ -307,7 +315,7 @@ dctool_download_run (int argc, char *argv[], dc_context_t *context, dc_descripto if (strcasecmp(format, "raw") == 0) { output = dctool_raw_output_new (filename); } else if (strcasecmp(format, "xml") == 0) { - output = dctool_xml_output_new (filename); + output = dctool_xml_output_new (filename, units); } else { message ("Unknown output format: %s\n", format); exitcode = EXIT_FAILURE; @@ -348,12 +356,14 @@ const dctool_command_t dctool_download = { " -p, --fingerprint Fingerprint data (hexadecimal)\n" " -c, --cache Cache directory\n" " -f, --format Output format\n" + " -u, --units Set units (metric or imperial)\n" #else " -h Show help message\n" " -o Output filename\n" " -p Fingerprint data (hexadecimal)\n" " -c Cache directory\n" " -f Output format\n" + " -u Set units (metric or imperial)\n" #endif "\n" "Supported output formats:\n" diff --git a/examples/dctool_parse.c b/examples/dctool_parse.c index ef05aa4..5057566 100644 --- a/examples/dctool_parse.c +++ b/examples/dctool_parse.c @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef HAVE_GETOPT_H #include #endif @@ -196,6 +197,7 @@ dctool_parse_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t dc_status_t status = DC_STATUS_SUCCESS; dc_buffer_t *buffer = NULL; dctool_output_t *output = NULL; + dctool_units_t units = DCTOOL_UNITS_METRIC; // Default option values. unsigned int help = 0; @@ -205,13 +207,14 @@ dctool_parse_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t // Parse the command-line options. int opt = 0; - const char *optstring = "ho:d:s:"; + const char *optstring = "ho:d:s:u:"; #ifdef HAVE_GETOPT_LONG struct option options[] = { {"help", no_argument, 0, 'h'}, {"output", required_argument, 0, 'o'}, {"devtime", required_argument, 0, 'd'}, {"systime", required_argument, 0, 's'}, + {"units", required_argument, 0, 'u'}, {0, 0, 0, 0 } }; while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { @@ -231,6 +234,12 @@ dctool_parse_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t case 's': systime = strtoll (optarg, NULL, 0); break; + case 'u': + if (strcmp (optarg, "metric") == 0) + units = DCTOOL_UNITS_METRIC; + if (strcmp (optarg, "imperial") == 0) + units = DCTOOL_UNITS_IMPERIAL; + break; default: return EXIT_FAILURE; } @@ -246,7 +255,7 @@ dctool_parse_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t } // Create the output. - output = dctool_xml_output_new (filename); + output = dctool_xml_output_new (filename, units); if (output == NULL) { message ("Failed to create the output.\n"); exitcode = EXIT_FAILURE; @@ -295,10 +304,12 @@ const dctool_command_t dctool_parse = { " -o, --output Output filename\n" " -d, --devtime Device time\n" " -s, --systime System time\n" + " -u, --units Set units (metric or imperial)\n" #else " -h Show help message\n" " -o Output filename\n" " -d Device time\n" " -s System time\n" + " -u Set units (metric or imperial)\n" #endif }; diff --git a/examples/output.h b/examples/output.h index 0912de2..b22a8f2 100644 --- a/examples/output.h +++ b/examples/output.h @@ -31,8 +31,13 @@ extern "C" { typedef struct dctool_output_t dctool_output_t; +typedef enum dctool_units_t { + DCTOOL_UNITS_METRIC, + DCTOOL_UNITS_IMPERIAL +} dctool_units_t; + dctool_output_t * -dctool_xml_output_new (const char *filename); +dctool_xml_output_new (const char *filename, dctool_units_t units); dctool_output_t * dctool_raw_output_new (const char *template); diff --git a/examples/output_xml.c b/examples/output_xml.c index a36e62a..2baa329 100644 --- a/examples/output_xml.c +++ b/examples/output_xml.c @@ -23,6 +23,8 @@ #include #include +#include + #include "output-private.h" #include "utils.h" @@ -32,6 +34,7 @@ static dc_status_t dctool_xml_output_free (dctool_output_t *output); typedef struct dctool_xml_output_t { dctool_output_t base; FILE *ostream; + dctool_units_t units; } dctool_xml_output_t; static const dctool_output_vtable_t xml_vtable = { @@ -42,9 +45,50 @@ static const dctool_output_vtable_t xml_vtable = { typedef struct sample_data_t { FILE *ostream; + dctool_units_t units; unsigned int nsamples; } sample_data_t; +static double +convert_depth (double value, dctool_units_t units) +{ + if (units == DCTOOL_UNITS_IMPERIAL) { + return value / FEET; + } else { + return value; + } +} + +static double +convert_temperature (double value, dctool_units_t units) +{ + if (units == DCTOOL_UNITS_IMPERIAL) { + return value * (9.0 / 5.0) + 32.0; + } else { + return value; + } +} + +static double +convert_pressure (double value, dctool_units_t units) +{ + if (units == DCTOOL_UNITS_IMPERIAL) { + return value * BAR / PSI; + } else { + return value; + } +} + +static double +convert_volume (double value, dctool_units_t units) +{ + if (units == DCTOOL_UNITS_IMPERIAL) { + return value / 1000.0 / CUFT; + } else { + return value; + } +} + static void sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata) { @@ -68,13 +112,17 @@ sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata) fprintf (sampledata->ostream, " \n", value.time / 60, value.time % 60); break; case DC_SAMPLE_DEPTH: - fprintf (sampledata->ostream, " %.2f\n", value.depth); + fprintf (sampledata->ostream, " %.2f\n", + convert_depth(value.depth, sampledata->units)); break; case DC_SAMPLE_PRESSURE: - fprintf (sampledata->ostream, " %.2f\n", value.pressure.tank, value.pressure.value); + fprintf (sampledata->ostream, " %.2f\n", + value.pressure.tank, + convert_pressure(value.pressure.value, sampledata->units)); break; case DC_SAMPLE_TEMPERATURE: - fprintf (sampledata->ostream, " %.2f\n", value.temperature); + fprintf (sampledata->ostream, " %.2f\n", + convert_temperature(value.temperature, sampledata->units)); break; case DC_SAMPLE_EVENT: if (value.event.type != SAMPLE_EVENT_GASCHANGE && value.event.type != SAMPLE_EVENT_GASCHANGE2) { @@ -108,7 +156,9 @@ sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata) break; case DC_SAMPLE_DECO: fprintf (sampledata->ostream, " %s\n", - value.deco.time, value.deco.depth, decostop[value.deco.type]); + value.deco.time, + convert_depth(value.deco.depth, sampledata->units), + decostop[value.deco.type]); break; case DC_SAMPLE_GASMIX: fprintf (sampledata->ostream, " %u\n", value.gasmix); @@ -119,7 +169,7 @@ sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata) } dctool_output_t * -dctool_xml_output_new (const char *filename) +dctool_xml_output_new (const char *filename, dctool_units_t units) { dctool_xml_output_t *output = NULL; @@ -138,6 +188,8 @@ dctool_xml_output_new (const char *filename) goto error_free; } + output->units = units; + fprintf (output->ostream, "\n"); return (dctool_output_t *) output; @@ -154,6 +206,12 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u dctool_xml_output_t *output = (dctool_xml_output_t *) abstract; dc_status_t status = DC_STATUS_SUCCESS; + // Initialize the sample data. + sample_data_t sampledata = {0}; + sampledata.nsamples = 0; + sampledata.ostream = output->ostream; + sampledata.units = output->units; + fprintf (output->ostream, "\n%u\n%u\n", abstract->number, size); if (fingerprint) { @@ -198,7 +256,7 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u } fprintf (output->ostream, "%.2f\n", - maxdepth); + convert_depth(maxdepth, output->units)); // Parse the temperature. message ("Parsing the temperature.\n"); @@ -217,7 +275,8 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u if (status != DC_STATUS_UNSUPPORTED) { fprintf (output->ostream, "%.1f\n", - names[i], temperature); + names[i], + convert_temperature(temperature, output->units)); } } @@ -279,13 +338,16 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u " %s\n" " %.1f\n" " %.2f\n", - names[tank.type], tank.volume, tank.workpressure); + names[tank.type], + convert_volume(tank.volume, output->units), + convert_pressure(tank.workpressure, output->units)); } fprintf (output->ostream, " %.2f\n" " %.2f\n" "\n", - tank.beginpressure, tank.endpressure); + convert_pressure(tank.beginpressure, output->units), + convert_pressure(tank.endpressure, output->units)); } // Parse the dive mode. @@ -328,14 +390,9 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u if (status != DC_STATUS_UNSUPPORTED) { fprintf (output->ostream, "%.5f\n", - atmospheric); + convert_pressure(atmospheric, output->units)); } - // Initialize the sample data. - sample_data_t sampledata = {0}; - sampledata.nsamples = 0; - sampledata.ostream = output->ostream; - // Parse the sample data. message ("Parsing the sample data.\n"); status = dc_parser_samples_foreach (parser, sample_cb, &sampledata); @@ -344,11 +401,12 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u goto cleanup; } +cleanup: + if (sampledata.nsamples) fprintf (output->ostream, "\n"); fprintf (output->ostream, "\n"); -cleanup: return status; } diff --git a/src/descriptor.c b/src/descriptor.c index bf310a1..af15103 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -184,6 +184,7 @@ static const dc_descriptor_t g_descriptors[] = { {"Aeris", "A300CS", DC_FAMILY_OCEANIC_ATOM2, 0x454C}, {"Oceanic", "F11", DC_FAMILY_OCEANIC_ATOM2, 0x4554}, {"Oceanic", "VTX", DC_FAMILY_OCEANIC_ATOM2, 0x4557}, + {"Aqualung", "i450T", DC_FAMILY_OCEANIC_ATOM2, 0x4641}, /* Mares Nemo */ {"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0}, {"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0}, @@ -228,6 +229,7 @@ static const dc_descriptor_t g_descriptors[] = { /* Cressi Leonardo */ {"Cressi", "Leonardo", DC_FAMILY_CRESSI_LEONARDO, 1}, {"Cressi", "Giotto", DC_FAMILY_CRESSI_LEONARDO, 4}, + {"Cressi", "Newton", DC_FAMILY_CRESSI_LEONARDO, 5}, /* Zeagle N2iTiON3 */ {"Zeagle", "N2iTiON3", DC_FAMILY_ZEAGLE_N2ITION3, 0}, {"Apeks", "Quantum X", DC_FAMILY_ZEAGLE_N2ITION3, 0}, diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 67fa45a..3bd81db 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -180,6 +180,10 @@ static const oceanic_common_version_t aeris_a300cs_version[] = { {"OCEANVTX \0\0 2048"}, }; +static const oceanic_common_version_t aqualung_i450t_version[] = { + {"AQUAI450 \0\0 2048"}, +}; + static const oceanic_common_layout_t aeris_f10_layout = { 0x10000, /* memsize */ 0x0000, /* cf_devinfo */ @@ -401,6 +405,18 @@ static const oceanic_common_layout_t aeris_a300cs_layout = { 1 /* pt_mode_logbook */ }; +static const oceanic_common_layout_t aqualung_i450t_layout = { + 0x40000, /* memsize */ + 0x0000, /* cf_devinfo */ + 0x0040, /* cf_pointers */ + 0x10C0, /* rb_logbook_begin */ + 0x1400, /* rb_logbook_end */ + 16, /* rb_logbook_entry_size */ + 0x1400, /* rb_profile_begin */ + 0x3FE00, /* rb_profile_end */ + 0, /* pt_mode_global */ + 1 /* pt_mode_logbook */ +}; static dc_status_t oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int crc_size) @@ -634,6 +650,8 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char } else if (OCEANIC_COMMON_MATCH (device->base.version, aeris_a300cs_version)) { device->base.layout = &aeris_a300cs_layout; device->bigpage = 16; + } else if (OCEANIC_COMMON_MATCH (device->base.version, aqualung_i450t_version)) { + device->base.layout = &aqualung_i450t_layout; } else { device->base.layout = &oceanic_default_layout; } diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 5de8c7c..485bcbd 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -77,6 +77,7 @@ #define A300CS 0x454C #define F11B 0x4554 #define VTX 0x4557 +#define I450T 0x4641 #define NORMAL 0 #define GAUGE 1 @@ -161,7 +162,7 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned } else if (model == F11A || model == F11B) { parser->headersize = 5 * PAGESIZE; parser->footersize = 0; - } else if (model == A300CS || model == VTX) { + } else if (model == A300CS || model == VTX || model == I450T) { parser->headersize = 5 * PAGESIZE; } @@ -287,6 +288,7 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim break; case A300CS: case VTX: + case I450T: datetime->year = (p[10]) + 2000; datetime->month = (p[8]); datetime->day = (p[9]); @@ -412,6 +414,9 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser) } else { ngasmixes = 4; } + } else if (parser->model == I450T) { + o2_offset = 0x30; + ngasmixes = 3; } else { o2_offset = header + 4; ngasmixes = 3; @@ -616,7 +621,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ } else if (parser->model == OC1A || parser->model == OC1B || parser->model == OC1C || parser->model == OCI || parser->model == TX1 || parser->model == A300CS || - parser->model == VTX) { + parser->model == VTX || parser->model == I450T) { samplesize = PAGESIZE; } @@ -741,7 +746,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ } else if (parser->model == GEO20 || parser->model == VEO20 || parser->model == VEO30 || parser->model == OC1A || parser->model == OC1B || parser->model == OC1C || - parser->model == OCI || parser->model == A300) { + parser->model == OCI || parser->model == A300 || + parser->model == I450T) { temperature = data[offset + 3]; } else if (parser->model == OCS || parser->model == TX1) { temperature = data[offset + 1]; @@ -775,7 +781,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ // Tank Pressure (psi) if (have_pressure) { if (parser->model == OC1A || parser->model == OC1B || - parser->model == OC1C || parser->model == OCI) + parser->model == OC1C || parser->model == OCI || + parser->model == I450T) pressure = (data[offset + 10] + (data[offset + 11] << 8)) & 0x0FFF; else if (parser->model == VT4 || parser->model == VT41|| parser->model == ATOM3 || parser->model == ATOM31 || @@ -799,7 +806,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ else if (parser->model == GEO20 || parser->model == VEO20 || parser->model == VEO30 || parser->model == OC1A || parser->model == OC1B || parser->model == OC1C || - parser->model == OCI || parser->model == A300) + parser->model == OCI || parser->model == A300 || + parser->model == I450T) depth = (data[offset + 4] + (data[offset + 5] << 8)) & 0x0FFF; else if (parser->model == ATOM1) depth = data[offset + 3] * 16; @@ -837,7 +845,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ // NDL / Deco unsigned int have_deco = 0; unsigned int decostop = 0, decotime = 0; - if (parser->model == A300CS || parser->model == VTX) { + if (parser->model == A300CS || parser->model == VTX || parser->model == I450T) { decostop = (data[offset + 15] & 0x70) >> 4; decotime = array_uint16_le(data + offset + 6) & 0x03FF; have_deco = 1;