diff --git a/src/descriptor.c b/src/descriptor.c index 0d9a561..da0a990 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -28,6 +28,17 @@ #include "platform.h" #define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array)) +#define C_ARRAY_ITEMSIZE(array) (sizeof *(array)) + +#define DC_FILTER_INTERNAL(key, values, isnullterminated, match) \ + dc_filter_internal( \ + key, \ + values, \ + C_ARRAY_SIZE(values) - isnullterminated, \ + C_ARRAY_ITEMSIZE(values), \ + match) + +typedef int (*dc_match_t)(const void *, const void *); static int dc_filter_uwatec (dc_transport_t transport, const void *userdata); static int dc_filter_suunto (dc_transport_t transport, const void *userdata); @@ -36,6 +47,7 @@ static int dc_filter_hw (dc_transport_t transport, const void *userdata); static int dc_filter_tecdiving (dc_transport_t transport, const void *userdata); static int dc_filter_garmin (dc_transport_t transport, const void *userdata); static int dc_filter_mares (dc_transport_t transport, const void *userdata); +static int dc_filter_divesystem (dc_transport_t transport, const void *userdata); static dc_status_t dc_descriptor_iterator_next (dc_iterator_t *iterator, void *item); @@ -228,6 +240,7 @@ static const dc_descriptor_t g_descriptors[] = { {"Aqualung", "i300C", DC_FAMILY_OCEANIC_ATOM2, 0x4648, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, NULL}, {"Aqualung", "i100", DC_FAMILY_OCEANIC_ATOM2, 0x464E, DC_TRANSPORT_SERIAL, NULL}, {"Aqualung", "i770R", DC_FAMILY_OCEANIC_ATOM2, 0x4651, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, NULL}, + {"Aqualung", "i550C", DC_FAMILY_OCEANIC_ATOM2, 0x4652, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, NULL}, {"Oceanic", "Geo 4.0", DC_FAMILY_OCEANIC_ATOM2, 0x4653, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, NULL}, /* Mares Nemo */ {"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL}, @@ -321,12 +334,12 @@ static const dc_descriptor_t g_descriptors[] = { {"DiveSystem", "iDive Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x09, DC_TRANSPORT_SERIAL, NULL}, {"DiveSystem", "iDive X3M", DC_FAMILY_DIVESYSTEM_IDIVE, 0x0A, DC_TRANSPORT_SERIAL, NULL}, {"DiveSystem", "iDive Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x0B, DC_TRANSPORT_SERIAL, NULL}, - {"Ratio", "iX3M Pro ", DC_FAMILY_DIVESYSTEM_IDIVE, 0x21, DC_TRANSPORT_SERIAL, NULL}, - {"Ratio", "iX3M Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x22, DC_TRANSPORT_SERIAL, NULL}, - {"Ratio", "iX3M Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x23, DC_TRANSPORT_SERIAL, NULL}, - {"Ratio", "iX3M Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x24, DC_TRANSPORT_SERIAL, NULL}, - {"Ratio", "iX3M Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x25, DC_TRANSPORT_SERIAL, NULL}, - {"Ratio", "iX3M Fancy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x26, DC_TRANSPORT_SERIAL, NULL}, + {"Ratio", "iX3M GPS Pro ", DC_FAMILY_DIVESYSTEM_IDIVE, 0x21, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_divesystem}, + {"Ratio", "iX3M GPS Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x22, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_divesystem}, + {"Ratio", "iX3M GPS Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x23, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_divesystem}, + {"Ratio", "iX3M GPS Tech+",DC_FAMILY_DIVESYSTEM_IDIVE, 0x24, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_divesystem}, + {"Ratio", "iX3M GPS Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x25, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_divesystem}, + {"Ratio", "iX3M GPS Fancy",DC_FAMILY_DIVESYSTEM_IDIVE, 0x26, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_divesystem}, {"Ratio", "iX3M Pro Fancy",DC_FAMILY_DIVESYSTEM_IDIVE, 0x31, DC_TRANSPORT_SERIAL, NULL}, {"Ratio", "iX3M Pro Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x32, DC_TRANSPORT_SERIAL, NULL}, {"Ratio", "iX3M Pro Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x33, DC_TRANSPORT_SERIAL, NULL}, @@ -363,60 +376,89 @@ static const dc_descriptor_t g_descriptors[] = { }; static int -dc_filter_internal_name (const char *name, const char *values[], size_t count) +dc_match_name (const void *key, const void *value) { - if (name == NULL) + const char *k = (const char *) key; + const char *v = *(const char * const *) value; + + return strcasecmp (k, v) == 0; +} + +static int +dc_match_prefix (const void *key, const void *value) +{ + const char *k = (const char *) key; + const char *v = *(const char * const *) value; + + return strncasecmp (k, v, strlen (v)) == 0; +} + +static int +dc_match_devname (const void *key, const void *value) +{ + const char *k = (const char *) key; + const char *v = *(const char * const *) value; + + return strncmp (k, v, strlen (v)) == 0; +} + +static int +dc_match_usb (const void *key, const void *value) +{ + const dc_usb_desc_t *k = (const dc_usb_desc_t *) key; + const dc_usb_desc_t *v = (const dc_usb_desc_t *) value; + + return k->vid == v->vid && k->pid == v->pid; +} + +static int +dc_match_number_with_prefix (const void *key, const void *value) +{ + const char *str = (const char *) key; + const char *prefix = *(const char * const *) value; + + size_t n = strlen (prefix); + + if (strncmp (str, prefix, n) != 0) { + return 0; + } + + while (str[n] != 0) { + const char c = str[n]; + if (c < '0' || c > '9') { + return 0; + } + n++; + } + + return 1; +} + +static int +dc_filter_internal (const void *key, const void *values, size_t count, size_t size, dc_match_t match) +{ + if (key == NULL) return 0; for (size_t i = 0; i < count; ++i) { - if (strcasecmp (name, values[i]) == 0) { + if (match (key, (const unsigned char *) values + i * size)) { return 1; } } - return 0; + return count == 0; } -static int -dc_filter_internal_usb (const dc_usb_desc_t *desc, const dc_usb_desc_t values[], size_t count) -{ - if (desc == NULL) - return 0; - - for (size_t i = 0; i < count; ++i) { - if (desc->vid == values[i].vid && - desc->pid == values[i].pid) { - return 1; - } - } - - return 0; -} - -static int -dc_filter_internal_rfcomm (const char *name) -{ - static const char *prefixes[] = { +static const char * const rfcomm[] = { #if defined (__linux__) - "/dev/rfcomm", + "/dev/rfcomm", #endif - NULL - }; - - if (name == NULL) - return 0; - - for (size_t i = 0; prefixes[i] != NULL; ++i) { - if (strncmp (name, prefixes[i], strlen (prefixes[i])) == 0) - return 1; - } - - return prefixes[0] == NULL; -} + NULL +}; static int dc_filter_uwatec (dc_transport_t transport, const void *userdata) { - static const char *irda[] = { + static const char * const irda[] = { "Aladin Smart Com", "Aladin Smart Pro", "Aladin Smart Tec", @@ -431,18 +473,18 @@ static int dc_filter_uwatec (dc_transport_t transport, const void *userdata) {0x2e6c, 0x4201}, // G2 HUD {0xc251, 0x2006}, // Aladin Square }; - static const char *bluetooth[] = { + static const char * const bluetooth[] = { "G2", "Aladin", "HUD", }; if (transport == DC_TRANSPORT_IRDA) { - return dc_filter_internal_name ((const char *) userdata, irda, C_ARRAY_SIZE(irda)); + return DC_FILTER_INTERNAL (userdata, irda, 0, dc_match_name); } else if (transport == DC_TRANSPORT_USBHID) { - return dc_filter_internal_usb ((const dc_usb_desc_t *) userdata, usbhid, C_ARRAY_SIZE(usbhid)); + return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usb); } else if (transport == DC_TRANSPORT_BLE) { - return dc_filter_internal_name ((const char *) userdata, bluetooth, C_ARRAY_SIZE(bluetooth)); + return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name); } return 1; @@ -455,18 +497,16 @@ static int dc_filter_suunto (dc_transport_t transport, const void *userdata) {0x1493, 0x0033}, // Eon Core {0x1493, 0x0035}, // D5 }; - static const char *bluetooth[] = { + static const char * const bluetooth[] = { "EON Steel", "EON Core", "Suunto D5", }; if (transport == DC_TRANSPORT_USBHID) { - return dc_filter_internal_usb ((const dc_usb_desc_t *) userdata, usbhid, C_ARRAY_SIZE(usbhid)); + return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usb); } else if (transport == DC_TRANSPORT_BLE) { - // This won't work for the D5 - the serial number is in the name, - // and that's not how dc_filter_internal_name() works - return dc_filter_internal_name ((const char *) userdata, bluetooth, C_ARRAY_SIZE(bluetooth)); + return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix); } return 1; @@ -474,11 +514,15 @@ static int dc_filter_suunto (dc_transport_t transport, const void *userdata) static int dc_filter_hw (dc_transport_t transport, const void *userdata) { + static const char * const bluetooth[] = { + "OSTC", + "FROG", + }; + if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) { - return strncasecmp ((const char *) userdata, "OSTC", 4) == 0 || - strncasecmp ((const char *) userdata, "FROG", 4) == 0; + return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix); } else if (transport == DC_TRANSPORT_SERIAL) { - return dc_filter_internal_rfcomm ((const char *) userdata); + return DC_FILTER_INTERNAL (userdata, rfcomm, 1, dc_match_devname); } return 1; @@ -486,7 +530,7 @@ static int dc_filter_hw (dc_transport_t transport, const void *userdata) static int dc_filter_shearwater (dc_transport_t transport, const void *userdata) { - static const char *bluetooth[] = { + static const char * const bluetooth[] = { "Predator", "Petrel", "Nerd", @@ -495,9 +539,9 @@ static int dc_filter_shearwater (dc_transport_t transport, const void *userdata) }; if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) { - return dc_filter_internal_name ((const char *) userdata, bluetooth, C_ARRAY_SIZE(bluetooth)); + return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name); } else if (transport == DC_TRANSPORT_SERIAL) { - return dc_filter_internal_rfcomm ((const char *) userdata); + return DC_FILTER_INTERNAL (userdata, rfcomm, 1, dc_match_devname); } return 1; @@ -505,14 +549,14 @@ static int dc_filter_shearwater (dc_transport_t transport, const void *userdata) static int dc_filter_tecdiving (dc_transport_t transport, const void *userdata) { - static const char *bluetooth[] = { + static const char * const bluetooth[] = { "DiveComputer", }; if (transport == DC_TRANSPORT_BLUETOOTH) { - return dc_filter_internal_name ((const char *) userdata, bluetooth, C_ARRAY_SIZE(bluetooth)); + return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name); } else if (transport == DC_TRANSPORT_SERIAL) { - return dc_filter_internal_rfcomm ((const char *) userdata); + return DC_FILTER_INTERNAL (userdata, rfcomm, 1, dc_match_devname); } return 1; @@ -525,7 +569,7 @@ static int dc_filter_garmin (dc_transport_t transport, const void *userdata) }; if (transport == DC_TRANSPORT_USBSTORAGE) { - return dc_filter_internal_usb ((const dc_usb_desc_t *) userdata, usbhid, C_ARRAY_SIZE(usbhid)); + return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usb); } return 1; @@ -533,12 +577,25 @@ static int dc_filter_garmin (dc_transport_t transport, const void *userdata) static int dc_filter_mares (dc_transport_t transport, const void *userdata) { - static const char *bluetooth[] = { + static const char * const bluetooth[] = { "Mares bluelink pro", }; if (transport == DC_TRANSPORT_BLE) { - return dc_filter_internal_name ((const char *) userdata, bluetooth, C_ARRAY_SIZE(bluetooth)); + return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name); + } + + return 1; +} + +static int dc_filter_divesystem (dc_transport_t transport, const void *userdata) +{ + static const char * const bluetooth[] = { + "DS", + }; + + if (transport == DC_TRANSPORT_BLUETOOTH) { + return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_number_with_prefix); } return 1; diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 0628c6a..ca5973d 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -161,6 +161,7 @@ static const oceanic_common_version_t oceanic_oc1_version[] = { {"OC1WATCH \0\0 1024"}, {"OCSWATCH \0\0 1024"}, {"AQUAI550 \0\0 1024"}, + {"AQUA550C \0\0 1024"}, }; static const oceanic_common_version_t oceanic_oci_version[] = { diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index de7f303..920c624 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -92,6 +92,7 @@ #define I300C 0x4648 #define I100 0x464E #define I770R 0x4651 +#define I550C 0x4652 #define GEO40 0x4653 #define NORMAL 0 @@ -186,6 +187,8 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned parser->headersize = 5 * PAGESIZE; } else if (model == PROPLUSX || model == GEO40) { parser->headersize = 3 * PAGESIZE; + } else if (model == I550C) { + parser->headersize = 5 * PAGESIZE / 2; } parser->serial = serial; @@ -261,6 +264,7 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim case A300AI: case OCI: case I550: + case I550C: case VISION: case XPAIR: datetime->year = ((p[5] & 0xE0) >> 5) + ((p[7] & 0xE0) >> 2) + 2000; @@ -910,7 +914,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ } else { unsigned int sign; if (parser->model == DG03 || parser->model == PROPLUS3 || - parser->model == I550) + parser->model == I550 || parser->model == I550C) sign = (~data[offset + 5] & 0x04) >> 2; else if (parser->model == VOYAGER2G || parser->model == AMPHOS || parser->model == AMPHOSAIR || parser->model == ZENAIR) @@ -942,7 +946,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ parser->model == ZENAIR ||parser->model == A300AI || parser->model == DG03 || parser->model == PROPLUS3 || parser->model == AMPHOSAIR || parser->model == I550 || - parser->model == VISION || parser->model == XPAIR) + parser->model == VISION || parser->model == XPAIR || + parser->model == I550C) pressure = (((data[offset + 0] & 0x03) << 8) + data[offset + 1]) * 5; else if (parser->model == TX1 || parser->model == A300CS || parser->model == VTX || parser->model == I750TC || @@ -1012,7 +1017,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ decotime = array_uint16_le(data + offset + 6); have_deco = 1; } else if (parser->model == ATOM31 || parser->model == VISION || - parser->model == XPAIR || parser->model == I550) { + parser->model == XPAIR || parser->model == I550 || + parser->model == I550C) { decostop = (data[offset + 5] & 0xF0) >> 4; decotime = array_uint16_le(data + offset + 4) & 0x03FF; have_deco = 1; @@ -1049,7 +1055,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ rbt = array_uint16_le(data + offset + 8) & 0x01FF; have_rbt = 1; } else if (parser->model == VISION || parser->model == XPAIR || - parser->model == I550) { + parser->model == I550 || parser->model == I550C) { rbt = array_uint16_le(data + offset + 6) & 0x03FF; have_rbt = 1; }