diff --git a/examples/universal.c b/examples/universal.c
index 56b1946..136454d 100644
--- a/examples/universal.c
+++ b/examples/universal.c
@@ -103,6 +103,7 @@ static const backend_table_t g_backends[] = {
{"predator", DC_FAMILY_SHEARWATER_PREDATOR},
{"petrel", DC_FAMILY_SHEARWATER_PETREL},
{"nitekq", DC_FAMILY_DIVERITE_NITEKQ},
+ {"aqualand", DC_FAMILY_CITIZEN_AQUALAND},
};
static dc_family_t
diff --git a/include/libdivecomputer/Makefile.am b/include/libdivecomputer/Makefile.am
index 891f4e0..3221d22 100644
--- a/include/libdivecomputer/Makefile.am
+++ b/include/libdivecomputer/Makefile.am
@@ -49,4 +49,6 @@ libdivecomputer_HEADERS = \
shearwater_petrel.h \
shearwater_predator.h \
diverite.h \
- diverite_nitekq.h
+ diverite_nitekq.h \
+ citizen.h \
+ citizen_aqualand.h
diff --git a/include/libdivecomputer/citizen.h b/include/libdivecomputer/citizen.h
new file mode 100644
index 0000000..01b7027
--- /dev/null
+++ b/include/libdivecomputer/citizen.h
@@ -0,0 +1,27 @@
+/*
+ * libdivecomputer
+ *
+ * Copyright (C) 2014 Jef Driesen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#ifndef CITIZEN_H
+#define CITIZEN_H
+
+#include "citizen_aqualand.h"
+
+#endif /* CITIZEN_H */
diff --git a/include/libdivecomputer/citizen_aqualand.h b/include/libdivecomputer/citizen_aqualand.h
new file mode 100644
index 0000000..2b703a4
--- /dev/null
+++ b/include/libdivecomputer/citizen_aqualand.h
@@ -0,0 +1,42 @@
+/*
+ * libdivecomputer
+ *
+ * Copyright (C) 2014 Jef Driesen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#ifndef CITIZEN_AQUALAND_H
+#define CITIZEN_AQUALAND_H
+
+#include "context.h"
+#include "device.h"
+#include "parser.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+dc_status_t
+citizen_aqualand_device_open (dc_device_t **device, dc_context_t *context, const char *name);
+
+dc_status_t
+citizen_aqualand_parser_create (dc_parser_t **parser, dc_context_t *context);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* CITIZEN_AQUALAND_H */
diff --git a/include/libdivecomputer/common.h b/include/libdivecomputer/common.h
index 4bcc700..708fd00 100644
--- a/include/libdivecomputer/common.h
+++ b/include/libdivecomputer/common.h
@@ -84,6 +84,8 @@ typedef enum dc_family_t {
DC_FAMILY_SHEARWATER_PETREL,
/* Dive Rite */
DC_FAMILY_DIVERITE_NITEKQ = (11 << 16),
+ /* Citizen */
+ DC_FAMILY_CITIZEN_AQUALAND = (12 << 16),
} dc_family_t;
#ifdef __cplusplus
diff --git a/msvc/libdivecomputer.vcproj b/msvc/libdivecomputer.vcproj
index ff22d90..2fea2b9 100644
--- a/msvc/libdivecomputer.vcproj
+++ b/msvc/libdivecomputer.vcproj
@@ -198,6 +198,14 @@
RelativePath="..\src\checksum.c"
>
+
+
+
+
@@ -488,6 +496,14 @@
RelativePath="..\src\checksum.h"
>
+
+
+
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 458f1dd..1f52841 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -53,6 +53,7 @@ libdivecomputer_la_SOURCES = \
shearwater_predator.c shearwater_predator_parser.c \
shearwater_petrel.c \
diverite_nitekq.c diverite_nitekq_parser.c \
+ citizen_aqualand.c citizen_aqualand_parser.c \
ringbuffer.h ringbuffer.c \
checksum.h checksum.c \
array.h array.c \
diff --git a/src/citizen_aqualand.c b/src/citizen_aqualand.c
new file mode 100644
index 0000000..dc291b4
--- /dev/null
+++ b/src/citizen_aqualand.c
@@ -0,0 +1,236 @@
+/*
+ * libdivecomputer
+ *
+ * Copyright (C) 2014 Jef Driesen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include // memcmp, memcpy
+#include // malloc, free
+
+#include
+
+#include "context-private.h"
+#include "device-private.h"
+#include "serial.h"
+#include "checksum.h"
+#include "ringbuffer.h"
+#include "array.h"
+
+#define ISINSTANCE(device) dc_device_isinstance((device), &citizen_aqualand_device_vtable)
+
+#define EXITCODE(rc) \
+( \
+ rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
+)
+
+typedef struct citizen_aqualand_device_t {
+ dc_device_t base;
+ serial_t *port;
+ unsigned char fingerprint[8];
+} citizen_aqualand_device_t;
+
+static dc_status_t citizen_aqualand_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
+static dc_status_t citizen_aqualand_device_dump (dc_device_t *abstract, dc_buffer_t *buffer);
+static dc_status_t citizen_aqualand_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
+static dc_status_t citizen_aqualand_device_close (dc_device_t *abstract);
+
+static const dc_device_vtable_t citizen_aqualand_device_vtable = {
+ DC_FAMILY_CITIZEN_AQUALAND,
+ citizen_aqualand_device_set_fingerprint, /* set_fingerprint */
+ NULL, /* read */
+ NULL, /* write */
+ citizen_aqualand_device_dump, /* dump */
+ citizen_aqualand_device_foreach, /* foreach */
+ citizen_aqualand_device_close /* close */
+};
+
+
+dc_status_t
+citizen_aqualand_device_open (dc_device_t **out, dc_context_t *context, const char *name)
+{
+ if (out == NULL)
+ return DC_STATUS_INVALIDARGS;
+
+ // Allocate memory.
+ citizen_aqualand_device_t *device = (citizen_aqualand_device_t *) malloc (sizeof (citizen_aqualand_device_t));
+ if (device == NULL) {
+ ERROR (context, "Failed to allocate memory.");
+ return DC_STATUS_NOMEMORY;
+ }
+
+ // Initialize the base class.
+ device_init (&device->base, context, &citizen_aqualand_device_vtable);
+
+ // Set the default values.
+ device->port = NULL;
+ memset (device->fingerprint, 0, sizeof (device->fingerprint));
+
+ // Open the device.
+ int rc = serial_open (&device->port, context, name);
+ if (rc == -1) {
+ ERROR (context, "Failed to open the serial port.");
+ free (device);
+ return DC_STATUS_IO;
+ }
+
+ // Set the serial communication protocol (4800 8N1).
+ rc = serial_configure (device->port, 4800, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
+ if (rc == -1) {
+ ERROR (context, "Failed to set the terminal attributes.");
+ serial_close (device->port);
+ free (device);
+ return DC_STATUS_IO;
+ }
+
+ // Set the timeout for receiving data (1000ms).
+ if (serial_set_timeout (device->port, 1000) == -1) {
+ ERROR (context, "Failed to set the timeout.");
+ serial_close (device->port);
+ free (device);
+ return DC_STATUS_IO;
+ }
+
+ // Make sure everything is in a sane state.
+ serial_sleep (device->port, 300);
+ serial_flush (device->port, SERIAL_QUEUE_BOTH);
+
+ *out = (dc_device_t *) device;
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+static dc_status_t
+citizen_aqualand_device_close (dc_device_t *abstract)
+{
+ citizen_aqualand_device_t *device = (citizen_aqualand_device_t*) abstract;
+
+ // Close the device.
+ if (serial_close (device->port) == -1) {
+ free (device);
+ return DC_STATUS_IO;
+ }
+
+ // Free memory.
+ free (device);
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+static dc_status_t
+citizen_aqualand_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size)
+{
+ citizen_aqualand_device_t *device = (citizen_aqualand_device_t *) abstract;
+
+ if (size && size != sizeof (device->fingerprint))
+ return DC_STATUS_INVALIDARGS;
+
+ if (size)
+ memcpy (device->fingerprint, data, sizeof (device->fingerprint));
+ else
+ memset (device->fingerprint, 0, sizeof (device->fingerprint));
+
+ return DC_STATUS_SUCCESS;
+}
+
+static dc_status_t
+citizen_aqualand_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
+{
+ citizen_aqualand_device_t *device = (citizen_aqualand_device_t *) abstract;
+
+ // Erase the current contents of the buffer and
+ // pre-allocate the required amount of memory.
+ if (!dc_buffer_clear (buffer)) {
+ ERROR (abstract->context, "Insufficient buffer space available.");
+ return DC_STATUS_NOMEMORY;
+ }
+
+ serial_set_dtr (device->port, 1);
+
+ // Send the init byte.
+ const unsigned char init[] = {0x7F};
+ int n = serial_write (device->port, init, sizeof (init));
+ if (n != sizeof (init)) {
+ ERROR (abstract->context, "Failed to send the command.");
+ return EXITCODE (n);
+ }
+
+ serial_sleep(device->port, 1200);
+
+ // Send the command.
+ const unsigned char command[] = {0xFF};
+ n = serial_write (device->port, command, sizeof (command));
+ if (n != sizeof (command)) {
+ ERROR (abstract->context, "Failed to send the command.");
+ return EXITCODE (n);
+ }
+
+ while (1) {
+ // Receive the response packet.
+ unsigned char answer[32] = {0};
+ n = serial_read (device->port, answer, sizeof (answer));
+ if (n != sizeof (answer)) {
+ ERROR (abstract->context, "Failed to receive the answer.");
+ return EXITCODE (n);
+ }
+
+ dc_buffer_append(buffer, answer, sizeof (answer));
+
+ // Send the command.
+ n = serial_write (device->port, command, sizeof (command));
+ if (n != sizeof (command)) {
+ ERROR (abstract->context, "Failed to send the command.");
+ return EXITCODE (n);
+ }
+
+ if (answer[sizeof(answer) - 1] == 0xFF)
+ break;
+ }
+
+ serial_set_dtr (device->port, 0);
+
+ return DC_STATUS_SUCCESS;
+}
+
+static dc_status_t
+citizen_aqualand_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
+{
+ citizen_aqualand_device_t *device = (citizen_aqualand_device_t *) abstract;
+
+ dc_buffer_t *buffer = dc_buffer_new (0);
+ if (buffer == NULL)
+ return DC_STATUS_NOMEMORY;
+
+ dc_status_t rc = citizen_aqualand_device_dump (abstract, buffer);
+ if (rc != DC_STATUS_SUCCESS) {
+ dc_buffer_free (buffer);
+ return rc;
+ }
+
+ unsigned char *data = dc_buffer_get_data (buffer);
+ unsigned int size = dc_buffer_get_size (buffer);
+
+ if (callback && memcmp (data + 0x05, device->fingerprint, sizeof (device->fingerprint)) != 0) {
+ callback (data, size, data + 0x05, sizeof (device->fingerprint), userdata);
+ }
+
+ dc_buffer_free (buffer);
+
+ return rc;
+}
diff --git a/src/citizen_aqualand_parser.c b/src/citizen_aqualand_parser.c
new file mode 100644
index 0000000..e9c2659
--- /dev/null
+++ b/src/citizen_aqualand_parser.c
@@ -0,0 +1,275 @@
+/*
+ * libdivecomputer
+ *
+ * Copyright (C) 2014 Jef Driesen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include
+
+#include
+#include
+
+#include "context-private.h"
+#include "parser-private.h"
+#include "array.h"
+
+#define ISINSTANCE(parser) dc_device_isinstance((parser), &citizen_aqualand_parser_vtable)
+
+#define SZ_HEADER 32
+
+typedef struct citizen_aqualand_parser_t {
+ dc_parser_t base;
+} citizen_aqualand_parser_t;
+
+static dc_status_t citizen_aqualand_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
+static dc_status_t citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
+static dc_status_t citizen_aqualand_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
+static dc_status_t citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
+static dc_status_t citizen_aqualand_parser_destroy (dc_parser_t *abstract);
+
+static const dc_parser_vtable_t citizen_aqualand_parser_vtable = {
+ DC_FAMILY_CITIZEN_AQUALAND,
+ citizen_aqualand_parser_set_data, /* set_data */
+ citizen_aqualand_parser_get_datetime, /* datetime */
+ citizen_aqualand_parser_get_field, /* fields */
+ citizen_aqualand_parser_samples_foreach, /* samples_foreach */
+ citizen_aqualand_parser_destroy /* destroy */
+};
+
+
+dc_status_t
+citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context)
+{
+ if (out == NULL)
+ return DC_STATUS_INVALIDARGS;
+
+ // Allocate memory.
+ citizen_aqualand_parser_t *parser = (citizen_aqualand_parser_t *) malloc (sizeof (citizen_aqualand_parser_t));
+ if (parser == NULL) {
+ ERROR (context, "Failed to allocate memory.");
+ return DC_STATUS_NOMEMORY;
+ }
+
+ // Initialize the base class.
+ parser_init (&parser->base, context, &citizen_aqualand_parser_vtable);
+
+ *out = (dc_parser_t*) parser;
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+static dc_status_t
+citizen_aqualand_parser_destroy (dc_parser_t *abstract)
+{
+ // Free memory.
+ free (abstract);
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+static dc_status_t
+citizen_aqualand_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
+{
+ return DC_STATUS_SUCCESS;
+}
+
+
+static dc_status_t
+citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
+{
+ if (abstract->size < SZ_HEADER)
+ return DC_STATUS_DATAFORMAT;
+
+ const unsigned char *p = abstract->data;
+
+ if (datetime) {
+ datetime->year = bcd2dec(p[0x05]) * 100 + bcd2dec(p[0x06]);
+ datetime->month = bcd2dec(p[0x07]);
+ datetime->day = bcd2dec(p[0x08]);
+ datetime->hour = bcd2dec(p[0x0A]);
+ datetime->minute = bcd2dec(p[0x0B]);
+ datetime->second = bcd2dec(p[0x0C]);
+ }
+
+ return DC_STATUS_SUCCESS;
+}
+
+
+static dc_status_t
+citizen_aqualand_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
+{
+ if (abstract->size < SZ_HEADER)
+ return DC_STATUS_DATAFORMAT;
+
+ const unsigned char *data = abstract->data;
+
+ unsigned int metric = (data[0x04] == 0xA6 ? 0 : 1);
+ unsigned int maxdepth = bcd2dec(data[0x12]) * 10 + ((data[0x13] >> 4) & 0x0F);
+ unsigned int divetime = (data[0x16] & 0x0F) * 100 + bcd2dec(data[0x17]);
+
+ if (value) {
+ switch (type) {
+ case DC_FIELD_DIVETIME:
+ *((unsigned int *) value) = divetime * 60;
+ break;
+ case DC_FIELD_MAXDEPTH:
+ if (metric)
+ *((double *) value) = maxdepth / 10.0;
+ else
+ *((double *) value) = maxdepth * FEET;
+ break;
+ case DC_FIELD_GASMIX_COUNT:
+ *((unsigned int *) value) = 0;
+ break;
+ default:
+ return DC_STATUS_UNSUPPORTED;
+ }
+ }
+
+ return DC_STATUS_SUCCESS;
+}
+
+static dc_status_t
+citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
+{
+ const unsigned char *data = abstract->data;
+ unsigned int size = abstract->size;
+
+ if (size < SZ_HEADER)
+ return DC_STATUS_DATAFORMAT;
+
+ // Estimate the maximum number of samples. We calculate the number of
+ // 12 bit values that fit in the available profile data, and round the
+ // result upwards. The actual number of samples should always be smaller
+ // due to the presence of at least two end markers.
+ unsigned int maxcount = (2 * (size - SZ_HEADER) + 2) / 3;
+
+ // Allocate storage for the processed 16 bit samples.
+ unsigned short *samples = (unsigned short *) malloc(maxcount * sizeof(unsigned short));
+ if (samples == NULL) {
+ return DC_STATUS_NOMEMORY;
+ }
+
+ // Pre-process the depth and temperature tables. The 12 bit BCD encoded
+ // values are converted into an array of 16 bit values, which is much
+ // more convenient to process in the second stage.
+ unsigned int nsamples = 0;
+ unsigned int count[2] = {0, 0};
+ unsigned int offset = SZ_HEADER * 2;
+ unsigned int length = size * 2;
+ for (unsigned int i = 0; i < 2; ++i) {
+ const unsigned int marker = (i == 0 ? 0xEF : 0xFF);
+
+ while (offset + 3 <= length) {
+ unsigned int value = 0;
+ unsigned int octet = offset / 2;
+ unsigned int nibble = offset % 2;
+ unsigned int hi = data[octet];
+ unsigned int lo = data[octet + 1];
+
+ // Check for the end marker.
+ if (hi == marker || lo == marker) {
+ offset += nibble;
+ break;
+ }
+
+ // Convert 12 bit BCD to decimal.
+ if (nibble) {
+ value = ((hi ) & 0x0F) * 100 +
+ ((lo >> 4) & 0x0F) * 10 +
+ ((lo ) & 0x0F);
+ } else {
+ value = ((hi >> 4) & 0x0F) * 100 +
+ ((hi ) & 0x0F) * 10 +
+ ((lo >> 4) & 0x0F);
+ }
+
+ // Store the value.
+ samples[nsamples] = value;
+ count[i]++;
+ nsamples++;
+
+ offset += 3;
+ }
+
+ // Verify the end marker.
+ if (offset + 2 > length || data[offset / 2] != marker) {
+ ERROR (abstract->context, "No end marker found.");
+ free(samples);
+ return DC_STATUS_DATAFORMAT;
+ }
+
+ offset += 2;
+ }
+
+ unsigned int time = 0;
+ unsigned int interval = 5;
+ unsigned int metric = (data[0x04] == 0xA6 ? 0 : 1);
+ for (unsigned int i = 0; i < count[0]; ++i) {
+ dc_sample_value_t sample = {0};
+
+ // Get the depth value.
+ unsigned int depth = samples[i];
+
+ // Every 12th sample there is a strange sample that always contains
+ // the value 999. This is clearly not a valid depth, but when trying
+ // to skip these samples, the depth and temperatures go out of sync.
+ // Therefore we replace the bogus sample with an interpolated value.
+ if (depth == 999) {
+ depth = 0;
+ if (i > 0) {
+ depth += samples[i - 1];
+ }
+ if (i < count[0] - 1) {
+ depth += samples[i + 1];
+ }
+ depth /= 2;
+ }
+
+ // Time
+ time += interval;
+ sample.time = time;
+ if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
+
+ // Depth
+ if (metric)
+ sample.depth = depth / 10.0;
+ else
+ sample.depth = depth * FEET;
+ if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
+
+ // Temperature
+ if (time % 300 == 0) {
+ unsigned int idx = count[0] + time / 300;
+ if (idx < nsamples) {
+ unsigned int temperature = samples[idx];
+ if (metric)
+ sample.temperature = temperature / 10.0;
+ else
+ sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
+ if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
+ }
+ }
+ }
+
+ free(samples);
+
+ return DC_STATUS_SUCCESS;
+}
diff --git a/src/descriptor.c b/src/descriptor.c
index 22ebe7c..93525e9 100644
--- a/src/descriptor.c
+++ b/src/descriptor.c
@@ -230,6 +230,8 @@ static const dc_descriptor_t g_descriptors[] = {
{"Shearwater", "Petrel", DC_FAMILY_SHEARWATER_PETREL, 3},
/* Dive Rite NiTek Q */
{"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0},
+ /* Citizen Hyper Aqualand */
+ {"Citizen", "Hyper Aqualand", DC_FAMILY_CITIZEN_AQUALAND, 0},
};
typedef struct dc_descriptor_iterator_t {
diff --git a/src/device.c b/src/device.c
index edc1cf2..909bac3 100644
--- a/src/device.c
+++ b/src/device.c
@@ -34,6 +34,7 @@
#include
#include
#include
+#include
#include "device-private.h"
#include "context-private.h"
@@ -157,6 +158,9 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
case DC_FAMILY_DIVERITE_NITEKQ:
rc = diverite_nitekq_device_open (&device, context, name);
break;
+ case DC_FAMILY_CITIZEN_AQUALAND:
+ rc = citizen_aqualand_device_open (&device, context, name);
+ break;
default:
return DC_STATUS_INVALIDARGS;
}
diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols
index 55852ae..8dfd7be 100644
--- a/src/libdivecomputer.symbols
+++ b/src/libdivecomputer.symbols
@@ -68,6 +68,7 @@ atomics_cobalt_parser_set_calibration
shearwater_predator_parser_create
shearwater_petrel_parser_create
diverite_nitekq_parser_create
+citizen_aqualand_parser_create
dc_device_open
dc_device_close
@@ -168,3 +169,4 @@ shearwater_predator_extract_dives
shearwater_petrel_device_open
diverite_nitekq_device_open
diverite_nitekq_extract_dives
+citizen_aqualand_device_open
diff --git a/src/parser.c b/src/parser.c
index a17a586..718682a 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -32,6 +32,7 @@
#include
#include
#include
+#include
#include "parser-private.h"
#include "device-private.h"
@@ -134,6 +135,9 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device)
case DC_FAMILY_DIVERITE_NITEKQ:
rc = diverite_nitekq_parser_create (&parser, context);
break;
+ case DC_FAMILY_CITIZEN_AQUALAND:
+ rc = citizen_aqualand_parser_create (&parser, context);
+ break;
default:
return DC_STATUS_INVALIDARGS;
}