diff --git a/examples/universal.c b/examples/universal.c index a5387b8..940b9aa 100644 --- a/examples/universal.c +++ b/examples/universal.c @@ -22,6 +22,7 @@ #include // fopen, fwrite, fclose #include #include +#include #ifndef _MSC_VER #include @@ -122,6 +123,25 @@ fpconvert (const char *fingerprint) return buffer; } +volatile sig_atomic_t g_cancel = 0; + +void +sighandler (int signum) +{ +#ifndef _WIN32 + // Restore the default signal handler. + signal (signum, SIG_DFL); +#endif + + g_cancel = 1; +} + +static int +cancel_cb (void *userdata) +{ + return g_cancel; +} + static void event_cb (device_t *device, device_event_t event, const void *data, void *userdata) { @@ -189,6 +209,8 @@ errmsg (device_status_t rc) return "Protocol error"; case DEVICE_STATUS_TIMEOUT: return "Timeout"; + case DEVICE_STATUS_CANCELLED: + return "Cancelled"; default: return "Unknown error"; } @@ -308,6 +330,15 @@ dowork (device_type_t backend, const char *devname, const char *filename, int me return rc; } + // Register the cancellation handler. + message ("Registering the cancellation handler.\n"); + rc = device_set_cancel (device, cancel_cb, NULL); + if (rc != DEVICE_STATUS_SUCCESS) { + WARNING ("Error registering the cancellation handler."); + device_close (device); + return rc; + } + // Register the fingerprint data. if (fingerprint) { message ("Registering the fingerprint data.\n"); @@ -425,6 +456,8 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } + signal (SIGINT, sighandler); + message_set_logfile (logfile); dc_buffer_t *fp = fpconvert (fingerprint); diff --git a/src/device-private.h b/src/device-private.h index 662b46c..20907f6 100644 --- a/src/device-private.h +++ b/src/device-private.h @@ -43,6 +43,9 @@ struct device_t { unsigned int event_mask; device_event_callback_t event_callback; void *event_userdata; + // Cancellation support. + device_cancel_callback_t cancel_callback; + void *cancel_userdata; }; struct device_backend_t { @@ -69,6 +72,9 @@ device_init (device_t *device, const device_backend_t *backend); void device_event_emit (device_t *device, device_event_t event, const void *data); +int +device_is_cancelled (device_t *device); + device_status_t device_dump_read (device_t *device, unsigned char data[], unsigned int size, unsigned int blocksize); diff --git a/src/device.c b/src/device.c index 4d31d16..e15b2cf 100644 --- a/src/device.c +++ b/src/device.c @@ -33,6 +33,9 @@ device_init (device_t *device, const device_backend_t *backend) device->event_mask = 0; device->event_callback = NULL; device->event_userdata = NULL; + + device->cancel_callback = NULL; + device->cancel_userdata = NULL; } @@ -46,6 +49,19 @@ device_get_type (device_t *device) } +device_status_t +device_set_cancel (device_t *device, device_cancel_callback_t callback, void *userdata) +{ + if (device == NULL) + return DEVICE_STATUS_UNSUPPORTED; + + device->cancel_callback = callback; + device->cancel_userdata = userdata; + + return DEVICE_STATUS_SUCCESS; +} + + device_status_t device_set_events (device_t *device, unsigned int events, device_event_callback_t callback, void *userdata) { @@ -223,3 +239,16 @@ device_event_emit (device_t *device, device_event_t event, const void *data) device->event_callback (device, event, data, device->event_userdata); } + + +int +device_is_cancelled (device_t *device) +{ + if (device == NULL) + return 0; + + if (device->cancel_callback == NULL) + return 0; + + return device->cancel_callback (device->cancel_userdata); +} diff --git a/src/device.h b/src/device.h index 0704ee4..f75bce1 100644 --- a/src/device.h +++ b/src/device.h @@ -59,7 +59,8 @@ typedef enum device_status_t { DEVICE_STATUS_IO = -4, DEVICE_STATUS_TIMEOUT = -5, DEVICE_STATUS_PROTOCOL = -6, - DEVICE_STATUS_MEMORY = -7 + DEVICE_STATUS_MEMORY = -7, + DEVICE_STATUS_CANCELLED = -8 } device_status_t; typedef enum device_event_t { @@ -87,12 +88,16 @@ typedef struct device_clock_t { dc_ticks_t systime; } device_clock_t; +typedef int (*device_cancel_callback_t) (void *userdata); + typedef void (*device_event_callback_t) (device_t *device, device_event_t event, const void *data, void *userdata); typedef int (*dive_callback_t) (const unsigned char *data, unsigned int size, const unsigned char *fingerprint, unsigned int fsize, void *userdata); device_type_t device_get_type (device_t *device); +device_status_t device_set_cancel (device_t *device, device_cancel_callback_t callback, void *userdata); + device_status_t device_set_events (device_t *device, unsigned int events, device_event_callback_t callback, void *userdata); device_status_t device_set_fingerprint (device_t *device, const unsigned char data[], unsigned int size); diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index cc13e01..5582652 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -43,6 +43,7 @@ device_dump device_foreach device_get_type device_read +device_set_cancel device_set_events device_set_fingerprint device_version diff --git a/src/mares_puck.c b/src/mares_puck.c index c4b1f71..9c69780 100644 --- a/src/mares_puck.c +++ b/src/mares_puck.c @@ -228,6 +228,11 @@ mares_puck_make_ascii (const unsigned char raw[], unsigned int rsize, unsigned c static device_status_t mares_puck_packet (mares_puck_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) { + device_t *abstract = (device_t *) device; + + if (device_is_cancelled (abstract)) + return DEVICE_STATUS_CANCELLED; + // Send the command to the device. int n = serial_write (device->port, command, csize); if (n != csize) { diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 892b073..d6183ae 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -88,6 +88,8 @@ device_is_oceanic_atom2 (device_t *abstract) static device_status_t oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) { + device_t *abstract = (device_t *) device; + // Send the command to the device. If the device responds with an // ACK byte, the command was received successfully and the answer // (if any) follows after the ACK byte. If the device responds with @@ -97,6 +99,9 @@ oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char comm unsigned int nretries = 0; unsigned char response = NAK; while (response == NAK) { + if (device_is_cancelled (abstract)) + return DEVICE_STATUS_CANCELLED; + // Send the command to the dive computer. int n = serial_write (device->port, command, csize); if (n != csize) { diff --git a/src/oceanic_veo250.c b/src/oceanic_veo250.c index bbc83d6..09ef6dd 100644 --- a/src/oceanic_veo250.c +++ b/src/oceanic_veo250.c @@ -89,6 +89,8 @@ device_is_oceanic_veo250 (device_t *abstract) static device_status_t oceanic_veo250_transfer (oceanic_veo250_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) { + device_t *abstract = (device_t *) device; + // Send the command to the device. If the device responds with an // ACK byte, the command was received successfully and the answer // (if any) follows after the ACK byte. If the device responds with @@ -98,6 +100,9 @@ oceanic_veo250_transfer (oceanic_veo250_device_t *device, const unsigned char co unsigned int nretries = 0; unsigned char response = NAK; while (response == NAK) { + if (device_is_cancelled (abstract)) + return DEVICE_STATUS_CANCELLED; + // Discard garbage bytes. serial_flush (device->port, SERIAL_QUEUE_INPUT); diff --git a/src/oceanic_vtpro.c b/src/oceanic_vtpro.c index 019182c..84acce9 100644 --- a/src/oceanic_vtpro.c +++ b/src/oceanic_vtpro.c @@ -89,6 +89,8 @@ device_is_oceanic_vtpro (device_t *abstract) static device_status_t oceanic_vtpro_transfer (oceanic_vtpro_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) { + device_t *abstract = (device_t *) device; + // Send the command to the device. If the device responds with an // ACK byte, the command was received successfully and the answer // (if any) follows after the ACK byte. If the device responds with @@ -98,6 +100,9 @@ oceanic_vtpro_transfer (oceanic_vtpro_device_t *device, const unsigned char comm unsigned int nretries = 0; unsigned char response = NAK; while (response == NAK) { + if (device_is_cancelled (abstract)) + return DEVICE_STATUS_CANCELLED; + // Send the command to the dive computer. int n = serial_write (device->port, command, csize); if (n != csize) { diff --git a/src/reefnet_sensusultra.c b/src/reefnet_sensusultra.c index f7c2336..ba4f5f3 100644 --- a/src/reefnet_sensusultra.c +++ b/src/reefnet_sensusultra.c @@ -273,6 +273,11 @@ reefnet_sensusultra_packet (reefnet_sensusultra_device_t *device, unsigned char { assert (size >= header + 2); + device_t *abstract = (device_t *) device; + + if (device_is_cancelled (abstract)) + return DEVICE_STATUS_CANCELLED; + // Receive the data packet. int rc = serial_read (device->port, data, size); if (rc != size) { diff --git a/src/suunto_d9.c b/src/suunto_d9.c index 611aa72..f9ca96d 100644 --- a/src/suunto_d9.c +++ b/src/suunto_d9.c @@ -157,6 +157,9 @@ suunto_d9_device_packet (device_t *abstract, const unsigned char command[], unsi { suunto_d9_device_t *device = (suunto_d9_device_t *) abstract; + if (device_is_cancelled (abstract)) + return DEVICE_STATUS_CANCELLED; + // Clear RTS to send the command. serial_set_rts (device->port, 0); diff --git a/src/suunto_vyper.c b/src/suunto_vyper.c index 35f6742..c212d71 100644 --- a/src/suunto_vyper.c +++ b/src/suunto_vyper.c @@ -238,6 +238,11 @@ suunto_vyper_transfer (suunto_vyper_device_t *device, const unsigned char comman { assert (asize >= size + 2); + device_t *abstract = (device_t *) device; + + if (device_is_cancelled (abstract)) + return DEVICE_STATUS_CANCELLED; + // Send the command to the dive computer. device_status_t rc = suunto_vyper_send (device, command, csize); if (rc != DEVICE_STATUS_SUCCESS) { @@ -359,6 +364,9 @@ suunto_vyper_read_dive (device_t *abstract, dc_buffer_t *buffer, int init, devic { suunto_vyper_device_t *device = (suunto_vyper_device_t*) abstract; + if (device_is_cancelled (abstract)) + return DEVICE_STATUS_CANCELLED; + // Erase the current contents of the buffer. if (!dc_buffer_clear (buffer)) { WARNING ("Insufficient buffer space available."); diff --git a/src/suunto_vyper2.c b/src/suunto_vyper2.c index d754a44..80a192f 100644 --- a/src/suunto_vyper2.c +++ b/src/suunto_vyper2.c @@ -157,6 +157,9 @@ suunto_vyper2_device_packet (device_t *abstract, const unsigned char command[], { suunto_vyper2_device_t *device = (suunto_vyper2_device_t *) abstract; + if (device_is_cancelled (abstract)) + return DEVICE_STATUS_CANCELLED; + serial_sleep (0x190 + 0xC8); // Set RTS to send the command. diff --git a/src/uwatec_aladin.c b/src/uwatec_aladin.c index 142fbf2..3d51228 100644 --- a/src/uwatec_aladin.c +++ b/src/uwatec_aladin.c @@ -218,6 +218,9 @@ uwatec_aladin_device_dump (device_t *abstract, dc_buffer_t *buffer) // Receive the header of the package. for (unsigned int i = 0; i < 4;) { + if (device_is_cancelled (abstract)) + return DEVICE_STATUS_CANCELLED; + int rc = serial_read (device->port, answer + i, 1); if (rc != 1) { WARNING ("Failed to receive the answer."); diff --git a/src/uwatec_memomouse.c b/src/uwatec_memomouse.c index 5ec17ea..bd0983f 100644 --- a/src/uwatec_memomouse.c +++ b/src/uwatec_memomouse.c @@ -349,12 +349,17 @@ uwatec_memomouse_read_packet_inner (uwatec_memomouse_device_t *device, dc_buffer static device_status_t uwatec_memomouse_dump_internal (uwatec_memomouse_device_t *device, dc_buffer_t *buffer) { + device_t *abstract = (device_t *) device; + // Enable progress notifications. device_progress_t progress = DEVICE_PROGRESS_INITIALIZER; device_event_emit (&device->base, DEVICE_EVENT_PROGRESS, &progress); // Waiting for greeting message. while (serial_get_received (device->port) == 0) { + if (device_is_cancelled (abstract)) + return DEVICE_STATUS_CANCELLED; + // Flush the input buffer. serial_flush (device->port, SERIAL_QUEUE_INPUT); @@ -421,6 +426,9 @@ uwatec_memomouse_dump_internal (uwatec_memomouse_device_t *device, dc_buffer_t * // Wait for the data packet. while (serial_get_received (device->port) == 0) { + if (device_is_cancelled (abstract)) + return DEVICE_STATUS_CANCELLED; + device_event_emit (&device->base, DEVICE_EVENT_WAITING, NULL); serial_sleep (100); }