Compare commits
112 Commits
Subsurface
...
v4.6.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca04147126 | ||
|
|
71cf0a5c69 | ||
|
|
3f74840f4c | ||
|
|
2e650b68ae | ||
|
|
6fccf5923f | ||
|
|
a6421b2f7b | ||
|
|
19b560d9b2 | ||
|
|
534dd2f34b | ||
|
|
4ec7283841 | ||
|
|
11fec04865 | ||
|
|
af84bd10fd | ||
|
|
a568c756a1 | ||
|
|
3ea2795bf1 | ||
|
|
89111ebb2a | ||
|
|
a6538ae7da | ||
|
|
f7d2086675 | ||
|
|
4c5b51f851 | ||
|
|
20d268acdb | ||
|
|
94e7a77d01 | ||
|
|
7e086f697d | ||
|
|
f9db4ca97c | ||
|
|
ed8b8f1221 | ||
|
|
6fa9f1566f | ||
|
|
d11d30999b | ||
|
|
cba786df2f | ||
|
|
4527c77a6b | ||
|
|
406dbf3dae | ||
|
|
8fb4018db3 | ||
|
|
8eb1c1232e | ||
|
|
7fe87f36b5 | ||
|
|
4599405078 | ||
|
|
69d26e00b0 | ||
|
|
5d4e1f97db | ||
|
|
3547c72111 | ||
|
|
1b5ccf5983 | ||
|
|
79e2e3b0b5 | ||
|
|
2e26ae4708 | ||
|
|
f38e8fe9ee | ||
|
|
0aeae321dc | ||
|
|
de7ed23bec | ||
|
|
341b7c2dad | ||
|
|
26b027cad8 | ||
|
|
5361bc06bd | ||
|
|
87facc940b | ||
|
|
bdc1c1349e | ||
|
|
f67bdcd080 | ||
|
|
2015546952 | ||
|
|
480e54ace7 | ||
|
|
ecebda3b19 | ||
|
|
6c6752d87e | ||
|
|
8356e22e61 | ||
|
|
515dc17914 | ||
|
|
cb0584adc1 | ||
|
|
f37b4b06db | ||
|
|
aa2f670224 | ||
|
|
af30fbb3f8 | ||
|
|
b13d8da426 | ||
|
|
7f6348b066 | ||
|
|
95d69ea30d | ||
|
|
cc12560b29 | ||
|
|
784844d8dd | ||
|
|
2fc31b72e7 | ||
|
|
2e0db552ad | ||
|
|
6bb60bba31 | ||
|
|
28f8cf6e19 | ||
|
|
55a44a73bb | ||
|
|
7c33c633fb | ||
|
|
e227a4c5a7 | ||
|
|
8bb373e514 | ||
|
|
290f2781ea | ||
|
|
4f321aef40 | ||
|
|
92a1919cf5 | ||
|
|
2106cb2dab | ||
|
|
854f58fa32 | ||
|
|
058538e628 | ||
|
|
138fd856bd | ||
|
|
1ccf937aa3 | ||
|
|
da0073c971 | ||
|
|
8932b2a936 | ||
|
|
9c7d1102d4 | ||
|
|
ad4bcffa23 | ||
|
|
f103553df1 | ||
|
|
a6274a3a55 | ||
|
|
adfff2d4a7 | ||
|
|
f0e695b089 | ||
|
|
fe2448e34f | ||
|
|
7fd201a400 | ||
|
|
c39dda89bc | ||
|
|
0c8886ce70 | ||
|
|
53ccc4f43b | ||
|
|
8c3e44aa0c | ||
|
|
5dbaa7a053 | ||
|
|
69bd993233 | ||
|
|
a50a1e0688 | ||
|
|
b9e3f40d59 | ||
|
|
f184b45e09 | ||
|
|
0ff1dd15f5 | ||
|
|
fb15ef18f6 | ||
|
|
3a17156be6 | ||
|
|
1f24f67565 | ||
|
|
5ecc65799c | ||
|
|
ddfdb6c306 | ||
|
|
b85f2333be | ||
|
|
06426af656 | ||
|
|
f459155b54 | ||
|
|
ebe6704747 | ||
|
|
5f76249923 | ||
|
|
0ddec2b50f | ||
|
|
8f4038d4cd | ||
|
|
d90417da38 | ||
|
|
f902f5882c | ||
|
|
eac8e98ee7 |
@ -2,7 +2,7 @@
|
||||
m4_define([dc_version_major],[0])
|
||||
m4_define([dc_version_minor],[6])
|
||||
m4_define([dc_version_micro],[0])
|
||||
m4_define([dc_version_suffix],[devel])
|
||||
m4_define([dc_version_suffix],[devel-Subsurface-branch])
|
||||
m4_define([dc_version],dc_version_major.dc_version_minor.dc_version_micro[]m4_ifset([dc_version_suffix],-[dc_version_suffix]))
|
||||
|
||||
# Libtool versioning.
|
||||
|
||||
@ -393,6 +393,24 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
||||
convert_pressure(atmospheric, output->units));
|
||||
}
|
||||
|
||||
message ("Parsing strings.\n");
|
||||
int idx;
|
||||
for (idx = 0; idx < 100; idx++) {
|
||||
dc_field_string_t str = { NULL };
|
||||
status = dc_parser_get_field(parser, DC_FIELD_STRING, idx, &str);
|
||||
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
|
||||
ERROR ("Error parsing strings");
|
||||
goto cleanup;
|
||||
}
|
||||
if (status == DC_STATUS_UNSUPPORTED)
|
||||
break;
|
||||
if (!str.desc || !str.value)
|
||||
break;
|
||||
fprintf (output->ostream, "<extradata key='%s' value='%s' />\n",
|
||||
str.desc, str.value);
|
||||
|
||||
}
|
||||
|
||||
// Parse the sample data.
|
||||
message ("Parsing the sample data.\n");
|
||||
status = dc_parser_samples_foreach (parser, sample_cb, &sampledata);
|
||||
|
||||
@ -3,6 +3,7 @@ libdivecomputer_HEADERS = \
|
||||
version.h \
|
||||
common.h \
|
||||
context.h \
|
||||
custom_serial.h \
|
||||
buffer.h \
|
||||
descriptor.h \
|
||||
iterator.h \
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#define DC_CONTEXT_H
|
||||
|
||||
#include "common.h"
|
||||
#include "custom_serial.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -47,6 +48,9 @@ dc_context_new (dc_context_t **context);
|
||||
dc_status_t
|
||||
dc_context_free (dc_context_t *context);
|
||||
|
||||
dc_status_t
|
||||
dc_context_set_custom_serial (dc_context_t *context, dc_custom_serial_t *custom_serial);
|
||||
|
||||
dc_status_t
|
||||
dc_context_set_loglevel (dc_context_t *context, dc_loglevel_t loglevel);
|
||||
|
||||
|
||||
90
include/libdivecomputer/custom_serial.h
Normal file
90
include/libdivecomputer/custom_serial.h
Normal file
@ -0,0 +1,90 @@
|
||||
#ifndef CUSTOM_SERIAL_H
|
||||
#define CUSTOM_SERIAL_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// Verbatim copy from src/serial.h
|
||||
|
||||
#ifndef __SERIAL_TYPES__
|
||||
#define __SERIAL_TYPES__
|
||||
// Don't re-declare when we're internal
|
||||
/**
|
||||
* The parity checking scheme.
|
||||
*/
|
||||
typedef enum dc_parity_t {
|
||||
DC_PARITY_NONE, /**< No parity */
|
||||
DC_PARITY_ODD, /**< Odd parity */
|
||||
DC_PARITY_EVEN, /**< Even parity */
|
||||
DC_PARITY_MARK, /**< Mark parity (always 1) */
|
||||
DC_PARITY_SPACE /**< Space parity (alwasy 0) */
|
||||
} dc_parity_t;
|
||||
|
||||
/**
|
||||
* The number of stop bits.
|
||||
*/
|
||||
typedef enum dc_stopbits_t {
|
||||
DC_STOPBITS_ONE, /**< 1 stop bit */
|
||||
DC_STOPBITS_ONEPOINTFIVE, /**< 1.5 stop bits*/
|
||||
DC_STOPBITS_TWO /**< 2 stop bits */
|
||||
} dc_stopbits_t;
|
||||
|
||||
/**
|
||||
* The flow control.
|
||||
*/
|
||||
typedef enum dc_flowcontrol_t {
|
||||
DC_FLOWCONTROL_NONE, /**< No flow control */
|
||||
DC_FLOWCONTROL_HARDWARE, /**< Hardware (RTS/CTS) flow control */
|
||||
DC_FLOWCONTROL_SOFTWARE /**< Software (XON/XOFF) flow control */
|
||||
} dc_flowcontrol_t;
|
||||
|
||||
/**
|
||||
* The direction of the data transmission.
|
||||
*/
|
||||
typedef enum dc_direction_t {
|
||||
DC_DIRECTION_INPUT = 0x01, /**< Input direction */
|
||||
DC_DIRECTION_OUTPUT = 0x02, /**< Output direction */
|
||||
DC_DIRECTION_ALL = DC_DIRECTION_INPUT | DC_DIRECTION_OUTPUT /**< All directions */
|
||||
} dc_direction_t;
|
||||
|
||||
/**
|
||||
* The serial line signals.
|
||||
*/
|
||||
typedef enum dc_line_t {
|
||||
DC_LINE_DCD = 0x01, /**< Data carrier detect */
|
||||
DC_LINE_CTS = 0x02, /**< Clear to send */
|
||||
DC_LINE_DSR = 0x04, /**< Data set ready */
|
||||
DC_LINE_RNG = 0x08, /**< Ring indicator */
|
||||
} dc_line_t;
|
||||
|
||||
#endif /* __SERIAL_TYPES__ */
|
||||
|
||||
typedef struct dc_custom_serial_t
|
||||
{
|
||||
void *userdata;
|
||||
dc_status_t (*open) (void **userdata, const char *name);
|
||||
dc_status_t (*close) (void **userdata);
|
||||
dc_status_t (*read) (void **userdata, void* data, size_t size, size_t *actual);
|
||||
dc_status_t (*write) (void **userdata, const void* data, size_t size, size_t *actual);
|
||||
dc_status_t (*purge) (void **userdata, dc_direction_t);
|
||||
dc_status_t (*get_available) (void **userdata, size_t *value);
|
||||
dc_status_t (*set_timeout) (void **userdata, long timeout);
|
||||
dc_status_t (*configure) (void **userdata, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol);
|
||||
dc_status_t (*set_dtr) (void **userdata, int level);
|
||||
dc_status_t (*set_rts) (void **userdata, int level);
|
||||
dc_status_t (*set_halfduplex) (void **userdata, unsigned int value);
|
||||
dc_status_t (*set_break) (void **userdata, unsigned int level);
|
||||
//dc_serial_set_latency (dc_serial_t *device, unsigned int milliseconds) - Unused
|
||||
//dc_serial_get_lines (dc_serial_t *device, unsigned int *value) - Unused
|
||||
//dc_serial_flush (dc_serial_t *device) - No device interaction
|
||||
//dc_serial_sleep (dc_serial_t *device, unsigned int timeout) - No device interaction
|
||||
} dc_custom_serial_t;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* CUSTOM_SERIAL_H */
|
||||
@ -56,6 +56,9 @@ dc_descriptor_get_type (dc_descriptor_t *descriptor);
|
||||
unsigned int
|
||||
dc_descriptor_get_model (dc_descriptor_t *descriptor);
|
||||
|
||||
unsigned int
|
||||
dc_descriptor_get_serial (dc_descriptor_t *descriptor);
|
||||
|
||||
dc_transport_t
|
||||
dc_descriptor_get_transport (dc_descriptor_t *descriptor);
|
||||
|
||||
|
||||
@ -65,7 +65,7 @@ dc_status_t
|
||||
hw_ostc_extract_dives (dc_device_t *device, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata);
|
||||
|
||||
dc_status_t
|
||||
hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int hwos);
|
||||
hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial, unsigned int hwos);
|
||||
|
||||
dc_status_t
|
||||
hw_ostc_device_fwupdate (dc_device_t *abstract, const char *filename);
|
||||
|
||||
@ -65,7 +65,7 @@ dc_status_t
|
||||
hw_ostc3_device_fwupdate (dc_device_t *abstract, const char *filename);
|
||||
|
||||
dc_status_t
|
||||
hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model);
|
||||
hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ dc_status_t
|
||||
oceanic_atom2_device_keepalive (dc_device_t *device);
|
||||
|
||||
dc_status_t
|
||||
oceanic_atom2_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
oceanic_atom2_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model, unsigned int serial);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -62,9 +62,13 @@ typedef enum dc_field_type_t {
|
||||
DC_FIELD_TEMPERATURE_MAXIMUM,
|
||||
DC_FIELD_TANK_COUNT,
|
||||
DC_FIELD_TANK,
|
||||
DC_FIELD_DIVEMODE
|
||||
DC_FIELD_DIVEMODE,
|
||||
DC_FIELD_STRING,
|
||||
} dc_field_type_t;
|
||||
|
||||
// Make it easy to test support compile-time with "#ifdef DC_FIELD_STRING"
|
||||
#define DC_FIELD_STRING DC_FIELD_STRING
|
||||
|
||||
typedef enum parser_sample_event_t {
|
||||
SAMPLE_EVENT_NONE,
|
||||
SAMPLE_EVENT_DECOSTOP,
|
||||
@ -92,17 +96,24 @@ typedef enum parser_sample_event_t {
|
||||
SAMPLE_EVENT_HEADING,
|
||||
SAMPLE_EVENT_TISSUELEVEL,
|
||||
SAMPLE_EVENT_GASCHANGE2, /* Deprecated: replaced by DC_SAMPLE_GASMIX. */
|
||||
SAMPLE_EVENT_STRING,
|
||||
} parser_sample_event_t;
|
||||
|
||||
/* To let the compile know we have this */
|
||||
#define SAMPLE_EVENT_STRING SAMPLE_EVENT_STRING
|
||||
|
||||
/* For backwards compatibility */
|
||||
#define SAMPLE_EVENT_UNKNOWN SAMPLE_EVENT_FLOOR
|
||||
|
||||
typedef enum parser_sample_flags_t {
|
||||
SAMPLE_FLAGS_NONE = 0,
|
||||
SAMPLE_FLAGS_BEGIN = (1 << 0),
|
||||
SAMPLE_FLAGS_END = (1 << 1)
|
||||
SAMPLE_FLAGS_END = (1 << 1),
|
||||
SAMPLE_FLAGS_SEVERITY_MASK = (7 << 2),
|
||||
} parser_sample_flags_t;
|
||||
|
||||
#define SAMPLE_FLAGS_SEVERITY_SHIFT 2
|
||||
|
||||
typedef enum parser_sample_vendor_t {
|
||||
SAMPLE_VENDOR_NONE,
|
||||
SAMPLE_VENDOR_UWATEC_ALADIN,
|
||||
@ -144,11 +155,17 @@ typedef struct dc_gasmix_t {
|
||||
|
||||
#define DC_GASMIX_UNKNOWN 0xFFFFFFFF
|
||||
|
||||
typedef enum dc_tankvolume_t {
|
||||
DC_TANKVOLUME_NONE,
|
||||
DC_TANKVOLUME_METRIC,
|
||||
DC_TANKVOLUME_IMPERIAL,
|
||||
} dc_tankvolume_t;
|
||||
typedef unsigned int dc_tankinfo_t;
|
||||
#define DC_TANKINFO_METRIC 1
|
||||
#define DC_TANKINFO_IMPERIAL 2
|
||||
#define DC_TANKINFO_CC_DILUENT 4
|
||||
#define DC_TANKINFO_CC_O2 8
|
||||
|
||||
// For backwards compatibility
|
||||
#define DC_TANKVOLUME_NONE 0
|
||||
#define DC_TANKVOLUME_METRIC DC_TANKINFO_METRIC
|
||||
#define DC_TANKVOLUME_IMPERIAL DC_TANKINFO_IMPERIAL
|
||||
|
||||
|
||||
/*
|
||||
* Tank volume
|
||||
@ -175,13 +192,18 @@ typedef enum dc_tankvolume_t {
|
||||
|
||||
typedef struct dc_tank_t {
|
||||
unsigned int gasmix; /* Gas mix index, or DC_GASMIX_UNKNOWN */
|
||||
dc_tankvolume_t type; /* Tank type */
|
||||
dc_tankinfo_t type; /* Tank type - metric/imperial and oc/cc */
|
||||
double volume; /* Volume (liter) */
|
||||
double workpressure; /* Work pressure (bar) */
|
||||
double beginpressure; /* Begin pressure (bar) */
|
||||
double endpressure; /* End pressure (bar) */
|
||||
} dc_tank_t;
|
||||
|
||||
typedef struct dc_field_string_t {
|
||||
const char *desc;
|
||||
const char *value;
|
||||
} dc_field_string_t;
|
||||
|
||||
typedef union dc_sample_value_t {
|
||||
unsigned int time;
|
||||
double depth;
|
||||
@ -193,6 +215,7 @@ typedef union dc_sample_value_t {
|
||||
struct {
|
||||
unsigned int type;
|
||||
unsigned int time;
|
||||
const char *name;
|
||||
unsigned int flags;
|
||||
unsigned int value;
|
||||
} event;
|
||||
|
||||
@ -34,7 +34,7 @@ dc_status_t
|
||||
shearwater_petrel_device_open (dc_device_t **device, dc_context_t *context, const char *name);
|
||||
|
||||
dc_status_t
|
||||
shearwater_petrel_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
shearwater_petrel_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ dc_status_t
|
||||
shearwater_predator_extract_dives (dc_device_t *device, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata);
|
||||
|
||||
dc_status_t
|
||||
shearwater_predator_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
shearwater_predator_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ dc_status_t
|
||||
suunto_d9_device_reset_maxdepth (dc_device_t *device);
|
||||
|
||||
dc_status_t
|
||||
suunto_d9_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
suunto_d9_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model, unsigned int serial);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -26,6 +26,10 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* use these defines to detect Subsurface specific features */
|
||||
#define SSRF_LIBDC_VERSION 1
|
||||
#define SSRF_CUSTOM_SERIAL 1
|
||||
|
||||
#define DC_VERSION "@DC_VERSION@"
|
||||
#define DC_VERSION_MAJOR @DC_VERSION_MAJOR@
|
||||
#define DC_VERSION_MINOR @DC_VERSION_MINOR@
|
||||
|
||||
@ -20,6 +20,12 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#include <libdivecomputer/atomics_cobalt.h>
|
||||
#include <libdivecomputer/units.h>
|
||||
@ -128,6 +134,9 @@ atomics_cobalt_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *dateti
|
||||
}
|
||||
|
||||
|
||||
#define BUFLEN 16
|
||||
|
||||
|
||||
static dc_status_t
|
||||
atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
|
||||
{
|
||||
@ -142,6 +151,9 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
||||
dc_tank_t *tank = (dc_tank_t *) value;
|
||||
|
||||
double atmospheric = 0.0;
|
||||
char buf[BUFLEN];
|
||||
dc_field_string_t *string = (dc_field_string_t *) value;
|
||||
|
||||
if (parser->atmospheric)
|
||||
atmospheric = parser->atmospheric;
|
||||
else
|
||||
@ -207,6 +219,29 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_STRING:
|
||||
switch(flags) {
|
||||
case 0: // Serialnr
|
||||
string->desc = "Serial";
|
||||
snprintf(buf, BUFLEN, "%c%c%c%c-%c%c%c%c", p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11]);
|
||||
break;
|
||||
case 1: // Program Version
|
||||
string->desc = "Program Version";
|
||||
snprintf(buf, BUFLEN, "%.2f", array_uint16_le(p + 30) / 100.0);
|
||||
break;
|
||||
case 2: // Boot Version
|
||||
string->desc = "Boot Version";
|
||||
snprintf(buf, BUFLEN, "%.2f", array_uint16_le(p + 32) / 100.0);
|
||||
break;
|
||||
case 3: // Nofly
|
||||
string->desc = "NoFly Time";
|
||||
snprintf(buf, BUFLEN, "%0u:%02u", p[0x52], p[0x53]);
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
string->value = strdup(buf);
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#endif
|
||||
|
||||
#include <libdivecomputer/context.h>
|
||||
#include <libdivecomputer/custom_serial.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -71,6 +72,23 @@ dc_context_syserror (dc_context_t *context, dc_loglevel_t loglevel, const char *
|
||||
dc_status_t
|
||||
dc_context_hexdump (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *prefix, const unsigned char data[], unsigned int size);
|
||||
|
||||
dc_custom_serial_t*
|
||||
_dc_context_custom_serial (dc_context_t *context);
|
||||
|
||||
#define RETURN_IF_CUSTOM_SERIAL(context, block, function, ...) \
|
||||
do { \
|
||||
dc_custom_serial_t *c = _dc_context_custom_serial(context); \
|
||||
dc_status_t _rc; \
|
||||
if (c) { \
|
||||
if (c->function) \
|
||||
_rc = c->function(&c->userdata, ##__VA_ARGS__); \
|
||||
else \
|
||||
_rc = DC_STATUS_SUCCESS; \
|
||||
block ;\
|
||||
return _rc; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
#endif
|
||||
|
||||
#include "context-private.h"
|
||||
#include <libdivecomputer/custom_serial.h>
|
||||
|
||||
struct dc_context_t {
|
||||
dc_loglevel_t loglevel;
|
||||
@ -45,6 +46,7 @@ struct dc_context_t {
|
||||
struct timeval timestamp;
|
||||
#endif
|
||||
#endif
|
||||
dc_custom_serial_t *custom_serial;
|
||||
};
|
||||
|
||||
#ifdef ENABLE_LOGGING
|
||||
@ -195,6 +197,8 @@ dc_context_new (dc_context_t **out)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
context->custom_serial = NULL;
|
||||
|
||||
*out = context;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
@ -208,6 +212,23 @@ dc_context_free (dc_context_t *context)
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_context_set_custom_serial (dc_context_t *context, dc_custom_serial_t *custom_serial)
|
||||
{
|
||||
if (context == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
context->custom_serial = custom_serial;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
dc_custom_serial_t*
|
||||
_dc_context_custom_serial (dc_context_t *context)
|
||||
{
|
||||
return context->custom_serial;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_context_set_loglevel (dc_context_t *context, dc_loglevel_t loglevel)
|
||||
{
|
||||
|
||||
@ -43,6 +43,7 @@ struct dc_descriptor_t {
|
||||
const char *product;
|
||||
dc_family_t type;
|
||||
unsigned int model;
|
||||
unsigned int serial;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -400,6 +401,15 @@ dc_descriptor_get_model (dc_descriptor_t *descriptor)
|
||||
return descriptor->model;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
dc_descriptor_get_serial (dc_descriptor_t *descriptor)
|
||||
{
|
||||
if (descriptor == NULL)
|
||||
return 0;
|
||||
|
||||
return descriptor->serial;
|
||||
}
|
||||
|
||||
dc_transport_t
|
||||
dc_descriptor_get_transport (dc_descriptor_t *descriptor)
|
||||
{
|
||||
|
||||
@ -20,6 +20,12 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#include <libdivecomputer/hw_ostc.h>
|
||||
#include <libdivecomputer/hw_ostc3.h>
|
||||
@ -60,8 +66,14 @@
|
||||
#define OSTC3_GAUGE 2
|
||||
#define OSTC3_APNEA 3
|
||||
|
||||
#define OSTC3_ZHL16 0
|
||||
#define OSTC3_ZHL16_GF 1
|
||||
#define OSTC4_VPM 2
|
||||
|
||||
#define OSTC4 0x3B
|
||||
|
||||
#define UNSUPPORTED 0xFFFFFFFF
|
||||
|
||||
typedef struct hw_ostc_sample_info_t {
|
||||
unsigned int type;
|
||||
unsigned int divisor;
|
||||
@ -77,7 +89,12 @@ typedef struct hw_ostc_layout_t {
|
||||
unsigned int salinity;
|
||||
unsigned int duration;
|
||||
unsigned int temperature;
|
||||
unsigned int battery;
|
||||
unsigned int desat;
|
||||
unsigned int firmware;
|
||||
unsigned int deco_info1;
|
||||
unsigned int deco_info2;
|
||||
unsigned int decomode;
|
||||
} hw_ostc_layout_t;
|
||||
|
||||
typedef struct hw_ostc_gasmix_t {
|
||||
@ -89,6 +106,7 @@ typedef struct hw_ostc_parser_t {
|
||||
dc_parser_t base;
|
||||
unsigned int hwos;
|
||||
unsigned int model;
|
||||
unsigned int serial;
|
||||
// Cached fields.
|
||||
unsigned int cached;
|
||||
unsigned int version;
|
||||
@ -124,7 +142,12 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc = {
|
||||
43, /* salinity */
|
||||
47, /* duration */
|
||||
13, /* temperature */
|
||||
34, /* battery volt after dive */
|
||||
17, /* desat */
|
||||
32, /* firmware */
|
||||
49, /* deco_info1 */
|
||||
50, /* deco_info1 */
|
||||
51, /* decomode */
|
||||
};
|
||||
|
||||
static const hw_ostc_layout_t hw_ostc_layout_frog = {
|
||||
@ -136,7 +159,12 @@ static const hw_ostc_layout_t hw_ostc_layout_frog = {
|
||||
43, /* salinity */
|
||||
47, /* duration */
|
||||
19, /* temperature */
|
||||
34, /* battery volt after dive */
|
||||
23, /* desat */
|
||||
32, /* firmware */
|
||||
49, /* deco_info1 */
|
||||
50, /* deco_info2 */
|
||||
51, /* decomode */
|
||||
};
|
||||
|
||||
static const hw_ostc_layout_t hw_ostc_layout_ostc3 = {
|
||||
@ -148,7 +176,12 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc3 = {
|
||||
70, /* salinity */
|
||||
75, /* duration */
|
||||
22, /* temperature */
|
||||
50, /* battery volt after dive */
|
||||
26, /* desat */
|
||||
48, /* firmware */
|
||||
77, /* deco_info1 */
|
||||
78, /* deco_info2 */
|
||||
79, /* decomode */
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
@ -275,7 +308,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsigned int hwos, unsigned int model)
|
||||
hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int hwos, unsigned int model)
|
||||
{
|
||||
hw_ostc_parser_t *parser = NULL;
|
||||
|
||||
@ -303,6 +336,7 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsign
|
||||
parser->gasmix[i].oxygen = 0;
|
||||
parser->gasmix[i].helium = 0;
|
||||
}
|
||||
parser->serial = serial;
|
||||
|
||||
*out = (dc_parser_t *) parser;
|
||||
|
||||
@ -311,15 +345,15 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsign
|
||||
|
||||
|
||||
dc_status_t
|
||||
hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int hwos)
|
||||
hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int hwos)
|
||||
{
|
||||
return hw_ostc_parser_create_internal (out, context, hwos, 0);
|
||||
return hw_ostc_parser_create_internal (out, context, serial, hwos, 0);
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int model)
|
||||
{
|
||||
return hw_ostc_parser_create_internal (out, context, 1, model);
|
||||
return hw_ostc_parser_create_internal (out, context, serial, 1, model);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
@ -402,6 +436,8 @@ hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define BUFLEN 16
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
|
||||
{
|
||||
@ -426,9 +462,12 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
||||
|
||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||
dc_salinity_t *water = (dc_salinity_t *) value;
|
||||
dc_field_string_t *string = (dc_field_string_t *) value;
|
||||
|
||||
unsigned int salinity = data[layout->salinity];
|
||||
if (version == 0x23 || version == 0x24)
|
||||
salinity += 100;
|
||||
char buf[BUFLEN];
|
||||
|
||||
if (value) {
|
||||
switch (type) {
|
||||
@ -519,6 +558,70 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_STRING:
|
||||
switch(flags) {
|
||||
case 0: /* battery */
|
||||
string->desc = "Battery at end";
|
||||
snprintf(buf, BUFLEN, "%.2f", array_uint16_le (data + layout->battery) / 1000.0);
|
||||
break;
|
||||
case 1: /* desat */
|
||||
string->desc = "Desat time";
|
||||
snprintf(buf, BUFLEN, "%0u:%02u", array_uint16_le (data + layout->desat) / 60,
|
||||
array_uint16_le (data + layout->desat) % 60);
|
||||
break;
|
||||
case 2: /* firmware */
|
||||
string->desc = "FW Version";
|
||||
/* OSTC4 stores firmware as XXXX XYYY YYZZ ZZZB, -> X.Y.Z beta? */
|
||||
if (parser->model == OSTC4) {
|
||||
int firmwareOnDevice = array_uint16_le (data + layout->firmware);
|
||||
unsigned char X = 0, Y = 0, Z = 0, beta = 0;
|
||||
X = (firmwareOnDevice & 0xF800) >> 11;
|
||||
Y = (firmwareOnDevice & 0x07C0) >> 6;
|
||||
Z = (firmwareOnDevice & 0x003E) >> 1;
|
||||
beta = firmwareOnDevice & 0x0001;
|
||||
|
||||
snprintf(buf, BUFLEN, "%u.%u.%u%s\n", X, Y, Z, beta? "beta": "");
|
||||
} else {
|
||||
snprintf(buf, BUFLEN, "%0u.%02u", data[layout->firmware], data[layout->firmware + 1]);
|
||||
}
|
||||
break;
|
||||
case 3: /* serial */
|
||||
string->desc = "Serial";
|
||||
snprintf(buf, BUFLEN, "%u", parser->serial);
|
||||
break;
|
||||
case 4: /* Deco model */
|
||||
string->desc = "Deco model";
|
||||
if (((version == 0x23 || version == 0x24) && data[layout->decomode] == OSTC3_ZHL16) ||
|
||||
(version == 0x22 && data[layout->decomode] == FROG_ZHL16) ||
|
||||
(version == 0x21 && (data[layout->decomode] == OSTC_ZHL16_OC || data[layout->decomode] == OSTC_ZHL16_CC)))
|
||||
strncpy(buf, "ZH-L16", BUFLEN);
|
||||
else if (((version == 0x23 || version == 0x24) && data[layout->decomode] == OSTC3_ZHL16_GF) ||
|
||||
(version == 0x22 && data[layout->decomode] == FROG_ZHL16_GF) ||
|
||||
(version == 0x21 && (data[layout->decomode] == OSTC_ZHL16_OC_GF || data[layout->decomode] == OSTC_ZHL16_CC_GF)))
|
||||
strncpy(buf, "ZH-L16-GF", BUFLEN);
|
||||
else if (((version == 0x24) && data[layout->decomode] == OSTC4_VPM))
|
||||
strncpy(buf, "VPM", BUFLEN);
|
||||
else
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
break;
|
||||
case 5: /* Deco model info */
|
||||
string->desc = "Deco model info";
|
||||
if (((version == 0x23 || version == 0x24) && data[layout->decomode] == OSTC3_ZHL16) ||
|
||||
(version == 0x22 && data[layout->decomode] == FROG_ZHL16) ||
|
||||
(version == 0x21 && (data[layout->decomode] == OSTC_ZHL16_OC || data[layout->decomode] == OSTC_ZHL16_CC)))
|
||||
snprintf(buf, BUFLEN, "Saturation %u, Desaturation %u", layout->deco_info1, layout->deco_info2);
|
||||
else if (((version == 0x23 || version == 0x24) && data[layout->decomode] == OSTC3_ZHL16_GF) ||
|
||||
(version == 0x22 && data[layout->decomode] == FROG_ZHL16_GF) ||
|
||||
(version == 0x21 && (data[layout->decomode] == OSTC_ZHL16_OC_GF || data[layout->decomode] == OSTC_ZHL16_CC_GF)))
|
||||
snprintf(buf, BUFLEN, "GF %u/%u", data[layout->deco_info1], data[layout->deco_info2]);
|
||||
else
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
string->value = strdup(buf);
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ dc_context_new
|
||||
dc_context_free
|
||||
dc_context_set_loglevel
|
||||
dc_context_set_logfunc
|
||||
dc_context_set_custom_serial
|
||||
|
||||
dc_iterator_next
|
||||
dc_iterator_free
|
||||
|
||||
@ -20,6 +20,8 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libdivecomputer/oceanic_atom2.h>
|
||||
#include <libdivecomputer/units.h>
|
||||
@ -101,6 +103,7 @@ struct oceanic_atom2_parser_t {
|
||||
unsigned int model;
|
||||
unsigned int headersize;
|
||||
unsigned int footersize;
|
||||
unsigned int serial;
|
||||
// Cached fields.
|
||||
unsigned int cached;
|
||||
unsigned int header;
|
||||
@ -130,7 +133,7 @@ static const dc_parser_vtable_t oceanic_atom2_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model, unsigned int serial)
|
||||
{
|
||||
oceanic_atom2_parser_t *parser = NULL;
|
||||
|
||||
@ -174,6 +177,7 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned
|
||||
parser->headersize = 5 * PAGESIZE;
|
||||
}
|
||||
|
||||
parser->serial = serial;
|
||||
parser->cached = 0;
|
||||
parser->header = 0;
|
||||
parser->footer = 0;
|
||||
@ -362,6 +366,7 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define BUF_LEN 16
|
||||
|
||||
static dc_status_t
|
||||
oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser)
|
||||
@ -494,6 +499,9 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
|
||||
|
||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||
dc_salinity_t *water = (dc_salinity_t *) value;
|
||||
dc_field_string_t *string = (dc_field_string_t *) value;
|
||||
|
||||
char buf[BUF_LEN];
|
||||
|
||||
if (value) {
|
||||
switch (type) {
|
||||
@ -549,6 +557,17 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_STRING:
|
||||
switch(flags) {
|
||||
case 0: /* Serial */
|
||||
string->desc = "Serial";
|
||||
snprintf(buf, BUF_LEN, "%06u", parser->serial);
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
string->value = strdup(buf);
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
22
src/parser.c
22
src/parser.c
@ -44,7 +44,7 @@
|
||||
#define REACTPROWHITE 0x4354
|
||||
|
||||
static dc_status_t
|
||||
dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t family, unsigned int model, unsigned int devtime, dc_ticks_t systime)
|
||||
dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t family, unsigned int model, unsigned int serial, unsigned int devtime, dc_ticks_t systime)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
dc_parser_t *parser = NULL;
|
||||
@ -67,7 +67,7 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t fa
|
||||
break;
|
||||
case DC_FAMILY_SUUNTO_VYPER2:
|
||||
case DC_FAMILY_SUUNTO_D9:
|
||||
rc = suunto_d9_parser_create (&parser, context, model);
|
||||
rc = suunto_d9_parser_create (&parser, context, model, serial);
|
||||
break;
|
||||
case DC_FAMILY_SUUNTO_EONSTEEL:
|
||||
rc = suunto_eonsteel_parser_create(&parser, context, model);
|
||||
@ -99,7 +99,7 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t fa
|
||||
if (model == REACTPROWHITE)
|
||||
rc = oceanic_veo250_parser_create (&parser, context, model);
|
||||
else
|
||||
rc = oceanic_atom2_parser_create (&parser, context, model);
|
||||
rc = oceanic_atom2_parser_create (&parser, context, model, serial);
|
||||
break;
|
||||
case DC_FAMILY_MARES_NEMO:
|
||||
case DC_FAMILY_MARES_PUCK:
|
||||
@ -112,11 +112,11 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t fa
|
||||
rc = mares_iconhd_parser_create (&parser, context, model);
|
||||
break;
|
||||
case DC_FAMILY_HW_OSTC:
|
||||
rc = hw_ostc_parser_create (&parser, context, 0);
|
||||
rc = hw_ostc_parser_create (&parser, context, serial, 0);
|
||||
break;
|
||||
case DC_FAMILY_HW_FROG:
|
||||
case DC_FAMILY_HW_OSTC3:
|
||||
rc = hw_ostc3_parser_create (&parser, context, model);
|
||||
rc = hw_ostc3_parser_create (&parser, context, serial, model);
|
||||
break;
|
||||
case DC_FAMILY_CRESSI_EDY:
|
||||
case DC_FAMILY_ZEAGLE_N2ITION3:
|
||||
@ -129,10 +129,10 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t fa
|
||||
rc = atomics_cobalt_parser_create (&parser, context);
|
||||
break;
|
||||
case DC_FAMILY_SHEARWATER_PREDATOR:
|
||||
rc = shearwater_predator_parser_create (&parser, context);
|
||||
rc = shearwater_predator_parser_create (&parser, context, serial);
|
||||
break;
|
||||
case DC_FAMILY_SHEARWATER_PETREL:
|
||||
rc = shearwater_petrel_parser_create (&parser, context);
|
||||
rc = shearwater_petrel_parser_create (&parser, context, serial);
|
||||
break;
|
||||
case DC_FAMILY_DIVERITE_NITEKQ:
|
||||
rc = diverite_nitekq_parser_create (&parser, context);
|
||||
@ -162,7 +162,9 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
return dc_parser_new_internal (out, device->context,
|
||||
dc_device_get_type (device), device->devinfo.model,
|
||||
dc_device_get_type (device),
|
||||
device->devinfo.model,
|
||||
device->devinfo.serial,
|
||||
device->clock.devtime, device->clock.systime);
|
||||
}
|
||||
|
||||
@ -170,7 +172,9 @@ dc_status_t
|
||||
dc_parser_new2 (dc_parser_t **out, dc_context_t *context, dc_descriptor_t *descriptor, unsigned int devtime, dc_ticks_t systime)
|
||||
{
|
||||
return dc_parser_new_internal (out, context,
|
||||
dc_descriptor_get_type (descriptor), dc_descriptor_get_model (descriptor),
|
||||
dc_descriptor_get_type (descriptor),
|
||||
dc_descriptor_get_model (descriptor),
|
||||
dc_descriptor_get_serial (descriptor),
|
||||
devtime, systime);
|
||||
}
|
||||
|
||||
|
||||
@ -34,6 +34,8 @@ extern "C" {
|
||||
*/
|
||||
typedef struct dc_serial_t dc_serial_t;
|
||||
|
||||
#ifndef __SERIAL_TYPES__
|
||||
#define __SERIAL_TYPES__
|
||||
/**
|
||||
* The parity checking scheme.
|
||||
*/
|
||||
@ -81,6 +83,7 @@ typedef enum dc_line_t {
|
||||
DC_LINE_DSR = 0x04, /**< Data set ready */
|
||||
DC_LINE_RNG = 0x08, /**< Ring indicator */
|
||||
} dc_line_t;
|
||||
#endif /* __SERIAL_TYPES__ */
|
||||
|
||||
/**
|
||||
* Serial enumeration callback.
|
||||
|
||||
@ -167,6 +167,8 @@ dc_serial_open (dc_serial_t **out, dc_context_t *context, const char *name)
|
||||
device->baudrate = 0;
|
||||
device->nbits = 0;
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(context, *out = device, open, name);
|
||||
|
||||
// Open the device in non-blocking mode, to return immediately
|
||||
// without waiting for the modem connection to complete.
|
||||
device->fd = open (name, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||
@ -217,6 +219,8 @@ dc_serial_close (dc_serial_t *device)
|
||||
if (device == NULL)
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, free(device), close);
|
||||
|
||||
// Restore the initial terminal attributes.
|
||||
if (tcsetattr (device->fd, TCSANOW, &device->tty) != 0) {
|
||||
int errcode = errno;
|
||||
@ -251,6 +255,8 @@ dc_serial_configure (dc_serial_t *device, unsigned int baudrate, unsigned int da
|
||||
INFO (device->context, "Configure: baudrate=%i, databits=%i, parity=%i, stopbits=%i, flowcontrol=%i",
|
||||
baudrate, databits, parity, stopbits, flowcontrol);
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, , configure, baudrate, databits, parity, stopbits, flowcontrol);
|
||||
|
||||
// Retrieve the current settings.
|
||||
struct termios tty;
|
||||
memset (&tty, 0, sizeof (tty));
|
||||
@ -449,9 +455,11 @@ dc_serial_configure (dc_serial_t *device, unsigned int baudrate, unsigned int da
|
||||
|
||||
// Apply the new settings.
|
||||
if (tcsetattr (device->fd, TCSANOW, &tty) != 0 && NOPTY) {
|
||||
#if 0 // who cares
|
||||
int errcode = errno;
|
||||
SYSERROR (device->context, errcode);
|
||||
return syserror (errcode);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Configure a custom baudrate if necessary.
|
||||
@ -503,6 +511,8 @@ dc_serial_set_timeout (dc_serial_t *device, int timeout)
|
||||
|
||||
INFO (device->context, "Timeout: value=%i", timeout);
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, , set_timeout, timeout);
|
||||
|
||||
device->timeout = timeout;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
@ -514,6 +524,8 @@ dc_serial_set_halfduplex (dc_serial_t *device, unsigned int value)
|
||||
if (device == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, , set_halfduplex, value);
|
||||
|
||||
device->halfduplex = value;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
@ -573,6 +585,14 @@ dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual)
|
||||
goto out;
|
||||
}
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context,
|
||||
{
|
||||
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Custom Read", (unsigned char *) data, nbytes);
|
||||
if (actual)
|
||||
*actual = nbytes;
|
||||
},
|
||||
read, data, size, &nbytes);
|
||||
|
||||
// The total timeout.
|
||||
int timeout = device->timeout;
|
||||
|
||||
@ -664,6 +684,14 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act
|
||||
goto out;
|
||||
}
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context,
|
||||
{
|
||||
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Custom Write", (unsigned char *) data, nbytes);
|
||||
if (actual)
|
||||
*actual = nbytes;
|
||||
},
|
||||
write, data, size, &nbytes);
|
||||
|
||||
struct timeval tve, tvb;
|
||||
if (device->halfduplex) {
|
||||
// Get the current time.
|
||||
@ -768,6 +796,8 @@ dc_serial_purge (dc_serial_t *device, dc_direction_t direction)
|
||||
|
||||
INFO (device->context, "Purge: direction=%u", direction);
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, , purge, direction);
|
||||
|
||||
int flags = 0;
|
||||
|
||||
switch (direction) {
|
||||
@ -812,6 +842,8 @@ dc_serial_set_break (dc_serial_t *device, unsigned int level)
|
||||
|
||||
INFO (device->context, "Break: value=%i", level);
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, , set_break, level);
|
||||
|
||||
unsigned long action = (level ? TIOCSBRK : TIOCCBRK);
|
||||
|
||||
if (ioctl (device->fd, action, NULL) != 0 && NOPTY) {
|
||||
@ -831,6 +863,8 @@ dc_serial_set_dtr (dc_serial_t *device, unsigned int level)
|
||||
|
||||
INFO (device->context, "DTR: value=%i", level);
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, , set_dtr, level);
|
||||
|
||||
unsigned long action = (level ? TIOCMBIS : TIOCMBIC);
|
||||
|
||||
int value = TIOCM_DTR;
|
||||
@ -851,6 +885,8 @@ dc_serial_set_rts (dc_serial_t *device, unsigned int level)
|
||||
|
||||
INFO (device->context, "RTS: value=%i", level);
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, , set_rts, level);
|
||||
|
||||
unsigned long action = (level ? TIOCMBIS : TIOCMBIC);
|
||||
|
||||
int value = TIOCM_RTS;
|
||||
@ -869,6 +905,8 @@ dc_serial_get_available (dc_serial_t *device, size_t *value)
|
||||
if (device == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, , get_available, value);
|
||||
|
||||
int bytes = 0;
|
||||
if (ioctl (device->fd, TIOCINQ, &bytes) != 0) {
|
||||
int errcode = errno;
|
||||
|
||||
@ -157,6 +157,8 @@ dc_serial_open (dc_serial_t **out, dc_context_t *context, const char *name)
|
||||
device->baudrate = 0;
|
||||
device->nbits = 0;
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(context, *out = device, open, name);
|
||||
|
||||
// Open the device.
|
||||
device->hFile = CreateFileA (devname,
|
||||
GENERIC_READ | GENERIC_WRITE, 0,
|
||||
@ -202,6 +204,8 @@ dc_serial_close (dc_serial_t *device)
|
||||
if (device == NULL)
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, free(device), close);
|
||||
|
||||
// Restore the initial communication settings and timeouts.
|
||||
if (!SetCommState (device->hFile, &device->dcb) ||
|
||||
!SetCommTimeouts (device->hFile, &device->timeouts)) {
|
||||
@ -232,6 +236,8 @@ dc_serial_configure (dc_serial_t *device, unsigned int baudrate, unsigned int da
|
||||
INFO (device->context, "Configure: baudrate=%i, databits=%i, parity=%i, stopbits=%i, flowcontrol=%i",
|
||||
baudrate, databits, parity, stopbits, flowcontrol);
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, , configure, baudrate, databits, parity, stopbits, flowcontrol);
|
||||
|
||||
// Retrieve the current settings.
|
||||
DCB dcb;
|
||||
if (!GetCommState (device->hFile, &dcb)) {
|
||||
@ -344,6 +350,8 @@ dc_serial_set_timeout (dc_serial_t *device, int timeout)
|
||||
|
||||
INFO (device->context, "Timeout: value=%i", timeout);
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, , set_timeout, timeout);
|
||||
|
||||
// Retrieve the current timeouts.
|
||||
COMMTIMEOUTS timeouts;
|
||||
if (!GetCommTimeouts (device->hFile, &timeouts)) {
|
||||
@ -392,6 +400,8 @@ dc_serial_set_halfduplex (dc_serial_t *device, unsigned int value)
|
||||
if (device == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, , set_halfduplex, value);
|
||||
|
||||
device->halfduplex = value;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
@ -409,6 +419,7 @@ dc_serial_set_latency (dc_serial_t *device, unsigned int value)
|
||||
dc_status_t
|
||||
dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual)
|
||||
{
|
||||
size_t nbytes = 0;
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
DWORD dwRead = 0;
|
||||
|
||||
@ -417,6 +428,14 @@ dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual)
|
||||
goto out;
|
||||
}
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context,
|
||||
{
|
||||
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Custom Read", (unsigned char *) data, nbytes);
|
||||
if (actual)
|
||||
*actual = nbytes;
|
||||
},
|
||||
read, data, size, &nbytes);
|
||||
|
||||
if (!ReadFile (device->hFile, data, size, &dwRead, NULL)) {
|
||||
DWORD errcode = GetLastError ();
|
||||
SYSERROR (device->context, errcode);
|
||||
@ -440,6 +459,7 @@ out:
|
||||
dc_status_t
|
||||
dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *actual)
|
||||
{
|
||||
size_t nbytes = 0;
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
DWORD dwWritten = 0;
|
||||
|
||||
@ -448,6 +468,14 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act
|
||||
goto out;
|
||||
}
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context,
|
||||
{
|
||||
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Custom Write", (unsigned char *) data, nbytes);
|
||||
if (actual)
|
||||
*actual = nbytes;
|
||||
},
|
||||
write, data, size, &nbytes);
|
||||
|
||||
LARGE_INTEGER begin, end, freq;
|
||||
if (device->halfduplex) {
|
||||
// Get the current time.
|
||||
@ -515,6 +543,8 @@ dc_serial_purge (dc_serial_t *device, dc_direction_t direction)
|
||||
|
||||
INFO (device->context, "Purge: direction=%u", direction);
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, , purge, direction);
|
||||
|
||||
DWORD flags = 0;
|
||||
|
||||
switch (direction) {
|
||||
@ -565,6 +595,8 @@ dc_serial_set_break (dc_serial_t *device, unsigned int level)
|
||||
|
||||
INFO (device->context, "Break: value=%i", level);
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, , set_break, level);
|
||||
|
||||
if (level) {
|
||||
if (!SetCommBreak (device->hFile)) {
|
||||
DWORD errcode = GetLastError ();
|
||||
@ -590,6 +622,8 @@ dc_serial_set_dtr (dc_serial_t *device, unsigned int level)
|
||||
|
||||
INFO (device->context, "DTR: value=%i", level);
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, , set_dtr, level);
|
||||
|
||||
int status = (level ? SETDTR : CLRDTR);
|
||||
|
||||
if (!EscapeCommFunction (device->hFile, status)) {
|
||||
@ -609,6 +643,8 @@ dc_serial_set_rts (dc_serial_t *device, unsigned int level)
|
||||
|
||||
INFO (device->context, "RTS: value=%i", level);
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, , set_rts, level);
|
||||
|
||||
int status = (level ? SETRTS : CLRRTS);
|
||||
|
||||
if (!EscapeCommFunction (device->hFile, status)) {
|
||||
@ -626,6 +662,8 @@ dc_serial_get_available (dc_serial_t *device, size_t *value)
|
||||
if (device == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
RETURN_IF_CUSTOM_SERIAL(device->context, , get_available, value);
|
||||
|
||||
COMSTAT stats;
|
||||
|
||||
if (!ClearCommError (device->hFile, NULL, &stats)) {
|
||||
|
||||
@ -58,6 +58,7 @@ shearwater_common_open (shearwater_common_device_t *device, dc_context_t *contex
|
||||
status = dc_serial_set_timeout (device->port, 3000);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the timeout.");
|
||||
status = DC_STATUS_IO;
|
||||
goto error_close;
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,12 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#include <libdivecomputer/shearwater_predator.h>
|
||||
#include <libdivecomputer/shearwater_petrel.h>
|
||||
@ -61,6 +67,7 @@ struct shearwater_predator_parser_t {
|
||||
unsigned int ngasmixes;
|
||||
unsigned int oxygen[NGASMIXES];
|
||||
unsigned int helium[NGASMIXES];
|
||||
unsigned int serial;
|
||||
dc_divemode_t mode;
|
||||
};
|
||||
|
||||
@ -105,7 +112,7 @@ shearwater_predator_find_gasmix (shearwater_predator_parser_t *parser, unsigned
|
||||
|
||||
|
||||
dc_status_t
|
||||
shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int petrel)
|
||||
shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int petrel)
|
||||
{
|
||||
shearwater_predator_parser_t *parser = NULL;
|
||||
const dc_parser_vtable_t *vtable = NULL;
|
||||
@ -129,9 +136,16 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsig
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
// Initialize the base class.
|
||||
parser->petrel = petrel;
|
||||
parser->samplesize = samplesize;
|
||||
parser->serial = serial;
|
||||
if (petrel) {
|
||||
parser->samplesize = SZ_SAMPLE_PETREL;
|
||||
} else {
|
||||
parser->samplesize = SZ_SAMPLE_PREDATOR;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
parser->cached = 0;
|
||||
parser->headersize = 0;
|
||||
parser->footersize = 0;
|
||||
@ -149,16 +163,16 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsig
|
||||
|
||||
|
||||
dc_status_t
|
||||
shearwater_predator_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
shearwater_predator_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial)
|
||||
{
|
||||
return shearwater_common_parser_create (out, context, 0);
|
||||
return shearwater_common_parser_create (out, context, serial, 0);
|
||||
}
|
||||
|
||||
|
||||
dc_status_t
|
||||
shearwater_petrel_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
shearwater_petrel_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial)
|
||||
{
|
||||
return shearwater_common_parser_create (out, context, 1);
|
||||
return shearwater_common_parser_create (out, context, serial, 1);
|
||||
}
|
||||
|
||||
|
||||
@ -200,6 +214,8 @@ shearwater_predator_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *d
|
||||
}
|
||||
|
||||
|
||||
#define BUFLEN 16
|
||||
|
||||
static dc_status_t
|
||||
shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
|
||||
{
|
||||
@ -316,7 +332,9 @@ shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t typ
|
||||
|
||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||
dc_salinity_t *water = (dc_salinity_t *) value;
|
||||
dc_field_string_t *string = (dc_field_string_t *) value;
|
||||
unsigned int density = 0;
|
||||
char buf[BUFLEN];
|
||||
|
||||
if (value) {
|
||||
switch (type) {
|
||||
@ -351,6 +369,57 @@ shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t typ
|
||||
case DC_FIELD_DIVEMODE:
|
||||
*((dc_divemode_t *) value) = parser->mode;
|
||||
break;
|
||||
case DC_FIELD_STRING:
|
||||
switch(flags) {
|
||||
case 0: // Battery
|
||||
string->desc = "Battery at end";
|
||||
snprintf(buf, BUFLEN, "%.1f", data[9] / 10.0);
|
||||
break;
|
||||
case 1: // Serial
|
||||
string->desc = "Serial";
|
||||
snprintf(buf, BUFLEN, "%08x", parser->serial);
|
||||
break;
|
||||
case 2: // FW Version
|
||||
string->desc = "FW Version";
|
||||
snprintf(buf, BUFLEN, "%2x", data[19]);
|
||||
break;
|
||||
case 3: /* Deco model */
|
||||
string->desc = "Deco model";
|
||||
switch (data[67]) {
|
||||
case 0:
|
||||
strncpy(buf, "GF", BUFLEN);
|
||||
break;
|
||||
case 1:
|
||||
strncpy(buf, "VPM-B", BUFLEN);
|
||||
break;
|
||||
case 2:
|
||||
strncpy(buf, "VPM-B/GFS", BUFLEN);
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case 4: /* Deco model info */
|
||||
string->desc = "Deco model info";
|
||||
switch (data[67]) {
|
||||
case 0:
|
||||
snprintf(buf, BUFLEN, "GF %u/%u", data[4], data[5]);
|
||||
break;
|
||||
case 1:
|
||||
snprintf(buf, BUFLEN, "VPM-B +%u", data[68]);
|
||||
break;
|
||||
case 2:
|
||||
snprintf(buf, BUFLEN, "VPM-B/GFS +%u %u%%", data[68], data[85]);
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
string->value = strdup(buf);
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
@ -422,11 +491,11 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal
|
||||
// Status flags.
|
||||
unsigned int status = data[offset + 11];
|
||||
|
||||
// PPO2
|
||||
sample.ppo2 = data[offset + 6] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);
|
||||
|
||||
if ((status & OC) == 0) {
|
||||
// PPO2 -- only return PPO2 if we are in closed circuit mode
|
||||
sample.ppo2 = data[offset + 6] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);
|
||||
|
||||
// Setpoint
|
||||
if (parser->petrel) {
|
||||
sample.setpoint = data[offset + 18] / 100.0;
|
||||
|
||||
@ -20,7 +20,8 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h> // memcmp
|
||||
#include <string.h> // memcmp, strdup
|
||||
#include <stdio.h> // snprintf
|
||||
|
||||
#include <libdivecomputer/suunto_d9.h>
|
||||
|
||||
@ -72,6 +73,7 @@ typedef struct suunto_d9_parser_t suunto_d9_parser_t;
|
||||
struct suunto_d9_parser_t {
|
||||
dc_parser_t base;
|
||||
unsigned int model;
|
||||
unsigned int serial;
|
||||
// Cached fields.
|
||||
unsigned int cached;
|
||||
unsigned int mode;
|
||||
@ -230,7 +232,7 @@ suunto_d9_parser_cache (suunto_d9_parser_t *parser)
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
suunto_d9_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
suunto_d9_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model, unsigned int serial)
|
||||
{
|
||||
suunto_d9_parser_t *parser = NULL;
|
||||
|
||||
@ -246,6 +248,7 @@ suunto_d9_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int
|
||||
|
||||
// Set the default values.
|
||||
parser->model = model;
|
||||
parser->serial = serial;
|
||||
parser->cached = 0;
|
||||
parser->mode = AIR;
|
||||
parser->ngasmixes = 0;
|
||||
@ -323,6 +326,7 @@ suunto_d9_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define BUFLEN 16
|
||||
|
||||
static dc_status_t
|
||||
suunto_d9_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
|
||||
@ -338,6 +342,9 @@ suunto_d9_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigne
|
||||
return rc;
|
||||
|
||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||
dc_field_string_t *string = (dc_field_string_t *) value;
|
||||
|
||||
char buf[BUFLEN];
|
||||
|
||||
if (value) {
|
||||
switch (type) {
|
||||
@ -384,6 +391,17 @@ suunto_d9_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigne
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_STRING:
|
||||
switch (flags) {
|
||||
case 0: /* serial */
|
||||
string->desc = "Serial";
|
||||
snprintf(buf, BUFLEN, "%08u", parser->serial);
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
string->value = strdup(buf);
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
@ -519,6 +519,7 @@ static int initialize_eonsteel(suunto_eonsteel_device_t *eon)
|
||||
dc_usbhid_set_timeout(eon->usbhid, 10);
|
||||
|
||||
/* Get rid of any pending stale input first */
|
||||
/* NOTE! This will cause an annoying warning from dc_usbhid_read() */
|
||||
for (;;) {
|
||||
size_t transferred = 0;
|
||||
|
||||
|
||||
@ -21,8 +21,16 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Wow. MSC is truly crap */
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
#include <libdivecomputer/suunto_eonsteel.h>
|
||||
|
||||
@ -82,6 +90,7 @@ struct type_desc {
|
||||
|
||||
#define MAXTYPE 512
|
||||
#define MAXGASES 16
|
||||
#define MAXSTRINGS 32
|
||||
|
||||
typedef struct suunto_eonsteel_parser_t {
|
||||
dc_parser_t base;
|
||||
@ -100,7 +109,8 @@ typedef struct suunto_eonsteel_parser_t {
|
||||
double lowsetpoint;
|
||||
double highsetpoint;
|
||||
double customsetpoint;
|
||||
dc_tankvolume_t tankinfo[MAXGASES];
|
||||
dc_field_string_t strings[MAXSTRINGS];
|
||||
dc_tankinfo_t tankinfo[MAXGASES];
|
||||
double tanksize[MAXGASES];
|
||||
double tankworkingpressure[MAXGASES];
|
||||
} cache;
|
||||
@ -108,11 +118,6 @@ typedef struct suunto_eonsteel_parser_t {
|
||||
|
||||
typedef int (*eon_data_cb_t)(unsigned short type, const struct type_desc *desc, const unsigned char *data, int len, void *user);
|
||||
|
||||
typedef struct eon_event_t {
|
||||
const char *name;
|
||||
parser_sample_event_t type;
|
||||
} eon_event_t;
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
enum eon_sample type;
|
||||
@ -178,16 +183,6 @@ static enum eon_sample lookup_descriptor_type(suunto_eonsteel_parser_t *eon, str
|
||||
return ES_none;
|
||||
}
|
||||
|
||||
static parser_sample_event_t lookup_event(const char *name, const eon_event_t events[], size_t n)
|
||||
{
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
if (!strcasecmp(name, events[i].name))
|
||||
return events[i].type;
|
||||
}
|
||||
|
||||
return SAMPLE_EVENT_NONE;
|
||||
}
|
||||
|
||||
static const char *desc_type_name(enum eon_sample type)
|
||||
{
|
||||
int i;
|
||||
@ -691,26 +686,17 @@ static void sample_event_state_type(const struct type_desc *desc, struct sample_
|
||||
static void sample_event_state_value(const struct type_desc *desc, struct sample_data *info, unsigned char value)
|
||||
{
|
||||
dc_sample_value_t sample = {0};
|
||||
static const eon_event_t states[] = {
|
||||
{"Wet Outside", SAMPLE_EVENT_NONE},
|
||||
{"Below Wet Activation Depth", SAMPLE_EVENT_NONE},
|
||||
{"Below Surface", SAMPLE_EVENT_NONE},
|
||||
{"Dive Active", SAMPLE_EVENT_NONE},
|
||||
{"Surface Calculation", SAMPLE_EVENT_NONE},
|
||||
{"Tank pressure available", SAMPLE_EVENT_NONE},
|
||||
{"Closed Circuit Mode", SAMPLE_EVENT_NONE},
|
||||
};
|
||||
const char *name;
|
||||
|
||||
name = info->state_type;
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
sample.event.type = lookup_event(name, states, C_ARRAY_SIZE(states));
|
||||
if (sample.event.type == SAMPLE_EVENT_NONE)
|
||||
return;
|
||||
|
||||
sample.event.type = SAMPLE_EVENT_STRING;
|
||||
sample.event.name = name;
|
||||
sample.event.flags = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END;
|
||||
sample.event.flags |= 1 << SAMPLE_FLAGS_SEVERITY_SHIFT;
|
||||
|
||||
if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata);
|
||||
}
|
||||
|
||||
@ -721,25 +707,6 @@ static void sample_event_notify_type(const struct type_desc *desc, struct sample
|
||||
|
||||
static void sample_event_notify_value(const struct type_desc *desc, struct sample_data *info, unsigned char value)
|
||||
{
|
||||
static const eon_event_t notifications[] = {
|
||||
{"NoFly Time", SAMPLE_EVENT_NONE},
|
||||
{"Depth", SAMPLE_EVENT_NONE},
|
||||
{"Surface Time", SAMPLE_EVENT_NONE},
|
||||
{"Tissue Level", SAMPLE_EVENT_TISSUELEVEL},
|
||||
{"Deco", SAMPLE_EVENT_NONE},
|
||||
{"Deco Window", SAMPLE_EVENT_NONE},
|
||||
{"Safety Stop Ahead", SAMPLE_EVENT_NONE},
|
||||
{"Safety Stop", SAMPLE_EVENT_SAFETYSTOP},
|
||||
{"Safety Stop Broken", SAMPLE_EVENT_CEILING_SAFETYSTOP},
|
||||
{"Deep Stop Ahead", SAMPLE_EVENT_NONE},
|
||||
{"Deep Stop", SAMPLE_EVENT_DEEPSTOP},
|
||||
{"Dive Time", SAMPLE_EVENT_DIVETIME},
|
||||
{"Gas Available", SAMPLE_EVENT_NONE},
|
||||
{"SetPoint Switch", SAMPLE_EVENT_NONE},
|
||||
{"Diluent Hypoxia", SAMPLE_EVENT_NONE},
|
||||
{"Air Time", SAMPLE_EVENT_NONE},
|
||||
{"Tank Pressure", SAMPLE_EVENT_NONE},
|
||||
};
|
||||
dc_sample_value_t sample = {0};
|
||||
const char *name;
|
||||
|
||||
@ -747,11 +714,11 @@ static void sample_event_notify_value(const struct type_desc *desc, struct sampl
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
sample.event.type = lookup_event(name, notifications, C_ARRAY_SIZE(notifications));
|
||||
if (sample.event.type == SAMPLE_EVENT_NONE)
|
||||
return;
|
||||
|
||||
sample.event.type = SAMPLE_EVENT_STRING;
|
||||
sample.event.name = name;
|
||||
sample.event.flags = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END;
|
||||
sample.event.flags |= 2 << SAMPLE_FLAGS_SEVERITY_SHIFT;
|
||||
|
||||
if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata);
|
||||
}
|
||||
|
||||
@ -763,22 +730,6 @@ static void sample_event_warning_type(const struct type_desc *desc, struct sampl
|
||||
|
||||
static void sample_event_warning_value(const struct type_desc *desc, struct sample_data *info, unsigned char value)
|
||||
{
|
||||
static const eon_event_t warnings[] = {
|
||||
{"ICD Penalty", SAMPLE_EVENT_NONE},
|
||||
{"Deep Stop Penalty", SAMPLE_EVENT_VIOLATION},
|
||||
{"Mandatory Safety Stop", SAMPLE_EVENT_SAFETYSTOP_MANDATORY},
|
||||
{"OTU250", SAMPLE_EVENT_NONE},
|
||||
{"OTU300", SAMPLE_EVENT_NONE},
|
||||
{"CNS80%", SAMPLE_EVENT_NONE},
|
||||
{"CNS100%", SAMPLE_EVENT_NONE},
|
||||
{"Max.Depth", SAMPLE_EVENT_MAXDEPTH},
|
||||
{"Air Time", SAMPLE_EVENT_AIRTIME},
|
||||
{"Tank Pressure", SAMPLE_EVENT_NONE},
|
||||
{"Safety Stop Broken", SAMPLE_EVENT_CEILING_SAFETYSTOP},
|
||||
{"Deep Stop Broken", SAMPLE_EVENT_CEILING_SAFETYSTOP},
|
||||
{"Ceiling Broken", SAMPLE_EVENT_CEILING},
|
||||
{"PO2 High", SAMPLE_EVENT_PO2},
|
||||
};
|
||||
dc_sample_value_t sample = {0};
|
||||
const char *name;
|
||||
|
||||
@ -786,11 +737,11 @@ static void sample_event_warning_value(const struct type_desc *desc, struct samp
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
sample.event.type = lookup_event(name, warnings, C_ARRAY_SIZE(warnings));
|
||||
if (sample.event.type == SAMPLE_EVENT_NONE)
|
||||
return;
|
||||
|
||||
sample.event.type = SAMPLE_EVENT_STRING;
|
||||
sample.event.name = name;
|
||||
sample.event.flags = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END;
|
||||
sample.event.flags |= 3 << SAMPLE_FLAGS_SEVERITY_SHIFT;
|
||||
|
||||
if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata);
|
||||
}
|
||||
|
||||
@ -802,27 +753,18 @@ static void sample_event_alarm_type(const struct type_desc *desc, struct sample_
|
||||
|
||||
static void sample_event_alarm_value(const struct type_desc *desc, struct sample_data *info, unsigned char value)
|
||||
{
|
||||
static const eon_event_t alarms[] = {
|
||||
{"Mandatory Safety Stop Broken", SAMPLE_EVENT_CEILING_SAFETYSTOP},
|
||||
{"Ascent Speed", SAMPLE_EVENT_ASCENT},
|
||||
{"Diluent Hyperoxia", SAMPLE_EVENT_NONE},
|
||||
{"Violated Deep Stop", SAMPLE_EVENT_VIOLATION},
|
||||
{"Ceiling Broken", SAMPLE_EVENT_CEILING},
|
||||
{"PO2 High", SAMPLE_EVENT_PO2},
|
||||
{"PO2 Low", SAMPLE_EVENT_PO2},
|
||||
};
|
||||
dc_sample_value_t sample = {0};
|
||||
const char *name;
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
name = info->alarm_type;
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
sample.event.type = lookup_event(name, alarms, C_ARRAY_SIZE(alarms));
|
||||
if (sample.event.type == SAMPLE_EVENT_NONE)
|
||||
return;
|
||||
|
||||
sample.event.type = SAMPLE_EVENT_STRING;
|
||||
sample.event.name = name;
|
||||
sample.event.flags = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END;
|
||||
sample.event.flags |= 4 << SAMPLE_FLAGS_SEVERITY_SHIFT;
|
||||
|
||||
if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata);
|
||||
}
|
||||
|
||||
@ -1025,6 +967,19 @@ suunto_eonsteel_parser_samples_foreach(dc_parser_t *abstract, dc_sample_callback
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t get_string_field(suunto_eonsteel_parser_t *eon, unsigned idx, dc_field_string_t *value)
|
||||
{
|
||||
if (idx < MAXSTRINGS) {
|
||||
dc_field_string_t *res = eon->cache.strings+idx;
|
||||
if (res->desc && res->value) {
|
||||
*value = *res;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
// Ugly define thing makes the code much easier to read
|
||||
// I'd love to use __typeof__, but that's a gcc'ism
|
||||
#define field_value(p, set) \
|
||||
@ -1093,11 +1048,13 @@ suunto_eonsteel_parser_get_field(dc_parser_t *parser, dc_field_type_t type, unsi
|
||||
* We need to have workpressure and a valid tank. In that case,
|
||||
* a fractional tank size implies imperial.
|
||||
*/
|
||||
if (tank->workpressure && (tank->type == DC_TANKVOLUME_METRIC)) {
|
||||
if (tank->workpressure && (tank->type & DC_TANKINFO_METRIC)) {
|
||||
if (fabs(tank->volume - rint(tank->volume)) > 0.001)
|
||||
tank->type = DC_TANKVOLUME_IMPERIAL;
|
||||
tank->type += DC_TANKINFO_IMPERIAL - DC_TANKINFO_METRIC;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_STRING:
|
||||
return get_string_field(eon, flags, (dc_field_string_t *)value);
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
@ -1144,7 +1101,7 @@ static void set_depth_field(suunto_eonsteel_parser_t *eon, unsigned short d)
|
||||
// "enum:0=Off,1=Primary,2=?,3=Diluent"
|
||||
// "enum:0=Off,1=Primary,3=Diluent,4=Oxygen"
|
||||
//
|
||||
// We turn that into the DC_TANKVOLUME data here, but
|
||||
// We turn that into the DC_TANKINFO data here, but
|
||||
// initially consider all non-off tanks to me METRIC.
|
||||
//
|
||||
// We may later turn the METRIC tank size into IMPERIAL if we
|
||||
@ -1152,7 +1109,7 @@ static void set_depth_field(suunto_eonsteel_parser_t *eon, unsigned short d)
|
||||
static int add_gas_type(suunto_eonsteel_parser_t *eon, const struct type_desc *desc, unsigned char type)
|
||||
{
|
||||
int idx = eon->cache.ngases;
|
||||
dc_tankvolume_t tankinfo = DC_TANKVOLUME_METRIC;
|
||||
dc_tankinfo_t tankinfo = DC_TANKINFO_METRIC;
|
||||
const char *name;
|
||||
|
||||
if (idx >= MAXGASES)
|
||||
@ -1163,9 +1120,9 @@ static int add_gas_type(suunto_eonsteel_parser_t *eon, const struct type_desc *d
|
||||
if (!name)
|
||||
DEBUG(eon->base.context, "Unable to look up gas type %u in %s", type, desc->format);
|
||||
else if (!strcasecmp(name, "Diluent"))
|
||||
;
|
||||
tankinfo |= DC_TANKINFO_CC_DILUENT;
|
||||
else if (!strcasecmp(name, "Oxygen"))
|
||||
;
|
||||
tankinfo |= DC_TANKINFO_CC_O2;
|
||||
else if (!strcasecmp(name, "None"))
|
||||
tankinfo = DC_TANKVOLUME_NONE;
|
||||
else if (strcasecmp(name, "Primary"))
|
||||
@ -1217,6 +1174,42 @@ static int add_gas_workpressure(suunto_eonsteel_parser_t *eon, float wp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_string(suunto_eonsteel_parser_t *eon, const char *desc, const char *value)
|
||||
{
|
||||
int i;
|
||||
|
||||
eon->cache.initialized |= 1 << DC_FIELD_STRING;
|
||||
for (i = 0; i < MAXSTRINGS; i++) {
|
||||
dc_field_string_t *str = eon->cache.strings+i;
|
||||
if (str->desc)
|
||||
continue;
|
||||
str->desc = desc;
|
||||
str->value = strdup(value);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_string_fmt(suunto_eonsteel_parser_t *eon, const char *desc, const char *fmt, ...)
|
||||
{
|
||||
char buffer[256];
|
||||
va_list ap;
|
||||
|
||||
/*
|
||||
* We ignore the return value from vsnprintf, and we
|
||||
* always NUL-terminate the destination buffer ourselves.
|
||||
*
|
||||
* That way we don't have to worry about random bad legacy
|
||||
* implementations.
|
||||
*/
|
||||
va_start(ap, fmt);
|
||||
buffer[sizeof(buffer)-1] = 0;
|
||||
(void) vsnprintf(buffer, sizeof(buffer)-1, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return add_string(eon, desc, buffer);
|
||||
}
|
||||
|
||||
static float get_le32_float(const unsigned char *src)
|
||||
{
|
||||
union {
|
||||
@ -1240,7 +1233,16 @@ static int traverse_device_fields(suunto_eonsteel_parser_t *eon, const struct ty
|
||||
const unsigned char *data, int len)
|
||||
{
|
||||
const char *name = desc->desc + strlen("sml.DeviceLog.Device.");
|
||||
|
||||
if (!strcmp(name, "SerialNumber"))
|
||||
return add_string(eon, "Serial", data);
|
||||
if (!strcmp(name, "Info.HW"))
|
||||
return add_string(eon, "HW Version", data);
|
||||
if (!strcmp(name, "Info.SW"))
|
||||
return add_string(eon, "FW Version", data);
|
||||
if (!strcmp(name, "Info.BatteryAtStart"))
|
||||
return add_string(eon, "Battery at start", data);
|
||||
if (!strcmp(name, "Info.BatteryAtEnd"))
|
||||
return add_string(eon, "Battery at end", data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1271,12 +1273,30 @@ static int traverse_gas_fields(suunto_eonsteel_parser_t *eon, const struct type_
|
||||
if (!strcmp(name, ".Gas.Helium"))
|
||||
return add_gas_he(eon, data[0]);
|
||||
|
||||
if (!strcmp(name, ".Gas.TransmitterID"))
|
||||
return add_string(eon, "Transmitter ID", data);
|
||||
|
||||
if (!strcmp(name, ".Gas.TankSize"))
|
||||
return add_gas_size(eon, get_le32_float(data));
|
||||
|
||||
if (!strcmp(name, ".Gas.TankFillPressure"))
|
||||
return add_gas_workpressure(eon, get_le32_float(data));
|
||||
|
||||
// There is a bug with older transmitters, where the transmitter
|
||||
// battery charge returns zero. Rather than returning that bogus
|
||||
// data, just don't return any battery charge information at all.
|
||||
//
|
||||
// Make sure to add all non-battery-charge field checks above this
|
||||
// test, so that it doesn't trigger for anything else.
|
||||
if (!data[0])
|
||||
return 0;
|
||||
|
||||
if (!strcmp(name, ".Gas.TransmitterStartBatteryCharge"))
|
||||
return add_string_fmt(eon, "Transmitter Battery at start", "%d %%", data[0]);
|
||||
|
||||
if (!strcmp(name, ".Gas.TransmitterEndBatteryCharge"))
|
||||
return add_string_fmt(eon, "Transmitter Battery at end", "%d %%", data[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1333,12 +1353,22 @@ static int traverse_diving_fields(suunto_eonsteel_parser_t *eon, const struct ty
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(name, "Algorithm"))
|
||||
return add_string(eon, "Deco algorithm", data);
|
||||
|
||||
if (!strcmp(name, "DiveMode")) {
|
||||
if (!strncmp((const char *)data, "CCR", 3)) {
|
||||
eon->cache.divemode = DC_DIVEMODE_CC;
|
||||
eon->cache.initialized |= 1 << DC_FIELD_DIVEMODE;
|
||||
}
|
||||
return 0;
|
||||
return add_string(eon, "Dive Mode", data);
|
||||
}
|
||||
|
||||
/* Signed byte of conservatism (-2 .. +2) */
|
||||
if (!strcmp(name, "Conservatism")) {
|
||||
int val = *(signed char *)data;
|
||||
|
||||
return add_string_fmt(eon, "Personal Adjustment", "P%d", val);
|
||||
}
|
||||
|
||||
if (!strcmp(name, "LowSetPoint")) {
|
||||
@ -1353,6 +1383,18 @@ static int traverse_diving_fields(suunto_eonsteel_parser_t *eon, const struct ty
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Time recoded in seconds.
|
||||
// Let's just agree to ignore seconds
|
||||
if (!strcmp(name, "DesaturationTime")) {
|
||||
unsigned int time = array_uint32_le(data) / 60;
|
||||
return add_string_fmt(eon, "Desaturation Time", "%d:%02d", time / 60, time % 60);
|
||||
}
|
||||
|
||||
if (!strcmp(name, "SurfaceTime")) {
|
||||
unsigned int time = array_uint32_le(data) / 60;
|
||||
return add_string_fmt(eon, "Surface Time", "%d:%02d", time / 60, time % 60);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1379,6 +1421,8 @@ static int traverse_header_fields(suunto_eonsteel_parser_t *eon, const struct ty
|
||||
eon->cache.maxdepth = d;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(name, "DateTime"))
|
||||
return add_string(eon, "Dive ID", data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user