Add support for imperial units in the xml output.

Libdivecomputer always uses metric units internally. But when reverse
engineering a device that stores everything using imperial units, it's
very convenient to be able to switch the output to imperial units too.
This commit is contained in:
Jef Driesen 2016-03-27 11:02:53 +02:00
parent 8ab3fb0542
commit 469717a2a1
4 changed files with 98 additions and 15 deletions

View File

@ -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_status_t status = DC_STATUS_SUCCESS;
dc_buffer_t *fingerprint = NULL; dc_buffer_t *fingerprint = NULL;
dctool_output_t *output = NULL; dctool_output_t *output = NULL;
dctool_units_t units = DCTOOL_UNITS_METRIC;
// Default option values. // Default option values.
unsigned int help = 0; 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. // Parse the command-line options.
int opt = 0; int opt = 0;
const char *optstring = "ho:p:c:f:"; const char *optstring = "ho:p:c:f:u:";
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
struct option options[] = { struct option options[] = {
{"help", no_argument, 0, 'h'}, {"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'}, {"fingerprint", required_argument, 0, 'p'},
{"cache", required_argument, 0, 'c'}, {"cache", required_argument, 0, 'c'},
{"format", required_argument, 0, 'f'}, {"format", required_argument, 0, 'f'},
{"units", required_argument, 0, 'u'},
{0, 0, 0, 0 } {0, 0, 0, 0 }
}; };
while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { 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': case 'f':
format = optarg; format = optarg;
break; break;
case 'u':
if (strcmp (optarg, "metric") == 0)
units = DCTOOL_UNITS_METRIC;
if (strcmp (optarg, "imperial") == 0)
units = DCTOOL_UNITS_IMPERIAL;
break;
default: default:
return EXIT_FAILURE; 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) { if (strcasecmp(format, "raw") == 0) {
output = dctool_raw_output_new (filename); output = dctool_raw_output_new (filename);
} else if (strcasecmp(format, "xml") == 0) { } else if (strcasecmp(format, "xml") == 0) {
output = dctool_xml_output_new (filename); output = dctool_xml_output_new (filename, units);
} else { } else {
message ("Unknown output format: %s\n", format); message ("Unknown output format: %s\n", format);
exitcode = EXIT_FAILURE; exitcode = EXIT_FAILURE;
@ -348,12 +356,14 @@ const dctool_command_t dctool_download = {
" -p, --fingerprint <data> Fingerprint data (hexadecimal)\n" " -p, --fingerprint <data> Fingerprint data (hexadecimal)\n"
" -c, --cache <directory> Cache directory\n" " -c, --cache <directory> Cache directory\n"
" -f, --format <format> Output format\n" " -f, --format <format> Output format\n"
" -u, --units <units> Set units (metric or imperial)\n"
#else #else
" -h Show help message\n" " -h Show help message\n"
" -o <filename> Output filename\n" " -o <filename> Output filename\n"
" -p <fingerprint> Fingerprint data (hexadecimal)\n" " -p <fingerprint> Fingerprint data (hexadecimal)\n"
" -c <directory> Cache directory\n" " -c <directory> Cache directory\n"
" -f <format> Output format\n" " -f <format> Output format\n"
" -u <units> Set units (metric or imperial)\n"
#endif #endif
"\n" "\n"
"Supported output formats:\n" "Supported output formats:\n"

View File

@ -26,6 +26,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#ifdef HAVE_GETOPT_H #ifdef HAVE_GETOPT_H
#include <getopt.h> #include <getopt.h>
#endif #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_status_t status = DC_STATUS_SUCCESS;
dc_buffer_t *buffer = NULL; dc_buffer_t *buffer = NULL;
dctool_output_t *output = NULL; dctool_output_t *output = NULL;
dctool_units_t units = DCTOOL_UNITS_METRIC;
// Default option values. // Default option values.
unsigned int help = 0; 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. // Parse the command-line options.
int opt = 0; int opt = 0;
const char *optstring = "ho:d:s:"; const char *optstring = "ho:d:s:u:";
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
struct option options[] = { struct option options[] = {
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{"output", required_argument, 0, 'o'}, {"output", required_argument, 0, 'o'},
{"devtime", required_argument, 0, 'd'}, {"devtime", required_argument, 0, 'd'},
{"systime", required_argument, 0, 's'}, {"systime", required_argument, 0, 's'},
{"units", required_argument, 0, 'u'},
{0, 0, 0, 0 } {0, 0, 0, 0 }
}; };
while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { 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': case 's':
systime = strtoll (optarg, NULL, 0); systime = strtoll (optarg, NULL, 0);
break; break;
case 'u':
if (strcmp (optarg, "metric") == 0)
units = DCTOOL_UNITS_METRIC;
if (strcmp (optarg, "imperial") == 0)
units = DCTOOL_UNITS_IMPERIAL;
break;
default: default:
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -246,7 +255,7 @@ dctool_parse_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t
} }
// Create the output. // Create the output.
output = dctool_xml_output_new (filename); output = dctool_xml_output_new (filename, units);
if (output == NULL) { if (output == NULL) {
message ("Failed to create the output.\n"); message ("Failed to create the output.\n");
exitcode = EXIT_FAILURE; exitcode = EXIT_FAILURE;
@ -295,10 +304,12 @@ const dctool_command_t dctool_parse = {
" -o, --output <filename> Output filename\n" " -o, --output <filename> Output filename\n"
" -d, --devtime <timestamp> Device time\n" " -d, --devtime <timestamp> Device time\n"
" -s, --systime <timestamp> System time\n" " -s, --systime <timestamp> System time\n"
" -u, --units <units> Set units (metric or imperial)\n"
#else #else
" -h Show help message\n" " -h Show help message\n"
" -o <filename> Output filename\n" " -o <filename> Output filename\n"
" -d <devtime> Device time\n" " -d <devtime> Device time\n"
" -s <systime> System time\n" " -s <systime> System time\n"
" -u <units> Set units (metric or imperial)\n"
#endif #endif
}; };

View File

@ -31,8 +31,13 @@ extern "C" {
typedef struct dctool_output_t dctool_output_t; 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_output_t *
dctool_xml_output_new (const char *filename); dctool_xml_output_new (const char *filename, dctool_units_t units);
dctool_output_t * dctool_output_t *
dctool_raw_output_new (const char *template); dctool_raw_output_new (const char *template);

View File

@ -23,6 +23,8 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <libdivecomputer/units.h>
#include "output-private.h" #include "output-private.h"
#include "utils.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 { typedef struct dctool_xml_output_t {
dctool_output_t base; dctool_output_t base;
FILE *ostream; FILE *ostream;
dctool_units_t units;
} dctool_xml_output_t; } dctool_xml_output_t;
static const dctool_output_vtable_t xml_vtable = { 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 { typedef struct sample_data_t {
FILE *ostream; FILE *ostream;
dctool_units_t units;
unsigned int nsamples; unsigned int nsamples;
} sample_data_t; } 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 static void
sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata) 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, " <time>%02u:%02u</time>\n", value.time / 60, value.time % 60); fprintf (sampledata->ostream, " <time>%02u:%02u</time>\n", value.time / 60, value.time % 60);
break; break;
case DC_SAMPLE_DEPTH: case DC_SAMPLE_DEPTH:
fprintf (sampledata->ostream, " <depth>%.2f</depth>\n", value.depth); fprintf (sampledata->ostream, " <depth>%.2f</depth>\n",
convert_depth(value.depth, sampledata->units));
break; break;
case DC_SAMPLE_PRESSURE: case DC_SAMPLE_PRESSURE:
fprintf (sampledata->ostream, " <pressure tank=\"%u\">%.2f</pressure>\n", value.pressure.tank, value.pressure.value); fprintf (sampledata->ostream, " <pressure tank=\"%u\">%.2f</pressure>\n",
value.pressure.tank,
convert_pressure(value.pressure.value, sampledata->units));
break; break;
case DC_SAMPLE_TEMPERATURE: case DC_SAMPLE_TEMPERATURE:
fprintf (sampledata->ostream, " <temperature>%.2f</temperature>\n", value.temperature); fprintf (sampledata->ostream, " <temperature>%.2f</temperature>\n",
convert_temperature(value.temperature, sampledata->units));
break; break;
case DC_SAMPLE_EVENT: case DC_SAMPLE_EVENT:
if (value.event.type != SAMPLE_EVENT_GASCHANGE && value.event.type != SAMPLE_EVENT_GASCHANGE2) { 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; break;
case DC_SAMPLE_DECO: case DC_SAMPLE_DECO:
fprintf (sampledata->ostream, " <deco time=\"%u\" depth=\"%.2f\">%s</deco>\n", fprintf (sampledata->ostream, " <deco time=\"%u\" depth=\"%.2f\">%s</deco>\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; break;
case DC_SAMPLE_GASMIX: case DC_SAMPLE_GASMIX:
fprintf (sampledata->ostream, " <gasmix>%u</gasmix>\n", value.gasmix); fprintf (sampledata->ostream, " <gasmix>%u</gasmix>\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_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; dctool_xml_output_t *output = NULL;
@ -138,6 +188,8 @@ dctool_xml_output_new (const char *filename)
goto error_free; goto error_free;
} }
output->units = units;
fprintf (output->ostream, "<device>\n"); fprintf (output->ostream, "<device>\n");
return (dctool_output_t *) output; return (dctool_output_t *) output;
@ -158,6 +210,7 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
sample_data_t sampledata = {0}; sample_data_t sampledata = {0};
sampledata.nsamples = 0; sampledata.nsamples = 0;
sampledata.ostream = output->ostream; sampledata.ostream = output->ostream;
sampledata.units = output->units;
fprintf (output->ostream, "<dive>\n<number>%u</number>\n<size>%u</size>\n", abstract->number, size); fprintf (output->ostream, "<dive>\n<number>%u</number>\n<size>%u</size>\n", abstract->number, size);
@ -203,7 +256,7 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
} }
fprintf (output->ostream, "<maxdepth>%.2f</maxdepth>\n", fprintf (output->ostream, "<maxdepth>%.2f</maxdepth>\n",
maxdepth); convert_depth(maxdepth, output->units));
// Parse the temperature. // Parse the temperature.
message ("Parsing the temperature.\n"); message ("Parsing the temperature.\n");
@ -222,7 +275,8 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
if (status != DC_STATUS_UNSUPPORTED) { if (status != DC_STATUS_UNSUPPORTED) {
fprintf (output->ostream, "<temperature type=\"%s\">%.1f</temperature>\n", fprintf (output->ostream, "<temperature type=\"%s\">%.1f</temperature>\n",
names[i], temperature); names[i],
convert_temperature(temperature, output->units));
} }
} }
@ -284,13 +338,16 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
" <type>%s</type>\n" " <type>%s</type>\n"
" <volume>%.1f</volume>\n" " <volume>%.1f</volume>\n"
" <workpressure>%.2f</workpressure>\n", " <workpressure>%.2f</workpressure>\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, fprintf (output->ostream,
" <beginpressure>%.2f</beginpressure>\n" " <beginpressure>%.2f</beginpressure>\n"
" <endpressure>%.2f</endpressure>\n" " <endpressure>%.2f</endpressure>\n"
"</tank>\n", "</tank>\n",
tank.beginpressure, tank.endpressure); convert_pressure(tank.beginpressure, output->units),
convert_pressure(tank.endpressure, output->units));
} }
// Parse the dive mode. // Parse the dive mode.
@ -333,7 +390,7 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
if (status != DC_STATUS_UNSUPPORTED) { if (status != DC_STATUS_UNSUPPORTED) {
fprintf (output->ostream, "<atmospheric>%.5f</atmospheric>\n", fprintf (output->ostream, "<atmospheric>%.5f</atmospheric>\n",
atmospheric); convert_pressure(atmospheric, output->units));
} }
// Parse the sample data. // Parse the sample data.