diff --git a/include/libdivecomputer/context.h b/include/libdivecomputer/context.h index 757245b..f8fa9ea 100644 --- a/include/libdivecomputer/context.h +++ b/include/libdivecomputer/context.h @@ -31,6 +31,9 @@ extern "C" { typedef struct dc_context_t dc_context_t; +/* Opaque libdivecomputer *user* data structure */ +typedef struct dc_user_device_t dc_user_device_t; + typedef enum dc_loglevel_t { DC_LOGLEVEL_NONE, DC_LOGLEVEL_ERROR, @@ -49,7 +52,7 @@ dc_status_t dc_context_free (dc_context_t *context); dc_status_t -dc_context_set_custom_io (dc_context_t *context, dc_custom_io_t *custom_io); +dc_context_set_custom_io (dc_context_t *context, dc_custom_io_t *custom_io, dc_user_device_t *); dc_status_t dc_context_set_loglevel (dc_context_t *context, dc_loglevel_t loglevel); diff --git a/include/libdivecomputer/custom_io.h b/include/libdivecomputer/custom_io.h index 6cbf766..14a66ca 100644 --- a/include/libdivecomputer/custom_io.h +++ b/include/libdivecomputer/custom_io.h @@ -63,24 +63,47 @@ typedef enum dc_line_t { #endif /* __SERIAL_TYPES__ */ struct dc_context_t; +struct dc_user_device_t; +/* + * Two different pointers to user-supplied data. + * + * The 'userdata' pointer is for the IO routines themselves, + * generally filled in by the 'xyz_open()' routine with whatever + * file descriptor etc information. + * + * The 'user_device' pointer is set when registering the + * custom IO with the download context, and has whatever + * data the downloader needs. + * + * The two are very different. The userdata is "per instance", + * and when nesting custom IO handlers, each level would + * generally have its own userdata, that would be specific + * to that particular set of IO routines. + * + * In contrast, the user_device is filled in when the + * download context is created, before open() is even called, + * and isn't specific to the IO routines, but to the download + * as a whole. + */ typedef struct dc_custom_io_t { void *userdata; + struct dc_user_device_t *user_device; // Custom serial (generally BT rfcomm) - dc_status_t (*serial_open) (void **userdata, const char *name); - dc_status_t (*serial_close) (void **userdata); - dc_status_t (*serial_read) (void **userdata, void* data, size_t size, size_t *actual); - dc_status_t (*serial_write) (void **userdata, const void* data, size_t size, size_t *actual); - dc_status_t (*serial_purge) (void **userdata, dc_direction_t); - dc_status_t (*serial_get_available) (void **userdata, size_t *value); - dc_status_t (*serial_set_timeout) (void **userdata, long timeout); - dc_status_t (*serial_configure) (void **userdata, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol); - dc_status_t (*serial_set_dtr) (void **userdata, int level); - dc_status_t (*serial_set_rts) (void **userdata, int level); - dc_status_t (*serial_set_halfduplex) (void **userdata, unsigned int value); - dc_status_t (*serial_set_break) (void **userdata, unsigned int level); + dc_status_t (*serial_open) (struct dc_custom_io_t *io, struct dc_context_t *, const char *name); + dc_status_t (*serial_close) (struct dc_custom_io_t *io); + dc_status_t (*serial_read) (struct dc_custom_io_t *io, void* data, size_t size, size_t *actual); + dc_status_t (*serial_write) (struct dc_custom_io_t *io, const void* data, size_t size, size_t *actual); + dc_status_t (*serial_purge) (struct dc_custom_io_t *io, dc_direction_t); + dc_status_t (*serial_get_available) (struct dc_custom_io_t *io, size_t *value); + dc_status_t (*serial_set_timeout) (struct dc_custom_io_t *io, long timeout); + dc_status_t (*serial_configure) (struct dc_custom_io_t *io, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol); + dc_status_t (*serial_set_dtr) (struct dc_custom_io_t *io, int level); + dc_status_t (*serial_set_rts) (struct dc_custom_io_t *io, int level); + dc_status_t (*serial_set_halfduplex) (struct dc_custom_io_t *io, unsigned int value); + dc_status_t (*serial_set_break) (struct dc_custom_io_t *io, unsigned int level); //dc_serial_set_latency (dc_serial_t *device, unsigned int milliseconds) - Unused //dc_serial_get_lines (dc_serial_t *device, unsigned int *value) - Unused //dc_serial_flush (dc_serial_t *device) - No device interaction diff --git a/include/libdivecomputer/version.h.in b/include/libdivecomputer/version.h.in index 0f46298..6404821 100644 --- a/include/libdivecomputer/version.h.in +++ b/include/libdivecomputer/version.h.in @@ -28,7 +28,7 @@ extern "C" { /* use these defines to detect Subsurface specific features */ #define SSRF_LIBDC_VERSION 2 -#define SSRF_CUSTOM_IO 1 +#define SSRF_CUSTOM_IO 2 #define DC_VERSION "@DC_VERSION@" #define DC_VERSION_MAJOR @DC_VERSION_MAJOR@ diff --git a/src/context-private.h b/src/context-private.h index 96fc0af..800ef24 100644 --- a/src/context-private.h +++ b/src/context-private.h @@ -81,7 +81,7 @@ _dc_context_custom_io (dc_context_t *context); dc_status_t _rc; \ if (c) { \ if (c->serial_##function) \ - _rc = c->serial_##function(&c->userdata, ##__VA_ARGS__); \ + _rc = c->serial_##function(c, ##__VA_ARGS__); \ else \ _rc = DC_STATUS_SUCCESS; \ block ;\ diff --git a/src/context.c b/src/context.c index b15a9fc..f731184 100644 --- a/src/context.c +++ b/src/context.c @@ -47,6 +47,7 @@ struct dc_context_t { #endif #endif dc_custom_io_t *custom_io; + dc_user_device_t *user_device; }; #ifdef ENABLE_LOGGING @@ -213,12 +214,13 @@ dc_context_free (dc_context_t *context) } dc_status_t -dc_context_set_custom_io (dc_context_t *context, dc_custom_io_t *custom_io) +dc_context_set_custom_io (dc_context_t *context, dc_custom_io_t *custom_io, dc_user_device_t *user_device) { if (context == NULL) return DC_STATUS_INVALIDARGS; context->custom_io = custom_io; + custom_io->user_device = user_device; return DC_STATUS_SUCCESS; } diff --git a/src/serial_posix.c b/src/serial_posix.c index 1b4a4d6..9327d96 100644 --- a/src/serial_posix.c +++ b/src/serial_posix.c @@ -167,7 +167,7 @@ dc_serial_open (dc_serial_t **out, dc_context_t *context, const char *name) device->baudrate = 0; device->nbits = 0; - RETURN_IF_CUSTOM_SERIAL(context, *out = device, open, name); + RETURN_IF_CUSTOM_SERIAL(context, *out = device, open, context, name); // Open the device in non-blocking mode, to return immediately // without waiting for the modem connection to complete. diff --git a/src/serial_win32.c b/src/serial_win32.c index 406d0a2..40cddf9 100644 --- a/src/serial_win32.c +++ b/src/serial_win32.c @@ -157,7 +157,7 @@ dc_serial_open (dc_serial_t **out, dc_context_t *context, const char *name) device->baudrate = 0; device->nbits = 0; - RETURN_IF_CUSTOM_SERIAL(context, *out = device, open, name); + RETURN_IF_CUSTOM_SERIAL(context, *out = device, open, context, name); // Open the device. device->hFile = CreateFileA (devname, diff --git a/src/usbhid.c b/src/usbhid.c index 0512830..784b53c 100644 --- a/src/usbhid.c +++ b/src/usbhid.c @@ -119,7 +119,7 @@ dc_usbhid_custom_io (dc_context_t *context, unsigned int vid, unsigned int pid) return status; custom.userdata = (void *)usbhid; - dc_context_set_custom_io(context, &custom); + dc_context_set_custom_io(context, &custom, NULL); dc_usbhid_set_timeout(usbhid, 10);