From 8f790b52e4a219dfa2baf8b6502a38d3352745be Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 27 Aug 2018 11:00:39 -0700 Subject: [PATCH] Add Garmin Descent Mk1 skeleton This does absolutely nothing, but it adds the basic skeleton for a new dive computer support. Not only don't I have any real code for any of this yet, but I actually think it might be useful to have a "this is how to add a new dive computer" example commit. Signed-off-by: Linus Torvalds --- examples/common.c | 1 + include/libdivecomputer/common.h | 2 + msvc/libdivecomputer.vcproj | 12 ++++ src/Makefile.am | 1 + src/descriptor.c | 16 +++++ src/device.c | 4 ++ src/garmin.c | 107 ++++++++++++++++++++++++++++ src/garmin.h | 43 +++++++++++ src/garmin_parser.c | 118 +++++++++++++++++++++++++++++++ src/parser.c | 4 ++ 10 files changed, 308 insertions(+) create mode 100644 src/garmin.c create mode 100644 src/garmin.h create mode 100644 src/garmin_parser.c diff --git a/examples/common.c b/examples/common.c index 830eac2..ad7086f 100644 --- a/examples/common.c +++ b/examples/common.c @@ -89,6 +89,7 @@ static const backend_table_t g_backends[] = { {"idive", DC_FAMILY_DIVESYSTEM_IDIVE, 0x03}, {"cochran", DC_FAMILY_COCHRAN_COMMANDER, 0}, {"divecomputereu", DC_FAMILY_TECDIVING_DIVECOMPUTEREU, 0}, + {"descentmk1", DC_FAMILY_GARMIN, 0}, }; static const transport_table_t g_transports[] = { diff --git a/include/libdivecomputer/common.h b/include/libdivecomputer/common.h index 7d89706..8d77b9c 100644 --- a/include/libdivecomputer/common.h +++ b/include/libdivecomputer/common.h @@ -107,6 +107,8 @@ typedef enum dc_family_t { DC_FAMILY_COCHRAN_COMMANDER = (14 << 16), /* Tecdiving */ DC_FAMILY_TECDIVING_DIVECOMPUTEREU = (15 << 16), + /* Garmin */ + DC_FAMILY_GARMIN = (16 << 16), } dc_family_t; #ifdef __cplusplus diff --git a/msvc/libdivecomputer.vcproj b/msvc/libdivecomputer.vcproj index 1a88ff8..5ab415c 100644 --- a/msvc/libdivecomputer.vcproj +++ b/msvc/libdivecomputer.vcproj @@ -490,6 +490,14 @@ RelativePath="..\src\tecdiving_divecomputereu_parser.c" > + + + + @@ -828,6 +836,10 @@ RelativePath="..\src\tecdiving_divecomputereu.h" > + + diff --git a/src/Makefile.am b/src/Makefile.am index 12f6b61..b9ddbef 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -71,6 +71,7 @@ libdivecomputer_la_SOURCES = \ buffer.c \ cochran_commander.h cochran_commander.c cochran_commander_parser.c \ tecdiving_divecomputereu.h tecdiving_divecomputereu.c tecdiving_divecomputereu_parser.c \ + garmin.h garmin.c garmin_parser.c \ socket.h socket.c \ irda.c \ usbhid.c \ diff --git a/src/descriptor.c b/src/descriptor.c index 6871e1b..d664beb 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -34,6 +34,7 @@ static int dc_filter_suunto (dc_transport_t transport, const void *userdata); static int dc_filter_shearwater (dc_transport_t transport, const void *userdata); 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 dc_status_t dc_descriptor_iterator_next (dc_iterator_t *iterator, void *item); @@ -326,6 +327,8 @@ static const dc_descriptor_t g_descriptors[] = { {"Cochran", "EMC-20H", DC_FAMILY_COCHRAN_COMMANDER, 5, DC_TRANSPORT_SERIAL, NULL}, /* Tecdiving DiveComputer.eu */ {"Tecdiving", "DiveComputer.eu", DC_FAMILY_TECDIVING_DIVECOMPUTEREU, 0, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, dc_filter_tecdiving}, + /* Garmin */ + {"Garmin", "Descent Mk1", DC_FAMILY_GARMIN, 0, DC_TRANSPORT_USBSTORAGE, dc_filter_garmin}, }; static int @@ -465,6 +468,19 @@ static int dc_filter_tecdiving (dc_transport_t transport, const void *userdata) return 1; } +static int dc_filter_garmin (dc_transport_t transport, const void *userdata) +{ + static const dc_usb_desc_t usbhid[] = { + {0x091e, 0x2b2b}, // Garmin Descent Mk1 + }; + + if (transport == DC_TRANSPORT_USBSTORAGE) { + return dc_filter_internal_usb ((const dc_usb_desc_t *) userdata, usbhid, C_ARRAY_SIZE(usbhid)); + } + + return 1; +} + dc_status_t dc_descriptor_iterator (dc_iterator_t **out) { diff --git a/src/device.c b/src/device.c index fc59464..c00aa3b 100644 --- a/src/device.c +++ b/src/device.c @@ -56,6 +56,7 @@ #include "divesystem_idive.h" #include "cochran_commander.h" #include "tecdiving_divecomputereu.h" +#include "garmin.h" #include "device-private.h" #include "context-private.h" @@ -207,6 +208,9 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr case DC_FAMILY_TECDIVING_DIVECOMPUTEREU: rc = tecdiving_divecomputereu_device_open (&device, context, iostream); break; + case DC_FAMILY_GARMIN: + rc = garmin_device_open (&device, context, iostream); + break; default: return DC_STATUS_INVALIDARGS; } diff --git a/src/garmin.c b/src/garmin.c new file mode 100644 index 0000000..df375e3 --- /dev/null +++ b/src/garmin.c @@ -0,0 +1,107 @@ +/* + * Garmin Descent Mk1 USB storage downloading + * + * Copyright (C) 2018 Linus Torvalds + * + * 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 "garmin.h" +#include "context-private.h" +#include "device-private.h" +#include "array.h" + +typedef struct garmin_device_t { + dc_device_t base; + dc_iostream_t *iostream; +} garmin_device_t; + +static dc_status_t garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata); +static dc_status_t garmin_device_close (dc_device_t *abstract); + +static const dc_device_vtable_t garmin_device_vtable = { + sizeof(garmin_device_t), + DC_FAMILY_GARMIN, + NULL, /* set_fingerprint */ + NULL, /* read */ + NULL, /* write */ + NULL, /* dump */ + garmin_device_foreach, /* foreach */ + NULL, /* timesync */ + garmin_device_close, /* close */ +}; + +dc_status_t +garmin_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream) +{ + dc_status_t status = DC_STATUS_SUCCESS; + garmin_device_t *device = NULL; + + if (out == NULL) + return DC_STATUS_INVALIDARGS; + + // Allocate memory. + device = (garmin_device_t *) dc_device_allocate (context, &garmin_device_vtable); + if (device == NULL) { + ERROR (context, "Failed to allocate memory."); + return DC_STATUS_NOMEMORY; + } + + // Set the default values. + device->iostream = iostream; + + *out = (dc_device_t *) device; + + return DC_STATUS_SUCCESS; +} + +static dc_status_t +garmin_device_close (dc_device_t *abstract) +{ + dc_status_t status = DC_STATUS_SUCCESS; + garmin_device_t *device = (garmin_device_t *) abstract; + + return DC_STATUS_SUCCESS; +} + +static dc_status_t +garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata) +{ + dc_status_t status = DC_STATUS_SUCCESS; + garmin_device_t *device = (garmin_device_t *) abstract; + + // Enable progress notifications. + dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; + device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); + + // Emit a device info event. + dc_event_devinfo_t devinfo; + devinfo.model = 0; + devinfo.firmware = 0; + devinfo.serial = 0; + device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); + + // Emit a vendor event. + dc_event_vendor_t vendor; + vendor.data = "Garmin"; + vendor.size = 6; + device_event_emit (abstract, DC_EVENT_VENDOR, &vendor); + + return status; +} diff --git a/src/garmin.h b/src/garmin.h new file mode 100644 index 0000000..fd1caa4 --- /dev/null +++ b/src/garmin.h @@ -0,0 +1,43 @@ +/* + * Garmin Descent Mk1 + * + * Copyright (C) 2018 Linus Torvalds + * + * 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 GARMIN_H +#define GARMIN_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +dc_status_t +garmin_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); + +dc_status_t +garmin_parser_create (dc_parser_t **parser, dc_context_t *context); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* GARMIN_H */ diff --git a/src/garmin_parser.c b/src/garmin_parser.c new file mode 100644 index 0000000..077e26d --- /dev/null +++ b/src/garmin_parser.c @@ -0,0 +1,118 @@ +/* + * Garmin Descent Mk1 parsing + * + * Copyright (C) 2018 Linus Torvalds + * + * 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 "garmin.h" +#include "context-private.h" +#include "parser-private.h" +#include "array.h" + +typedef struct garmin_parser_t { + dc_parser_t base; +} garmin_parser_t; + +static dc_status_t garmin_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size); +static dc_status_t garmin_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); +static dc_status_t garmin_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); +static dc_status_t garmin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); + +static const dc_parser_vtable_t garmin_parser_vtable = { + sizeof(garmin_parser_t), + DC_FAMILY_GARMIN, + garmin_parser_set_data, /* set_data */ + garmin_parser_get_datetime, /* datetime */ + garmin_parser_get_field, /* fields */ + garmin_parser_samples_foreach, /* samples_foreach */ + NULL /* destroy */ +}; + + +dc_status_t +garmin_parser_create (dc_parser_t **out, dc_context_t *context) +{ + garmin_parser_t *parser = NULL; + + if (out == NULL) + return DC_STATUS_INVALIDARGS; + + // Allocate memory. + parser = (garmin_parser_t *) dc_parser_allocate (context, &garmin_parser_vtable); + if (parser == NULL) { + ERROR (context, "Failed to allocate memory."); + return DC_STATUS_NOMEMORY; + } + + *out = (dc_parser_t *) parser; + + return DC_STATUS_SUCCESS; +} + + +static dc_status_t +garmin_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) +{ + return DC_STATUS_SUCCESS; +} + + +static dc_status_t +garmin_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) +{ + const unsigned char *data = abstract->data; + + return DC_STATUS_SUCCESS; +} + + +static dc_status_t +garmin_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value) +{ + const unsigned char *data = abstract->data; + + if (!value) + return DC_STATUS_INVALIDARGS; + + switch (type) { + case DC_FIELD_DIVETIME: + *((unsigned int *) value) = 0; + break; + case DC_FIELD_AVGDEPTH: + *((double *) value) = 0; + break; + case DC_FIELD_MAXDEPTH: + *((double *) value) = 0; + break; + default: + return DC_STATUS_UNSUPPORTED; + } + + return DC_STATUS_SUCCESS; +} + +static dc_status_t +garmin_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; + + return DC_STATUS_SUCCESS; +} diff --git a/src/parser.c b/src/parser.c index e9e97a2..1795f62 100644 --- a/src/parser.c +++ b/src/parser.c @@ -56,6 +56,7 @@ #include "divesystem_idive.h" #include "cochran_commander.h" #include "tecdiving_divecomputereu.h" +#include "garmin.h" #include "context-private.h" #include "parser-private.h" @@ -168,6 +169,9 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t fa case DC_FAMILY_TECDIVING_DIVECOMPUTEREU: rc = tecdiving_divecomputereu_parser_create (&parser, context); break; + case DC_FAMILY_GARMIN: + rc = garmin_parser_create (&parser, context); + break; default: return DC_STATUS_INVALIDARGS; }