Merge branch 'oceanic-firmware-version'

This commit is contained in:
Jef Driesen 2020-10-27 11:14:29 +01:00
commit 7f553c1276
5 changed files with 182 additions and 247 deletions

View File

@ -92,141 +92,6 @@ static const oceanic_common_device_vtable_t oceanic_atom2_device_vtable = {
oceanic_common_device_profile,
};
static const oceanic_common_version_t aeris_f10_version[] = {
{"FREEWAER \0\0 512K"},
{"OCEANF10 \0\0 512K"},
{"MUNDIAL R\0\0 512K"},
};
static const oceanic_common_version_t aeris_f11_version[] = {
{"AERISF11 \0\0 1024"},
{"OCEANF11 \0\0 1024"},
};
static const oceanic_common_version_t aeris_manta_version[] = {
{"MANTA R\0\0 512K"},
};
static const oceanic_common_version_t oceanic_atom1_version[] = {
{"ATOM rev\0\0 256K"},
};
static const oceanic_common_version_t oceanic_atom2_version[] = {
{"2M ATOM r\0\0 512K"},
};
static const oceanic_common_version_t oceanic_atom2a_version[] = {
{"INSIGHT2 \0\0 512K"},
{"OCEVEO30 \0\0 512K"},
{"ATMOSAI R\0\0 512K"},
{"PROPLUS2 \0\0 512K"},
{"OCEGEO20 \0\0 512K"},
{"OCE GEO R\0\0 512K"},
{"AQUAI200 \0\0 512K"},
{"AQUA200C \0\0 512K"},
};
static const oceanic_common_version_t oceanic_atom2b_version[] = {
{"ELEMENT2 \0\0 512K"},
{"OCEVEO20 \0\0 512K"},
{"TUSAZEN \0\0 512K"},
{"AQUAI300 \0\0 512K"},
{"HOLLDG03 \0\0 512K"},
{"AQUAI100 \0\0 512K"},
{"AQUA300C \0\0 512K"},
{"OCEGEO40 \0\0 512K"},
{"VEOSMART \0\0 512K"},
};
static const oceanic_common_version_t oceanic_atom2c_version[] = {
{"2M EPIC r\0\0 512K"},
{"EPIC1 R\0\0 512K"},
{"AERIA300 \0\0 512K"},
};
static const oceanic_common_version_t oceanic_default_version[] = {
{"OCE VT3 R\0\0 512K"},
{"ELITET3 R\0\0 512K"},
{"ELITET31 \0\0 512K"},
{"DATAMASK \0\0 512K"},
{"COMPMASK \0\0 512K"},
};
static const oceanic_common_version_t sherwood_wisdom_version[] = {
{"WISDOM R\0\0 512K"},
};
static const oceanic_common_version_t oceanic_proplus3_version[] = {
{"PROPLUS3 \0\0 512K"},
{"PROPLUS4 \0\0 512K"},
};
static const oceanic_common_version_t tusa_zenair_version[] = {
{"TUZENAIR \0\0 512K"},
{"AMPHOSSW \0\0 512K"},
{"AMPHOAIR \0\0 512K"},
{"VOYAGE2G \0\0 512K"},
{"TUSTALIS \0\0 512K"},
};
static const oceanic_common_version_t oceanic_oc1_version[] = {
{"OCWATCH R\0\0 1024"},
{"OC1WATCH \0\0 1024"},
{"OCSWATCH \0\0 1024"},
{"AQUAI550 \0\0 1024"},
{"AQUA550C \0\0 1024"},
{"WISDOM04 \0\0 1024"},
{"AQUA470C \0\0 1024"},
};
static const oceanic_common_version_t oceanic_oci_version[] = {
{"OCEANOCI \0\0 1024"},
};
static const oceanic_common_version_t oceanic_atom3_version[] = {
{"OCEATOM3 \0\0 1024"},
{"ATOM31 \0\0 1024"},
};
static const oceanic_common_version_t oceanic_vt4_version[] = {
{"OCEANVT4 \0\0 1024"},
{"OCEAVT41 \0\0 1024"},
{"AERISAIR \0\0 1024"},
{"SWVISION \0\0 1024"},
{"XPSUBAIR \0\0 1024"},
};
static const oceanic_common_version_t hollis_tx1_version[] = {
{"HOLLDG04 \0\0 2048"},
};
static const oceanic_common_version_t oceanic_veo1_version[] = {
{"OCEVEO10 \0\0 8K"},
{"AERIS XR1 NX R\0\0"},
};
static const oceanic_common_version_t oceanic_reactpro_version[] = {
{"REACPRO2 \0\0 512K"},
};
static const oceanic_common_version_t oceanic_proplusx_version[] = {
{"OCEANOCX \0\0 \0\0\0\0"},
};
static const oceanic_common_version_t aqualung_i770r_version[] = {
{"AQUA770R \0\0 \0\0\0\0"},
};
static const oceanic_common_version_t aeris_a300cs_version[] = {
{"AER300CS \0\0 2048"},
{"OCEANVTX \0\0 2048"},
{"AQUAI750 \0\0 2048"},
};
static const oceanic_common_version_t aqualung_i450t_version[] = {
{"AQUAI450 \0\0 2048"},
};
static const oceanic_common_layout_t aeris_f10_layout = {
0x10000, /* memsize */
0, /* highmem */
@ -542,6 +407,98 @@ static const oceanic_common_layout_t aqualung_i450t_layout = {
0, /* pt_mode_serial */
};
static const oceanic_common_version_t versions[] = {
{"OCEVEO10 \0\0 8K", 0, &oceanic_veo1_layout},
{"AERIS XR1 NX R\0\0", 0, &oceanic_veo1_layout},
{"ATOM rev\0\0 256K", 0, &oceanic_atom1_layout},
{"MANTA R\0\0 512K", 0x3242, &oceanic_atom2a_layout},
{"MANTA R\0\0 512K", 0, &oceanic_atom2c_layout},
{"2M ATOM r\0\0 512K", 0x3349, &oceanic_atom2a_layout},
{"2M ATOM r\0\0 512K", 0, &oceanic_atom2c_layout},
{"INSIGHT2 \0\0 512K", 0, &oceanic_atom2a_layout},
{"OCEVEO30 \0\0 512K", 0, &oceanic_atom2a_layout},
{"ATMOSAI R\0\0 512K", 0, &oceanic_atom2a_layout},
{"PROPLUS2 \0\0 512K", 0, &oceanic_atom2a_layout},
{"OCEGEO20 \0\0 512K", 0, &oceanic_atom2a_layout},
{"OCE GEO R\0\0 512K", 0, &oceanic_atom2a_layout},
{"AQUAI200 \0\0 512K", 0, &oceanic_atom2a_layout},
{"AQUA200C \0\0 512K", 0, &oceanic_atom2a_layout},
{"ELEMENT2 \0\0 512K", 0, &oceanic_atom2b_layout},
{"OCEVEO20 \0\0 512K", 0, &oceanic_atom2b_layout},
{"TUSAZEN \0\0 512K", 0, &oceanic_atom2b_layout},
{"AQUAI300 \0\0 512K", 0, &oceanic_atom2b_layout},
{"HOLLDG03 \0\0 512K", 0, &oceanic_atom2b_layout},
{"AQUAI100 \0\0 512K", 0, &oceanic_atom2b_layout},
{"AQUA300C \0\0 512K", 0, &oceanic_atom2b_layout},
{"OCEGEO40 \0\0 512K", 0, &oceanic_atom2b_layout},
{"VEOSMART \0\0 512K", 0, &oceanic_atom2b_layout},
{"2M EPIC r\0\0 512K", 0, &oceanic_atom2c_layout},
{"EPIC1 R\0\0 512K", 0, &oceanic_atom2c_layout},
{"AERIA300 \0\0 512K", 0, &oceanic_atom2c_layout},
{"OCE VT3 R\0\0 512K", 0, &oceanic_default_layout},
{"ELITET3 R\0\0 512K", 0, &oceanic_default_layout},
{"ELITET31 \0\0 512K", 0, &oceanic_default_layout},
{"DATAMASK \0\0 512K", 0, &oceanic_default_layout},
{"COMPMASK \0\0 512K", 0, &oceanic_default_layout},
{"WISDOM R\0\0 512K", 0, &sherwood_wisdom_layout},
{"PROPLUS3 \0\0 512K", 0, &oceanic_proplus3_layout},
{"PROPLUS4 \0\0 512K", 0, &oceanic_proplus3_layout},
{"TUZENAIR \0\0 512K", 0, &tusa_zenair_layout},
{"AMPHOSSW \0\0 512K", 0, &tusa_zenair_layout},
{"AMPHOAIR \0\0 512K", 0, &tusa_zenair_layout},
{"VOYAGE2G \0\0 512K", 0, &tusa_zenair_layout},
{"TUSTALIS \0\0 512K", 0, &tusa_zenair_layout},
{"REACPRO2 \0\0 512K", 0, &oceanic_reactpro_layout},
{"FREEWAER \0\0 512K", 0, &aeris_f10_layout},
{"OCEANF10 \0\0 512K", 0, &aeris_f10_layout},
{"MUNDIAL R\0\0 512K", 0, &aeris_f10_layout},
{"AERISF11 \0\0 1024", 0, &aeris_f11_layout},
{"OCEANF11 \0\0 1024", 0, &aeris_f11_layout},
{"OCWATCH R\0\0 1024", 0, &oceanic_oc1_layout},
{"OC1WATCH \0\0 1024", 0, &oceanic_oc1_layout},
{"OCSWATCH \0\0 1024", 0, &oceanic_oc1_layout},
{"AQUAI550 \0\0 1024", 0, &oceanic_oc1_layout},
{"AQUA550C \0\0 1024", 0, &oceanic_oc1_layout},
{"WISDOM04 \0\0 1024", 0, &oceanic_oc1_layout},
{"AQUA470C \0\0 1024", 0, &oceanic_oc1_layout},
{"OCEANOCI \0\0 1024", 0, &oceanic_oci_layout},
{"OCEATOM3 \0\0 1024", 0, &oceanic_atom3_layout},
{"ATOM31 \0\0 1024", 0, &oceanic_atom3_layout},
{"OCEANVT4 \0\0 1024", 0, &oceanic_vt4_layout},
{"OCEAVT41 \0\0 1024", 0, &oceanic_vt4_layout},
{"AERISAIR \0\0 1024", 0, &oceanic_vt4_layout},
{"SWVISION \0\0 1024", 0, &oceanic_vt4_layout},
{"XPSUBAIR \0\0 1024", 0, &oceanic_vt4_layout},
{"HOLLDG04 \0\0 2048", 0, &hollis_tx1_layout},
{"AER300CS \0\0 2048", 0, &aeris_a300cs_layout},
{"OCEANVTX \0\0 2048", 0, &aeris_a300cs_layout},
{"AQUAI750 \0\0 2048", 0, &aeris_a300cs_layout},
{"AQUAI450 \0\0 2048", 0, &aqualung_i450t_layout},
{"OCEANOCX \0\0 \0\0\0\0", 0, &oceanic_proplusx_layout},
{"AQUA770R \0\0 \0\0\0\0", 0, &aqualung_i770r_layout},
};
/*
* The BLE GATT packet size is up to 20 bytes and the format is:
*
@ -952,68 +909,10 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, dc_iostream
}
}
// Override the base class values.
if (OCEANIC_COMMON_MATCH (device->base.version, aeris_f10_version)) {
device->base.layout = &aeris_f10_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, aeris_f11_version)) {
device->base.layout = &aeris_f11_layout;
device->bigpage = 8;
} else if (OCEANIC_COMMON_MATCH (device->base.version, aeris_manta_version)) {
if (array_uint16_be (device->base.version + 0x08) >= 0x3242) {
device->base.layout = &oceanic_atom2a_layout;
} else {
device->base.layout = &oceanic_atom2c_layout;
}
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_atom1_version)) {
device->base.layout = &oceanic_atom1_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_atom2_version)) {
if (array_uint16_be (device->base.version + 0x09) >= 0x3349) {
device->base.layout = &oceanic_atom2a_layout;
} else {
device->base.layout = &oceanic_atom2c_layout;
}
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_atom2a_version)) {
device->base.layout = &oceanic_atom2a_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_atom2b_version)) {
device->base.layout = &oceanic_atom2b_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_atom2c_version)) {
device->base.layout = &oceanic_atom2c_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, sherwood_wisdom_version)) {
device->base.layout = &sherwood_wisdom_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_proplus3_version)) {
device->base.layout = &oceanic_proplus3_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, tusa_zenair_version)) {
device->base.layout = &tusa_zenair_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_oc1_version)) {
device->base.layout = &oceanic_oc1_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_oci_version)) {
device->base.layout = &oceanic_oci_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_atom3_version)) {
device->base.layout = &oceanic_atom3_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_vt4_version)) {
device->base.layout = &oceanic_vt4_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, hollis_tx1_version)) {
device->base.layout = &hollis_tx1_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_veo1_version)) {
device->base.layout = &oceanic_veo1_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_reactpro_version)) {
device->base.layout = &oceanic_reactpro_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_proplusx_version)) {
device->base.layout = &oceanic_proplusx_layout;
device->bigpage = 16;
} else if (OCEANIC_COMMON_MATCH (device->base.version, aqualung_i770r_version)) {
device->base.layout = &aqualung_i770r_layout;
device->bigpage = 16;
} else if (OCEANIC_COMMON_MATCH (device->base.version, aeris_a300cs_version)) {
device->base.layout = &aeris_a300cs_layout;
device->bigpage = 16;
} else if (OCEANIC_COMMON_MATCH (device->base.version, aqualung_i450t_version)) {
device->base.layout = &aqualung_i450t_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_default_version)) {
device->base.layout = &oceanic_default_layout;
} else {
// Detect the memory layout.
device->base.layout = OCEANIC_COMMON_MATCH(device->base.version, versions, &device->base.firmware);
if (device->base.layout == NULL) {
WARNING (context, "Unsupported device detected!");
device->base.layout = &oceanic_default_layout;
if (memcmp(device->base.version + 12, "256K", 4) == 0) {
device->base.layout = &oceanic_atom1_layout;
} else if (memcmp(device->base.version + 12, "512K", 4) == 0) {
@ -1027,6 +926,15 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, dc_iostream
}
}
// Set the big page support.
if (device->base.layout == &aeris_f11_layout) {
device->bigpage = 8;
} else if (device->base.layout == &oceanic_proplusx_layout ||
device->base.layout == &aqualung_i770r_layout ||
device->base.layout == &aeris_a300cs_layout) {
device->bigpage = 16;
}
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;

View File

@ -99,26 +99,52 @@ get_profile_last (const unsigned char data[], const oceanic_common_layout_t *lay
static int
oceanic_common_match_pattern (const unsigned char *string, const unsigned char *pattern)
oceanic_common_match_pattern (const unsigned char *string, const unsigned char *pattern, unsigned int *firmware)
{
unsigned int value = 0;
unsigned int count = 0;
for (unsigned int i = 0; i < PAGESIZE; ++i, ++pattern, ++string) {
if (*pattern != '\0' && *pattern != *string)
return 0;
if (*pattern != '\0') {
// Compare the pattern.
if (*pattern != *string)
return 0;
} else {
// Extract the firmware version.
// This is based on the assumption that (only) the first block of
// zeros in the pattern contains the firmware version.
if (i == 0 || *(pattern - 1) != '\0')
count++;
if (count == 1) {
value <<= 8;
value |= *string;
}
}
}
if (firmware) {
*firmware = value;
}
return 1;
}
int
oceanic_common_match (const unsigned char *version, const oceanic_common_version_t patterns[], unsigned int n)
const oceanic_common_layout_t *
oceanic_common_match (const unsigned char *version, const oceanic_common_version_t patterns[], size_t n, unsigned int *firmware)
{
for (unsigned int i = 0; i < n; ++i) {
if (oceanic_common_match_pattern (version, patterns[i]))
return 1;
for (size_t i = 0; i < n; ++i) {
unsigned int fw = 0;
if (oceanic_common_match_pattern (version, patterns[i].pattern, &fw) &&
fw >= patterns[i].firmware)
{
if (firmware) {
*firmware = fw;
}
return patterns[i].layout;
}
}
return 0;
return NULL;
}
@ -128,6 +154,7 @@ oceanic_common_device_init (oceanic_common_device_t *device)
assert (device != NULL);
// Set the default values.
device->firmware = 0;
memset (device->version, 0, sizeof (device->version));
memset (device->fingerprint, 0, sizeof (device->fingerprint));
device->layout = NULL;
@ -585,7 +612,7 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
// Emit a device info event.
dc_event_devinfo_t devinfo;
devinfo.model = array_uint16_be (id + 8);
devinfo.firmware = 0;
devinfo.firmware = device->firmware;
if (layout->pt_mode_serial == 0)
devinfo.serial = bcd2dec (id[10]) * 10000 + bcd2dec (id[11]) * 100 + bcd2dec (id[12]);
else if (layout->pt_mode_serial == 1)

View File

@ -31,9 +31,9 @@ extern "C" {
#define PAGESIZE 0x10
#define FPMAXSIZE 0x20
#define OCEANIC_COMMON_MATCH(version,patterns) \
#define OCEANIC_COMMON_MATCH(version,patterns,firmware) \
oceanic_common_match ((version), (patterns), \
sizeof (patterns) / sizeof *(patterns))
sizeof (patterns) / sizeof *(patterns), (firmware))
typedef struct oceanic_common_layout_t {
// Memory size.
@ -61,6 +61,7 @@ typedef struct oceanic_common_layout_t {
typedef struct oceanic_common_device_t {
dc_device_t base;
unsigned int firmware;
unsigned char version[PAGESIZE];
unsigned char fingerprint[FPMAXSIZE];
const oceanic_common_layout_t *layout;
@ -73,10 +74,14 @@ typedef struct oceanic_common_device_vtable_t {
dc_status_t (*profile) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata);
} oceanic_common_device_vtable_t;
typedef unsigned char oceanic_common_version_t[PAGESIZE + 1];
typedef struct oceanic_common_version_t {
unsigned char pattern[PAGESIZE + 1];
unsigned int firmware;
const oceanic_common_layout_t *layout;
} oceanic_common_version_t;
int
oceanic_common_match (const unsigned char *version, const oceanic_common_version_t patterns[], unsigned int n);
const oceanic_common_layout_t *
oceanic_common_match (const unsigned char *version, const oceanic_common_version_t patterns[], size_t n, unsigned int *firmware);
void
oceanic_common_device_init (oceanic_common_device_t *device);

View File

@ -62,17 +62,6 @@ static const oceanic_common_device_vtable_t oceanic_veo250_device_vtable = {
oceanic_common_device_profile,
};
static const oceanic_common_version_t oceanic_veo250_version[] = {
{"GENREACT \0\0 256K"},
{"VEO 200 R\0\0 256K"},
{"VEO 250 R\0\0 256K"},
{"SEEMANN R\0\0 256K"},
{"VEO 180 R\0\0 256K"},
{"AERISXR2 \0\0 256K"},
{"INSIGHT R\0\0 256K"},
{"HO DGO2 R\0\0 256K"},
};
static const oceanic_common_layout_t oceanic_veo250_layout = {
0x8000, /* memsize */
0, /* highmem */
@ -88,6 +77,16 @@ static const oceanic_common_layout_t oceanic_veo250_layout = {
1, /* pt_mode_serial */
};
static const oceanic_common_version_t versions[] = {
{"GENREACT \0\0 256K", 0, &oceanic_veo250_layout},
{"VEO 200 R\0\0 256K", 0, &oceanic_veo250_layout},
{"VEO 250 R\0\0 256K", 0, &oceanic_veo250_layout},
{"SEEMANN R\0\0 256K", 0, &oceanic_veo250_layout},
{"VEO 180 R\0\0 256K", 0, &oceanic_veo250_layout},
{"AERISXR2 \0\0 256K", 0, &oceanic_veo250_layout},
{"INSIGHT R\0\0 256K", 0, &oceanic_veo250_layout},
{"HO DGO2 R\0\0 256K", 0, &oceanic_veo250_layout},
};
static dc_status_t
oceanic_veo250_send (oceanic_veo250_device_t *device, const unsigned char command[], unsigned int csize)
@ -316,10 +315,9 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, dc_iostrea
goto error_free;
}
// Override the base class values.
if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_veo250_version)) {
device->base.layout = &oceanic_veo250_layout;
} else {
// Detect the memory layout.
device->base.layout = OCEANIC_COMMON_MATCH(device->base.version, versions, &device->base.firmware);
if (device->base.layout == NULL) {
WARNING (context, "Unsupported device detected!");
device->base.layout = &oceanic_veo250_layout;
}

View File

@ -74,19 +74,6 @@ static const oceanic_common_device_vtable_t oceanic_vtpro_device_vtable = {
oceanic_common_device_profile,
};
static const oceanic_common_version_t oceanic_vtpro_version[] = {
{"VERSAPRO \0\0 256K"},
{"ATMOSTWO \0\0 256K"},
{"PROPLUS2 \0\0 256K"},
{"ATMOSAIR \0\0 256K"},
{"VTPRO r\0\0 256K"},
{"ELITE r\0\0 256K"},
};
static const oceanic_common_version_t oceanic_wisdom_version[] = {
{"WISDOM r\0\0 256K"},
};
static const oceanic_common_layout_t oceanic_vtpro_layout = {
0x8000, /* memsize */
0, /* highmem */
@ -132,6 +119,17 @@ static const oceanic_common_layout_t aeris_500ai_layout = {
2, /* pt_mode_serial */
};
static const oceanic_common_version_t versions[] = {
{"VERSAPRO \0\0 256K", 0, &oceanic_vtpro_layout},
{"ATMOSTWO \0\0 256K", 0, &oceanic_vtpro_layout},
{"PROPLUS2 \0\0 256K", 0, &oceanic_vtpro_layout},
{"ATMOSAIR \0\0 256K", 0, &oceanic_vtpro_layout},
{"VTPRO r\0\0 256K", 0, &oceanic_vtpro_layout},
{"ELITE r\0\0 256K", 0, &oceanic_vtpro_layout},
{"WISDOM r\0\0 256K", 0, &oceanic_wisdom_layout},
};
static dc_status_t
oceanic_vtpro_send (oceanic_vtpro_device_t *device, const unsigned char command[], unsigned int csize)
{
@ -491,16 +489,15 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, dc_iostream
goto error_free;
}
// Override the base class values.
// Detect the memory layout.
if (model == AERIS500AI) {
device->base.layout = &aeris_500ai_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_wisdom_version)) {
device->base.layout = &oceanic_wisdom_layout;
} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_vtpro_version)) {
device->base.layout = &oceanic_vtpro_layout;
} else {
WARNING (context, "Unsupported device detected!");
device->base.layout = &oceanic_vtpro_layout;
device->base.layout = OCEANIC_COMMON_MATCH(device->base.version, versions, &device->base.firmware);
if (device->base.layout == NULL) {
WARNING (context, "Unsupported device detected!");
device->base.layout = &oceanic_vtpro_layout;
}
}
*out = (dc_device_t*) device;