Add cancellation support.
To be able to cancel an operation, an application should register a callback function that returns a non-zero value whenever the active operaton should be cancelled. A backend can invoke this callback function to query the application for a pending cancellation request.
This commit is contained in:
parent
de889f9d46
commit
f6d35fa2c2
@ -22,6 +22,7 @@
|
||||
#include <stdio.h> // fopen, fwrite, fclose
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
29
src/device.c
29
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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -43,6 +43,7 @@ device_dump
|
||||
device_foreach
|
||||
device_get_type
|
||||
device_read
|
||||
device_set_cancel
|
||||
device_set_events
|
||||
device_set_fingerprint
|
||||
device_version
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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.");
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.");
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user