Add support for the Mares Nemo Air data format.

The Nemo Air contains an extra header which can be detected due to the
presence of a three byte marker sequence. The sample size is larger too.
This commit is contained in:
Jef Driesen 2010-02-26 14:41:10 +00:00
parent 6b09bdb7ef
commit 9b1a89582c
2 changed files with 103 additions and 33 deletions

View File

@ -95,19 +95,31 @@ mares_common_extract_dives (mares_common_device_t *device, const mares_common_la
unsigned int offset = layout->rb_profile_end - layout->rb_profile_begin;
while (offset >= 3) {
// Check for the presence of extra header bytes, which can be detected
// by means of a three byte marker sequence.
unsigned int extra = 0;
const unsigned char marker[3] = {0xAA, 0xBB, 0xCC};
if (memcmp (buffer + offset - 3, marker, sizeof (marker)) == 0) {
extra = 12;
}
// Check for overflows due to incomplete dives.
if (offset < extra + 3)
break;
// Check the dive mode of the logbook entry. Valid modes are
// 0 (air), 1 (EANx), 2 (freedive) or 3 (bottom timer).
// If the ringbuffer has never reached the wrap point before,
// there will be "empty" memory (filled with 0xFF) and
// processing should stop at this point.
unsigned int mode = buffer[offset - 1];
unsigned int mode = buffer[offset - extra - 1];
if (mode == 0xFF)
break;
// The header and sample size are dependant on the dive mode. Only
// in freedive mode, the sizes are different from the other modes.
unsigned int header_size = 53;
unsigned int sample_size = 2;
unsigned int sample_size = (extra ? 5 : 2);
if (mode == 2) {
header_size = 28;
sample_size = 6;
@ -115,13 +127,13 @@ mares_common_extract_dives (mares_common_device_t *device, const mares_common_la
}
// Get the number of samples in the profile data.
unsigned int nsamples = array_uint16_le (buffer + offset - 3);
unsigned int nsamples = array_uint16_le (buffer + offset - extra - 3);
// Calculate the total number of bytes for this dive.
// If the buffer does not contain that much bytes, we reached the
// end of the ringbuffer. The current dive is incomplete (partially
// overwritten with newer data), and processing should stop.
unsigned int nbytes = 2 + nsamples * sample_size + header_size;
unsigned int nbytes = 2 + nsamples * sample_size + header_size + extra;
if (offset < nbytes)
break;
@ -169,7 +181,7 @@ mares_common_extract_dives (mares_common_device_t *device, const mares_common_la
nbytes += idx - layout->rb_freedives_begin;
}
unsigned int fp_offset = offset + length - FP_OFFSET;
unsigned int fp_offset = offset + length - extra - FP_OFFSET;
if (device && memcmp (buffer + fp_offset, device->fingerprint, sizeof (device->fingerprint)) == 0) {
free (buffer);
return DEVICE_STATUS_SUCCESS;

View File

@ -20,6 +20,7 @@
*/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "mares_nemo.h"
@ -32,6 +33,13 @@ typedef struct mares_nemo_parser_t mares_nemo_parser_t;
struct mares_nemo_parser_t {
parser_t base;
/* Internal state */
unsigned int mode;
unsigned int length;
unsigned int sample_count;
unsigned int sample_size;
unsigned int header;
unsigned int extra;
};
static parser_status_t mares_nemo_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size);
@ -74,6 +82,14 @@ mares_nemo_parser_create (parser_t **out)
// Initialize the base class.
parser_init (&parser->base, &mares_nemo_parser_backend);
// Set the default values.
parser->mode = 0;
parser->length = 0;
parser->sample_count = 0;
parser->sample_size = 0;
parser->header = 0;
parser->extra = 0;
*out = (parser_t*) parser;
return PARSER_STATUS_SUCCESS;
@ -96,8 +112,61 @@ mares_nemo_parser_destroy (parser_t *abstract)
static parser_status_t
mares_nemo_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size)
{
if (! parser_is_mares_nemo (abstract))
return PARSER_STATUS_TYPE_MISMATCH;
mares_nemo_parser_t *parser = (mares_nemo_parser_t *) abstract;
// Clear the previous state.
parser->base.data = NULL;
parser->base.size = 0;
parser->mode = 0;
parser->length = 0;
parser->sample_count = 0;
parser->sample_size = 0;
parser->header = 0;
parser->extra = 0;
if (size == 0)
return PARSER_STATUS_SUCCESS;
if (size < 2 + 3)
return PARSER_STATUS_ERROR;
unsigned int length = array_uint16_le (data);
if (length > size)
return PARSER_STATUS_ERROR;
unsigned int extra = 0;
const unsigned char marker[3] = {0xAA, 0xBB, 0xCC};
if (memcmp (data + length - 3, marker, sizeof (marker)) == 0) {
extra = 12;
}
if (length < 2 + extra + 3)
return PARSER_STATUS_ERROR;
unsigned int mode = data[length - extra - 1];
unsigned int header_size = 53;
unsigned int sample_size = (extra ? 5 : 2);
if (mode == 2) {
header_size = 28;
sample_size = 6;
}
unsigned int nsamples = array_uint16_le (data + length - extra - 3);
unsigned int nbytes = 2 + nsamples * sample_size + header_size + extra;
if (length != nbytes)
return PARSER_STATUS_ERROR;
// Store the new state.
parser->base.data = data;
parser->base.size = size;
parser->mode = mode;
parser->length = length;
parser->sample_count = nsamples;
parser->sample_size = sample_size;
parser->header = header_size;
parser->extra = extra;
return PARSER_STATUS_SUCCESS;
}
@ -106,15 +175,12 @@ mares_nemo_parser_set_data (parser_t *abstract, const unsigned char *data, unsig
static parser_status_t
mares_nemo_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime)
{
if (abstract->size < 2)
mares_nemo_parser_t *parser = (mares_nemo_parser_t *) abstract;
if (abstract->size == 0)
return PARSER_STATUS_ERROR;
unsigned int length = array_uint16_le (abstract->data);
if (length < 8 || length > abstract->size)
return PARSER_STATUS_ERROR;
const unsigned char *p = abstract->data + length - 8;
const unsigned char *p = abstract->data + parser->length - parser->extra - 8;
if (datetime) {
datetime->year = p[0] + 2000;
@ -132,28 +198,20 @@ mares_nemo_parser_get_datetime (parser_t *abstract, dc_datetime_t *datetime)
static parser_status_t
mares_nemo_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata)
{
if (! parser_is_mares_nemo (abstract))
return PARSER_STATUS_TYPE_MISMATCH;
mares_nemo_parser_t *parser = (mares_nemo_parser_t *) abstract;
if (abstract->size == 0)
return PARSER_STATUS_ERROR;
const unsigned char *data = abstract->data;
unsigned int size = abstract->size;
if (size < 5)
return PARSER_STATUS_ERROR;
unsigned int length = array_uint16_le (data);
assert (length <= size);
unsigned int mode = data[length - 1];
unsigned int nsamples = array_uint16_le (data + length - 3);
if (mode != 2) {
if (parser->mode != 2) {
unsigned int time = 0;
for (unsigned int i = 0; i < nsamples; ++i) {
for (unsigned int i = 0; i < parser->sample_count; ++i) {
parser_sample_value_t sample = {0};
unsigned int idx = 2 + 2 * i;
unsigned int idx = 2 + parser->sample_size * i;
unsigned int value = array_uint16_le (data + idx);
unsigned int depth = value & 0x0FFF;
unsigned int ascent = (value & 0xC000) >> 14;
@ -202,14 +260,14 @@ mares_nemo_parser_samples_foreach (parser_t *abstract, sample_callback_t callbac
// the normal dive data. We assume a freedive has a detailed profile
// when the buffer contains more data than the size indicated in the
// header.
int profiles = (size > length);
int profiles = (size > parser->length);
unsigned int time = 0;
unsigned int offset = length;
for (unsigned int i = 0; i < nsamples; ++i) {
unsigned int offset = parser->length;
for (unsigned int i = 0; i < parser->sample_count; ++i) {
parser_sample_value_t sample = {0};
unsigned int idx = 2 + 6 * i;
unsigned int idx = 2 + parser->sample_size * i;
unsigned int maxdepth = array_uint16_le (data + idx);
unsigned int divetime = data[idx + 2] + data[idx + 3] * 60;
unsigned int surftime = data[idx + 4] + data[idx + 5] * 60;