Merge branch 'garmin-descent' into Subsurface-NG
Merge the initial Garmin Descent Mk1 support. This actually works well enough to be useful, even though there are a few ugly details yet to be sorted out. The download itself is fairly complete, but all event handling is currently missing (warnings, gas changes, things like that). Also, because of how libdivecomputer works, the "downloading" of dives is entirely separate from the "parsing" of dives in the libdivecomputer world. And that is actually problematic for the Garmin Descent downloader, because you actually need to parse the data to even figure out whether it's actually a dive at all! The Garmin Descent is also a fitness and general excercise tracker, so people can (and do) use it for other sports than just diving, and so the activities we download may end up not being dives at all, but other events. But before we parse them, we don't know, and we aren't really supposed to parse them until after we've passed the data to the application and it passes it back for parsing. Nasty chicken-and-egg problem there.. So right now non-diving activities will just show up as very short and/or shallow dives. This is fixable by just parsing things an extra time, but I really wish libdivecomputer would just stop thinking that downloading and parsing are separate events. * garmin-descent: Add dc_usb_storage_open to the symbols list garmin: only record gasmixes for cylinders that aren't enabled garmin: don't emit fake device info and vendor event garmin: add support for downloading gas mixes garmin: add GPS coordinate data and improve parser_get_field() reports garmin: actually start using the parsed data garmin: turn all the remaining unrecognized fields into DEBUG messages garmin: add a lot of new field definitions garmin: teach the parser to show undefined values for unknown fields too garmin: fix file length header parsing garmin: teach the parser about invalid values and more dates garmin: some fields are defined in all message types Garmin: start parsing definition records Garmin Descent Mk1: flesh out the actual downloading part Add Garmin Descent Mk1 skeleton Add 'USB storage' transport enumeration
This commit is contained in:
commit
f6ea5f514a
@ -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[] = {
|
||||
@ -98,6 +99,7 @@ static const transport_table_t g_transports[] = {
|
||||
{"irda", DC_TRANSPORT_IRDA},
|
||||
{"bluetooth", DC_TRANSPORT_BLUETOOTH},
|
||||
{"ble", DC_TRANSPORT_BLE},
|
||||
{"usbstorage",DC_TRANSPORT_USBSTORAGE},
|
||||
};
|
||||
|
||||
const char *
|
||||
@ -536,6 +538,8 @@ dctool_iostream_open (dc_iostream_t **iostream, dc_context_t *context, dc_descri
|
||||
return dctool_irda_open (iostream, context, descriptor, devname);
|
||||
case DC_TRANSPORT_BLUETOOTH:
|
||||
return dctool_bluetooth_open (iostream, context, descriptor, devname);
|
||||
case DC_TRANSPORT_USBSTORAGE:
|
||||
return dc_usb_storage_open (iostream, context, devname);
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
@ -48,9 +48,13 @@ typedef enum dc_transport_t {
|
||||
DC_TRANSPORT_USBHID = (1 << 2),
|
||||
DC_TRANSPORT_IRDA = (1 << 3),
|
||||
DC_TRANSPORT_BLUETOOTH = (1 << 4),
|
||||
DC_TRANSPORT_BLE = (1 << 5)
|
||||
DC_TRANSPORT_BLE = (1 << 5),
|
||||
DC_TRANSPORT_USBSTORAGE= (1 << 6),
|
||||
} dc_transport_t;
|
||||
|
||||
// Idiotic enums can't be queried
|
||||
#define DC_TRANSPORT_USBSTORAGE DC_TRANSPORT_USBSTORAGE
|
||||
|
||||
typedef enum dc_family_t {
|
||||
DC_FAMILY_NULL = 0,
|
||||
/* Suunto */
|
||||
@ -103,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
|
||||
|
||||
@ -283,6 +283,9 @@ dc_iostream_sleep (dc_iostream_t *iostream, unsigned int milliseconds);
|
||||
dc_status_t
|
||||
dc_iostream_close (dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
dc_usb_storage_open (dc_iostream_t **out, dc_context_t *context, const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -490,6 +490,14 @@
|
||||
RelativePath="..\src\tecdiving_divecomputereu_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\garmin.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\garmin_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\timer.c"
|
||||
>
|
||||
@ -828,6 +836,10 @@
|
||||
RelativePath="..\src\tecdiving_divecomputereu.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\garmin.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\timer.h"
|
||||
>
|
||||
|
||||
@ -71,10 +71,12 @@ 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 \
|
||||
bluetooth.c \
|
||||
usb_storage.c \
|
||||
custom.c
|
||||
|
||||
if OS_WIN32
|
||||
|
||||
@ -334,6 +334,7 @@ dc_context_get_transports (dc_context_t *context)
|
||||
#elif defined(HAVE_LIBUSB) && !defined(__APPLE__)
|
||||
| DC_TRANSPORT_USBHID
|
||||
#endif
|
||||
| DC_TRANSPORT_USBSTORAGE
|
||||
#ifdef _WIN32
|
||||
#ifdef HAVE_AF_IRDA_H
|
||||
| DC_TRANSPORT_IRDA
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -328,6 +329,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
|
||||
@ -467,6 +470,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)
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
302
src/garmin.c
Normal file
302
src/garmin.c
Normal file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
unsigned char fingerprint[FIT_NAME_SIZE];
|
||||
} garmin_device_t;
|
||||
|
||||
static dc_status_t garmin_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
||||
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,
|
||||
garmin_device_set_fingerprint, /* 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;
|
||||
memset(device->fingerprint, 0, sizeof(device->fingerprint));
|
||||
|
||||
*out = (dc_device_t *) device;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
garmin_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size)
|
||||
{
|
||||
garmin_device_t *device = (garmin_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
|
||||
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;
|
||||
}
|
||||
|
||||
struct file_list {
|
||||
int nr, allocated;
|
||||
struct fit_name *array;
|
||||
};
|
||||
|
||||
static int name_cmp(const void *a, const void *b)
|
||||
{
|
||||
// Sort reverse string ordering (newest first), so use 'b,a'
|
||||
return strcmp(b,a);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the FIT file list and sort it.
|
||||
*
|
||||
* Return number of files found.
|
||||
*/
|
||||
static int get_file_list(DIR *dir, struct file_list *files)
|
||||
{
|
||||
struct dirent *de;
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
int len = strlen(de->d_name);
|
||||
|
||||
if (len != FIT_NAME_SIZE-1)
|
||||
continue;
|
||||
if (strncasecmp(de->d_name + len - 4, ".FIT", 4))
|
||||
continue;
|
||||
|
||||
if (files->nr == files->allocated) {
|
||||
struct fit_name *array;
|
||||
int n = 3*(files->allocated + 8)/2;
|
||||
size_t new_size;
|
||||
|
||||
new_size = n * sizeof(array[0]);
|
||||
array = realloc(files->array, new_size);
|
||||
if (!array)
|
||||
return DC_STATUS_NOMEMORY;
|
||||
|
||||
files->array = array;
|
||||
files->allocated = n;
|
||||
}
|
||||
|
||||
memcpy(files->array + files->nr++, de->d_name, FIT_NAME_SIZE);
|
||||
}
|
||||
|
||||
qsort(files->array, files->nr, sizeof(struct fit_name), name_cmp);
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
read_file(char *pathname, int pathlen, const char *name, dc_buffer_t *file)
|
||||
{
|
||||
int fd, rc;
|
||||
|
||||
pathname[pathlen] = '/';
|
||||
memcpy(pathname+pathlen+1, name, FIT_NAME_SIZE);
|
||||
fd = open(pathname, O_RDONLY);
|
||||
|
||||
if (fd < 0)
|
||||
return DC_STATUS_IO;
|
||||
|
||||
rc = DC_STATUS_SUCCESS;
|
||||
for (;;) {
|
||||
char buffer[4096];
|
||||
int n;
|
||||
|
||||
n = read(fd, buffer, sizeof(buffer));
|
||||
if (!n)
|
||||
break;
|
||||
if (n > 0) {
|
||||
dc_buffer_append(file, buffer, n);
|
||||
continue;
|
||||
}
|
||||
rc = DC_STATUS_IO;
|
||||
break;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
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;
|
||||
char pathname[PATH_MAX];
|
||||
size_t pathlen;
|
||||
struct file_list files = { 0, 0, NULL };
|
||||
dc_buffer_t *file;
|
||||
DIR *dir;
|
||||
int rc;
|
||||
|
||||
// Read the directory name from the iostream
|
||||
rc = dc_iostream_read(device->iostream, &pathname, sizeof(pathname), &pathlen);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
// The actual dives are under the "Garmin/Activity/" directory
|
||||
// as FIT files, with names like "2018-08-20-10-23-30.fit".
|
||||
// Make sure our buffer is big enough.
|
||||
if (pathlen + strlen("/Garmin/Activity/") + FIT_NAME_SIZE + 2 > PATH_MAX)
|
||||
return DC_STATUS_IO;
|
||||
|
||||
if (pathlen && pathname[pathlen-1] != '/')
|
||||
pathname[pathlen++] = '/';
|
||||
strcpy(pathname + pathlen, "Garmin/Activity");
|
||||
pathlen += strlen("Garmin/Activity");
|
||||
|
||||
dir = opendir(pathname);
|
||||
if (!dir)
|
||||
return DC_STATUS_IO;
|
||||
|
||||
// Get the list of FIT files
|
||||
rc = get_file_list(dir, &files);
|
||||
closedir(dir);
|
||||
if (rc != DC_STATUS_SUCCESS || !files.nr) {
|
||||
free(files.array);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Can we find the fingerprint entry?
|
||||
for (int i = 0; i < files.nr; i++) {
|
||||
const char *name = files.array[i].name;
|
||||
|
||||
if (memcmp(name, device->fingerprint, sizeof (device->fingerprint)))
|
||||
continue;
|
||||
|
||||
// Found fingerprint, just cut the array short here
|
||||
files.nr = i;
|
||||
break;
|
||||
}
|
||||
|
||||
// Enable progress notifications.
|
||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||
progress.maximum = files.nr;
|
||||
progress.current = 0;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
#if 0
|
||||
// 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);
|
||||
#endif
|
||||
|
||||
file = dc_buffer_new (16384);
|
||||
if (file == NULL) {
|
||||
ERROR (abstract->context, "Insufficient buffer space available.");
|
||||
free(files.array);
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
for (int i = 0; i < files.nr; i++) {
|
||||
const char *name = files.array[i].name;
|
||||
const unsigned char *data;
|
||||
unsigned int size;
|
||||
|
||||
if (device_is_cancelled(abstract)) {
|
||||
status = DC_STATUS_CANCELLED;
|
||||
break;
|
||||
}
|
||||
|
||||
// Reset the membuffer, read the data
|
||||
dc_buffer_clear(file);
|
||||
dc_buffer_append(file, name, FIT_NAME_SIZE);
|
||||
|
||||
status = read_file(pathname, pathlen, name, file);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
break;
|
||||
|
||||
data = dc_buffer_get_data(file);
|
||||
size = dc_buffer_get_size(file);
|
||||
|
||||
if (callback && !callback(data, size, name, FIT_NAME_SIZE, userdata))
|
||||
break;
|
||||
|
||||
progress.current++;
|
||||
device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);
|
||||
}
|
||||
|
||||
free(files.array);
|
||||
return status;
|
||||
}
|
||||
54
src/garmin.h
Normal file
54
src/garmin.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 <libdivecomputer/context.h>
|
||||
#include <libdivecomputer/iostream.h>
|
||||
#include <libdivecomputer/device.h>
|
||||
#include <libdivecomputer/parser.h>
|
||||
|
||||
#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);
|
||||
|
||||
// The dive names are of the form "2018-08-20-10-23-30.fit"
|
||||
// With the terminating zero, that's 24 bytes.
|
||||
//
|
||||
// We use this as the fingerprint, but it ends up being a
|
||||
// special fixed header in the parser data too.
|
||||
#define FIT_NAME_SIZE 24
|
||||
|
||||
struct fit_name {
|
||||
char name[FIT_NAME_SIZE];
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* GARMIN_H */
|
||||
1024
src/garmin_parser.c
Normal file
1024
src/garmin_parser.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -75,6 +75,8 @@ dc_usbhid_device_free
|
||||
dc_usbhid_iterator_new
|
||||
dc_usbhid_open
|
||||
|
||||
dc_usb_storage_open
|
||||
|
||||
dc_custom_open
|
||||
|
||||
dc_parser_new
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
109
src/usb_storage.c
Normal file
109
src/usb_storage.c
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Dummy "stream" operations for USB storage
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common-private.h"
|
||||
#include "context-private.h"
|
||||
#include "iostream-private.h"
|
||||
#include "iterator-private.h"
|
||||
#include "descriptor-private.h"
|
||||
#include "timer.h"
|
||||
|
||||
// Fake "device" that just contains the directory name that
|
||||
// you can read out of the iostream. All the actual IO is
|
||||
// up to you.
|
||||
typedef struct dc_usbstorage_t {
|
||||
dc_iostream_t base;
|
||||
char pathname[PATH_MAX];
|
||||
} dc_usbstorage_t;
|
||||
|
||||
static dc_status_t
|
||||
dc_usb_storage_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual);
|
||||
|
||||
static const dc_iostream_vtable_t dc_usbstorage_vtable = {
|
||||
sizeof(dc_usbstorage_t),
|
||||
NULL, /* set_timeout */
|
||||
NULL, /* set_latency */
|
||||
NULL, /* set_break */
|
||||
NULL, /* set_dtr */
|
||||
NULL, /* set_rts */
|
||||
NULL, /* get_lines */
|
||||
NULL, /* get_available */
|
||||
NULL, /* configure */
|
||||
dc_usb_storage_read, /* read */
|
||||
NULL, /* write */
|
||||
NULL, /* flush */
|
||||
NULL, /* purge */
|
||||
NULL, /* sleep */
|
||||
NULL, /* close */
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
dc_usb_storage_open (dc_iostream_t **out, dc_context_t *context, const char *name)
|
||||
{
|
||||
dc_usbstorage_t *device = NULL;
|
||||
struct stat st;
|
||||
|
||||
if (out == NULL || name == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
INFO (context, "Open: name=%s", name);
|
||||
if (stat(name, &st) < 0 || !S_ISDIR(st.st_mode))
|
||||
return DC_STATUS_NODEVICE;
|
||||
|
||||
// Allocate memory.
|
||||
device = (dc_usbstorage_t *) dc_iostream_allocate (context, &dc_usbstorage_vtable, DC_TRANSPORT_USBSTORAGE);
|
||||
if (device == NULL) {
|
||||
SYSERROR (context, ENOMEM);
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
strncpy(device->pathname, name, PATH_MAX);
|
||||
device->pathname[PATH_MAX-1] = 0;
|
||||
|
||||
*out = (dc_iostream_t *) device;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_usb_storage_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual)
|
||||
{
|
||||
dc_usbstorage_t *device = (dc_usbstorage_t *) iostream;
|
||||
size_t len = strlen(device->pathname);
|
||||
|
||||
if (size <= len)
|
||||
return DC_STATUS_IO;
|
||||
memcpy(data, device->pathname, len+1);
|
||||
if (actual)
|
||||
*actual = len;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user