Merge branch 'goa-freedive'

This commit is contained in:
Jef Driesen 2020-10-20 13:58:54 +02:00
commit 5b133233f7
5 changed files with 203 additions and 39 deletions

View File

@ -51,6 +51,9 @@ dc_buffer_append (dc_buffer_t *buffer, const unsigned char data[], size_t size);
int
dc_buffer_prepend (dc_buffer_t *buffer, const unsigned char data[], size_t size);
int
dc_buffer_insert (dc_buffer_t *buffer, size_t offset, const unsigned char data[], size_t size);
int
dc_buffer_slice (dc_buffer_t *buffer, size_t offset, size_t size);

View File

@ -231,6 +231,72 @@ dc_buffer_prepend (dc_buffer_t *buffer, const unsigned char data[], size_t size)
}
int
dc_buffer_insert (dc_buffer_t *buffer, size_t offset, const unsigned char data[], size_t size)
{
if (buffer == NULL)
return 0;
if (offset > buffer->size)
return 0;
size_t head = buffer->offset;
size_t tail = buffer->capacity - (buffer->offset + buffer->size);
unsigned char *ptr = buffer->data + buffer->offset;
if (size <= head) {
if (buffer->size)
memmove (ptr - size, ptr, offset);
buffer->offset -= size;
} else if (size <= tail) {
if (buffer->size)
memmove (ptr + offset + size, ptr + offset, buffer->size - offset);
} else if (size <= tail + head) {
size_t n = buffer->size + size;
size_t available = buffer->capacity - n;
size_t tmp_offset = head > tail ? available : 0;
unsigned char *tmp = buffer->data;
if (buffer->size) {
memmove (tmp + tmp_offset, ptr, offset);
memmove (tmp + tmp_offset + offset + size, ptr + offset, buffer->size - offset);
}
buffer->offset = tmp_offset;
} else {
size_t n = buffer->size + size;
size_t capacity = dc_buffer_expand_calc (buffer, n);
size_t available = capacity - n;
size_t tmp_offset = head > tail ? available : 0;
unsigned char *tmp = (unsigned char *) malloc (capacity);
if (tmp == NULL)
return 0;
if (buffer->size) {
memcpy (tmp + tmp_offset, ptr, offset);
memcpy (tmp + tmp_offset + offset + size, ptr + offset, buffer->size - offset);
}
free (buffer->data);
buffer->data = tmp;
buffer->capacity = capacity;
buffer->offset = tmp_offset;
}
if (size)
memcpy (buffer->data + buffer->offset + offset, data, size);
buffer->size += size;
return 1;
}
int
dc_buffer_slice (dc_buffer_t *buffer, size_t offset, size_t size)
{

View File

@ -485,7 +485,19 @@ cressi_goa_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
goto error_free_dive;
}
if (callback && !callback(dive_data, dive_size, dive_data + FP_OFFSET - 5, sizeof(device->fingerprint), userdata))
// Those 5 extra bytes contain the dive mode, which is required for
// parsing the dive data. Therefore, insert all 5 bytes again. The
// remaining 4 bytes appear to be some 32 bit address.
if (!dc_buffer_insert (dive, 2, logbook_data + offset + 2, 5)) {
ERROR (abstract->context, "Out of memory.");
status = DC_STATUS_NOMEMORY;
goto error_free_dive;
}
dive_data = dc_buffer_get_data (dive);
dive_size = dc_buffer_get_size (dive);
if (callback && !callback(dive_data, dive_size, dive_data + FP_OFFSET, sizeof(device->fingerprint), userdata))
break;
}

View File

@ -28,11 +28,23 @@
#define ISINSTANCE(parser) dc_device_isinstance((parser), &cressi_goa_parser_vtable)
#define SZ_HEADER 0x5C
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
#define SZ_HEADER 23
#define SZ_HEADER_SCUBA 0x61
#define SZ_HEADER_FREEDIVE 0x2B
#define SZ_HEADER_GAUGE 0x2D
#define DEPTH 0
#define DEPTH2 1
#define TIME 2
#define TEMPERATURE 3
#define SCUBA 0
#define NITROX 1
#define FREEDIVE 2
#define GAUGE 3
typedef struct cressi_goa_parser_t cressi_goa_parser_t;
struct cressi_goa_parser_t {
@ -58,6 +70,13 @@ static const dc_parser_vtable_t cressi_goa_parser_vtable = {
NULL /* destroy */
};
static const unsigned int headersizes[] = {
SZ_HEADER_SCUBA,
SZ_HEADER_SCUBA,
SZ_HEADER_FREEDIVE,
SZ_HEADER_GAUGE,
};
dc_status_t
cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{
@ -97,17 +116,29 @@ cressi_goa_parser_set_data (dc_parser_t *abstract, const unsigned char *data, un
static dc_status_t
cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{
if (abstract->size < SZ_HEADER)
const unsigned char *data = abstract->data;
unsigned int size = abstract->size;
if (size < SZ_HEADER)
return DC_STATUS_DATAFORMAT;
const unsigned char *p = abstract->data;
unsigned int divemode = data[2];
if (divemode >= C_ARRAY_SIZE(headersizes)) {
return DC_STATUS_DATAFORMAT;
}
unsigned int headersize = headersizes[divemode];
if (size < headersize)
return DC_STATUS_DATAFORMAT;
const unsigned char *p = abstract->data + 0x11;
if (datetime) {
datetime->year = array_uint16_le(p + 0x0C);
datetime->month = p[0x0E];
datetime->day = p[0x0F];
datetime->hour = p[0x10];
datetime->minute = p[0x11];
datetime->year = array_uint16_le(p);
datetime->month = p[2];
datetime->day = p[3];
datetime->hour = p[4];
datetime->minute = p[5];
datetime->second = 0;
datetime->timezone = DC_TIMEZONE_NONE;
}
@ -119,10 +150,20 @@ static dc_status_t
cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
{
cressi_goa_parser_t *parser = (cressi_goa_parser_t *) abstract;
if (abstract->size < SZ_HEADER)
const unsigned char *data = abstract->data;
unsigned int size = abstract->size;
if (size < SZ_HEADER)
return DC_STATUS_DATAFORMAT;
const unsigned char *data = abstract->data;
unsigned int divemode = data[2];
if (divemode >= C_ARRAY_SIZE(headersizes)) {
return DC_STATUS_DATAFORMAT;
}
unsigned int headersize = headersizes[divemode];
if (size < headersize)
return DC_STATUS_DATAFORMAT;
if (!parser->cached) {
sample_statistics_t statistics = SAMPLE_STATISTICS_INITIALIZER;
@ -140,19 +181,35 @@ cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
if (value) {
switch (type) {
case DC_FIELD_DIVETIME:
*((unsigned int *) value) = array_uint16_le (data + 0x14);
*((unsigned int *) value) = array_uint16_le (data + 0x19);
break;
case DC_FIELD_MAXDEPTH:
*((double *) value) = parser->maxdepth;
break;
case DC_FIELD_GASMIX_COUNT:
*((unsigned int *) value) = 2;
*((unsigned int *) value) = divemode == SCUBA || divemode == NITROX ? 2 : 0;
break;
case DC_FIELD_GASMIX:
gasmix->helium = 0.0;
gasmix->oxygen = data[0x1B + 2 * flags] / 100.0;
gasmix->oxygen = data[0x20 + 2 * flags] / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
break;
case DC_FIELD_DIVEMODE:
switch (divemode) {
case SCUBA:
case NITROX:
*((dc_divemode_t *) value) = DC_DIVEMODE_OC;
break;
case GAUGE:
*((dc_divemode_t *) value) = DC_DIVEMODE_GAUGE;
break;
case FREEDIVE:
*((dc_divemode_t *) value) = DC_DIVEMODE_FREEDIVE;
break;
default:
return DC_STATUS_DATAFORMAT;
}
break;
default:
return DC_STATUS_UNSUPPORTED;
}
@ -167,12 +224,28 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
const unsigned char *data = abstract->data;
unsigned int size = abstract->size;
unsigned int time = 0;
unsigned int interval = 5;
unsigned int complete = 1;
unsigned int gasmix_previous = 0xFFFFFFFF;
if (size < SZ_HEADER)
return DC_STATUS_DATAFORMAT;
unsigned int offset = SZ_HEADER;
unsigned int divemode = data[2];
if (divemode >= C_ARRAY_SIZE(headersizes)) {
return DC_STATUS_DATAFORMAT;
}
unsigned int headersize = headersizes[divemode];
if (size < headersize)
return DC_STATUS_DATAFORMAT;
unsigned int interval = divemode == FREEDIVE ? 2 : 5;
unsigned int time = 0;
unsigned int depth = 0;
unsigned int gasmix = 0, gasmix_previous = 0xFFFFFFFF;
unsigned int temperature = 0;
unsigned int have_temperature = 0;
unsigned int complete = 0;
unsigned int offset = headersize;
while (offset + 2 <= size) {
dc_sample_value_t sample = {0};
@ -181,35 +254,44 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
unsigned int type = (raw & 0x0003);
unsigned int value = (raw & 0xFFFC) >> 2;
if (complete) {
// Time (seconds).
if (type == DEPTH || type == DEPTH2) {
depth = (value & 0x07FF);
gasmix = (value & 0x0800) >> 11;
time += interval;
sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
complete = 0;
complete = 1;
} else if (type == TEMPERATURE) {
temperature = value;
have_temperature = 1;
} else if (type == TIME) {
time += value;
}
if (type == DEPTH) {
if (complete) {
// Time (seconds).
sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Temperature (1/10 °C).
if (have_temperature) {
sample.temperature = temperature / 10.0;
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
have_temperature = 0;
}
// Depth (1/10 m).
unsigned int depth = value & 0x07FF;
sample.depth = depth / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Gas change.
unsigned int gasmix = (value & 0x0800) >> 11;
if (gasmix != gasmix_previous) {
sample.gasmix = gasmix;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
gasmix_previous = gasmix;
// Gas change
if (divemode == SCUBA || divemode == NITROX) {
if (gasmix != gasmix_previous) {
sample.gasmix = gasmix;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
gasmix_previous = gasmix;
}
}
complete = 1;
} else if (type == TEMPERATURE) {
// Temperature (1/10 °C).
sample.temperature = value / 10.0;
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
} else {
WARNING(abstract->context, "Unknown sample type %u.", type);
complete = 0;
}
offset += 2;

View File

@ -8,6 +8,7 @@ dc_buffer_reserve
dc_buffer_resize
dc_buffer_append
dc_buffer_prepend
dc_buffer_insert
dc_buffer_slice
dc_buffer_get_size
dc_buffer_get_data