Refactor the internal serial and IrDA api.

The low level serial and IrDA functions are modified to:

 - Use the libdivecomputer namespace prefix.

 - Return a more detailed status code instead of the zero on success and
   negative on error return value. This will allow to return more
   fine-grained error codes.

 - The read and write functions have an additional output parameter to
   return the actual number of bytes transferred. Since these functions
   are not atomic, some data might still be transferred successfully if
   an error occurs.

The dive computer backends are updated to use the new api.
This commit is contained in:
Jef Driesen 2015-09-13 11:19:14 +02:00
parent dbba7f3272
commit 84563c6303
39 changed files with 1992 additions and 1703 deletions

View File

@ -33,14 +33,9 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &citizen_aqualand_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &citizen_aqualand_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
typedef struct citizen_aqualand_device_t { typedef struct citizen_aqualand_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
unsigned char fingerprint[8]; unsigned char fingerprint[8];
} citizen_aqualand_device_t; } citizen_aqualand_device_t;
@ -82,38 +77,36 @@ citizen_aqualand_device_open (dc_device_t **out, dc_context_t *context, const ch
memset (device->fingerprint, 0, sizeof (device->fingerprint)); memset (device->fingerprint, 0, sizeof (device->fingerprint));
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (4800 8N1). // Set the serial communication protocol (4800 8N1).
rc = serial_configure (device->port, 4800, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 4800, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (1000ms). // Set the timeout for receiving data (1000ms).
if (serial_set_timeout (device->port, 1000) == -1) { status = dc_serial_set_timeout (device->port, 1000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_sleep (device->port, 300); dc_serial_sleep (device->port, 300);
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
*out = (dc_device_t *) device; *out = (dc_device_t *) device;
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -125,10 +118,12 @@ citizen_aqualand_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
citizen_aqualand_device_t *device = (citizen_aqualand_device_t*) abstract; citizen_aqualand_device_t *device = (citizen_aqualand_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -154,6 +149,7 @@ citizen_aqualand_device_set_fingerprint (dc_device_t *abstract, const unsigned c
static dc_status_t static dc_status_t
citizen_aqualand_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) citizen_aqualand_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
citizen_aqualand_device_t *device = (citizen_aqualand_device_t *) abstract; citizen_aqualand_device_t *device = (citizen_aqualand_device_t *) abstract;
// Erase the current contents of the buffer and // Erase the current contents of the buffer and
@ -163,49 +159,49 @@ citizen_aqualand_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
} }
serial_set_dtr (device->port, 1); dc_serial_set_dtr (device->port, 1);
// Send the init byte. // Send the init byte.
const unsigned char init[] = {0x7F}; const unsigned char init[] = {0x7F};
int n = serial_write (device->port, init, sizeof (init)); status = dc_serial_write (device->port, init, sizeof (init), NULL);
if (n != sizeof (init)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
serial_sleep(device->port, 1200); dc_serial_sleep(device->port, 1200);
// Send the command. // Send the command.
const unsigned char command[] = {0xFF}; const unsigned char command[] = {0xFF};
n = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (n != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
while (1) { while (1) {
// Receive the response packet. // Receive the response packet.
unsigned char answer[32] = {0}; unsigned char answer[32] = {0};
n = serial_read (device->port, answer, sizeof (answer)); status = dc_serial_read (device->port, answer, sizeof (answer), NULL);
if (n != sizeof (answer)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
dc_buffer_append(buffer, answer, sizeof (answer)); dc_buffer_append(buffer, answer, sizeof (answer));
// Send the command. // Send the command.
n = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (n != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
if (answer[sizeof(answer) - 1] == 0xFF) if (answer[sizeof(answer) - 1] == 0xFF)
break; break;
} }
serial_set_dtr (device->port, 0); dc_serial_set_dtr (device->port, 0);
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
} }

View File

@ -32,11 +32,6 @@
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array)) #define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define COCHRAN_MODEL_COMMANDER_AIR_NITROX 0 #define COCHRAN_MODEL_COMMANDER_AIR_NITROX 0
#define COCHRAN_MODEL_EMC_14 1 #define COCHRAN_MODEL_EMC_14 1
#define COCHRAN_MODEL_EMC_16 2 #define COCHRAN_MODEL_EMC_16 2
@ -92,7 +87,7 @@ typedef struct cochran_device_layout_t {
typedef struct cochran_commander_device_t { typedef struct cochran_commander_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
const cochran_device_layout_t *layout; const cochran_device_layout_t *layout;
unsigned char id[67]; unsigned char id[67];
unsigned char fingerprint[6]; unsigned char fingerprint[6];
@ -226,33 +221,36 @@ cochran_commander_get_model (cochran_commander_device_t *device)
static dc_status_t static dc_status_t
cochran_commander_serial_setup (cochran_commander_device_t *device) cochran_commander_serial_setup (cochran_commander_device_t *device)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
// Set the serial communication protocol (9600 8N2, no FC). // Set the serial communication protocol (9600 8N2, no FC).
int rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (device->base.context, "Failed to set the terminal attributes."); ERROR (device->base.context, "Failed to set the terminal attributes.");
return DC_STATUS_IO; return status;
} }
// Set the timeout for receiving data (5000 ms). // Set the timeout for receiving data (5000 ms).
if (serial_set_timeout (device->port, 5000) == -1) { status = dc_serial_set_timeout (device->port, 5000);
if (status != DC_STATUS_SUCCESS) {
ERROR (device->base.context, "Failed to set the timeout."); ERROR (device->base.context, "Failed to set the timeout.");
return DC_STATUS_IO; return status;
} }
// Wake up DC and trigger heartbeat // Wake up DC and trigger heartbeat
serial_set_break(device->port, 1); dc_serial_set_break(device->port, 1);
serial_sleep(device->port, 16); dc_serial_sleep(device->port, 16);
serial_set_break(device->port, 0); dc_serial_set_break(device->port, 0);
// Clear old heartbeats // Clear old heartbeats
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
// Wait for heartbeat byte before send // Wait for heartbeat byte before send
unsigned char answer = 0; unsigned char answer = 0;
int n = serial_read(device->port, &answer, 1); status = dc_serial_read(device->port, &answer, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (device->base.context, "Failed to receive device heartbeat."); ERROR (device->base.context, "Failed to receive device heartbeat.");
return EXITCODE (n); return status;
} }
if (answer != 0xAA) { if (answer != 0xAA) {
@ -270,6 +268,7 @@ cochran_commander_packet (cochran_commander_device_t *device, dc_event_progress_
unsigned char answer[], unsigned int asize, int high_speed) unsigned char answer[], unsigned int asize, int high_speed)
{ {
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
dc_status_t status = DC_STATUS_SUCCESS;
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
@ -279,24 +278,24 @@ cochran_commander_packet (cochran_commander_device_t *device, dc_event_progress_
// has no buffering. // has no buffering.
for (unsigned int i = 0; i < csize; i++) { for (unsigned int i = 0; i < csize; i++) {
// Give the DC time to read the character. // Give the DC time to read the character.
if (i) serial_sleep(device->port, 16); // 16 ms if (i) dc_serial_sleep(device->port, 16); // 16 ms
unsigned int n = serial_write(device->port, command + i, 1); status = dc_serial_write(device->port, command + i, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
} }
if (high_speed) { if (high_speed) {
// Give the DC time to process the command. // Give the DC time to process the command.
serial_sleep(device->port, 45); dc_serial_sleep(device->port, 45);
// Rates are odd, like 806400 for the EMC, 115200 for commander // Rates are odd, like 806400 for the EMC, 115200 for commander
int rc = serial_configure(device->port, device->layout->baudrate, 8, SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure(device->port, device->layout->baudrate, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to set the high baud rate."); ERROR (abstract->context, "Failed to set the high baud rate.");
return DC_STATUS_IO; return status;
} }
} }
@ -308,17 +307,16 @@ cochran_commander_packet (cochran_commander_device_t *device, dc_event_progress_
if (len > 1024) if (len > 1024)
len = 1024; len = 1024;
int n = serial_read (device->port, answer + nbytes, len); status = dc_serial_read (device->port, answer + nbytes, len, NULL);
if (n != len) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive data, expected %u," ERROR (abstract->context, "Failed to receive data.");
"read %u.",len, n); return status;
return EXITCODE (n);
} }
nbytes += n; nbytes += len;
if (progress) { if (progress) {
progress->current += n; progress->current += len;
device_event_emit (abstract, DC_EVENT_PROGRESS, progress); device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
} }
} }
@ -417,7 +415,7 @@ cochran_commander_read (cochran_commander_device_t *device, dc_event_progress_t
return DC_STATUS_UNSUPPORTED; return DC_STATUS_UNSUPPORTED;
} }
serial_sleep(device->port, 800); dc_serial_sleep(device->port, 800);
// set back to 9600 baud // set back to 9600 baud
rc = cochran_commander_serial_setup(device); rc = cochran_commander_serial_setup(device);
@ -630,10 +628,9 @@ cochran_commander_device_open (dc_device_t **out, dc_context_t *context, const c
cochran_commander_device_set_fingerprint((dc_device_t *) device, NULL, 0); cochran_commander_device_set_fingerprint((dc_device_t *) device, NULL, 0);
// Open the device. // Open the device.
int rc = serial_open (&device->port, device->base.context, name); status = dc_serial_open (&device->port, device->base.context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (device->base.context, "Failed to open the serial port."); ERROR (device->base.context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
@ -674,7 +671,7 @@ cochran_commander_device_open (dc_device_t **out, dc_context_t *context, const c
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -685,10 +682,12 @@ cochran_commander_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
cochran_commander_device_t *device = (cochran_commander_device_t *) abstract; cochran_commander_device_t *device = (cochran_commander_device_t *) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;

View File

@ -34,11 +34,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &cressi_edy_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &cressi_edy_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define MAXRETRIES 4 #define MAXRETRIES 4
#define SZ_PACKET 0x80 #define SZ_PACKET 0x80
@ -60,7 +55,7 @@ typedef struct cressi_edy_layout_t {
typedef struct cressi_edy_device_t { typedef struct cressi_edy_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
const cressi_edy_layout_t *layout; const cressi_edy_layout_t *layout;
unsigned char fingerprint[SZ_PAGE / 2]; unsigned char fingerprint[SZ_PAGE / 2];
unsigned int model; unsigned int model;
@ -122,6 +117,7 @@ iceil (unsigned int x, unsigned int n)
static dc_status_t static dc_status_t
cressi_edy_packet (cressi_edy_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, int trailer) cressi_edy_packet (cressi_edy_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, int trailer)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
@ -129,18 +125,18 @@ cressi_edy_packet (cressi_edy_device_t *device, const unsigned char command[], u
for (unsigned int i = 0; i < csize; ++i) { for (unsigned int i = 0; i < csize; ++i) {
// Send the command to the device. // Send the command to the device.
int n = serial_write (device->port, command + i, 1); status = dc_serial_write (device->port, command + i, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Receive the echo. // Receive the echo.
unsigned char echo = 0; unsigned char echo = 0;
n = serial_read (device->port, &echo, 1); status = dc_serial_read (device->port, &echo, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the echo."); ERROR (abstract->context, "Failed to receive the echo.");
return EXITCODE (n); return status;
} }
// Verify the echo. // Verify the echo.
@ -152,10 +148,10 @@ cressi_edy_packet (cressi_edy_device_t *device, const unsigned char command[], u
if (asize) { if (asize) {
// Receive the answer of the device. // Receive the answer of the device.
int n = serial_read (device->port, answer, asize); status = dc_serial_read (device->port, answer, asize, NULL);
if (n != asize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the trailer of the packet. // Verify the trailer of the packet.
@ -182,8 +178,8 @@ cressi_edy_transfer (cressi_edy_device_t *device, const unsigned char command[],
return rc; return rc;
// Delay the next attempt. // Delay the next attempt.
serial_sleep (device->port, 300); dc_serial_sleep (device->port, 300);
serial_flush (device->port, SERIAL_QUEUE_INPUT); dc_serial_purge (device->port, DC_DIRECTION_INPUT);
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
@ -257,39 +253,43 @@ cressi_edy_device_open (dc_device_t **out, dc_context_t *context, const char *na
memset (device->fingerprint, 0, sizeof (device->fingerprint)); memset (device->fingerprint, 0, sizeof (device->fingerprint));
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (1200 8N1). // Set the serial communication protocol (1200 8N1).
rc = serial_configure (device->port, 1200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 1200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (1000 ms). // Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->port, 1000) == -1) { status = dc_serial_set_timeout (device->port, 1000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the DTR and clear the RTS line. // Set the DTR line.
if (serial_set_dtr (device->port, 1) == -1 || status = dc_serial_set_dtr (device->port, 1);
serial_set_rts (device->port, 0) == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the DTR/RTS line."); ERROR (context, "Failed to set the DTR line.");
status = DC_STATUS_IO; goto error_close;
}
// Clear the RTS line.
status = dc_serial_set_rts (device->port, 0);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to clear the RTS line.");
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_sleep(device->port, 300); dc_serial_sleep(device->port, 300);
serial_flush(device->port, SERIAL_QUEUE_BOTH); dc_serial_purge(device->port, DC_DIRECTION_ALL);
// Send the init commands. // Send the init commands.
cressi_edy_init1 (device); cressi_edy_init1 (device);
@ -303,23 +303,22 @@ cressi_edy_device_open (dc_device_t **out, dc_context_t *context, const char *na
} }
// Set the serial communication protocol (4800 8N1). // Set the serial communication protocol (4800 8N1).
rc = serial_configure (device->port, 4800, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 4800, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_sleep(device->port, 300); dc_serial_sleep(device->port, 300);
serial_flush(device->port, SERIAL_QUEUE_BOTH); dc_serial_purge(device->port, DC_DIRECTION_ALL);
*out = (dc_device_t*) device; *out = (dc_device_t*) device;
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -331,13 +330,15 @@ cressi_edy_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
cressi_edy_device_t *device = (cressi_edy_device_t*) abstract; cressi_edy_device_t *device = (cressi_edy_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Send the quit command. // Send the quit command.
cressi_edy_quit (device); cressi_edy_quit (device);
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;

View File

@ -34,11 +34,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &cressi_leonardo_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &cressi_leonardo_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define SZ_MEMORY 32000 #define SZ_MEMORY 32000
#define RB_LOGBOOK_BEGIN 0x0100 #define RB_LOGBOOK_BEGIN 0x0100
@ -52,7 +47,7 @@
typedef struct cressi_leonardo_device_t { typedef struct cressi_leonardo_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
unsigned char fingerprint[5]; unsigned char fingerprint[5];
} cressi_leonardo_device_t; } cressi_leonardo_device_t;
@ -93,45 +88,49 @@ cressi_leonardo_device_open (dc_device_t **out, dc_context_t *context, const cha
memset (device->fingerprint, 0, sizeof (device->fingerprint)); memset (device->fingerprint, 0, sizeof (device->fingerprint));
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (115200 8N1). // Set the serial communication protocol (115200 8N1).
rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (1000 ms). // Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->port, 1000) == -1) { status = dc_serial_set_timeout (device->port, 1000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Clear the DTR and set the RTS line. // Clear the DTR line.
if (serial_set_dtr (device->port, 0) == -1 || status = dc_serial_set_dtr (device->port, 0);
serial_set_rts (device->port, 1) == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the DTR/RTS line."); ERROR (context, "Failed to clear the DTR line.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
serial_sleep (device->port, 100); // Set the RTS line.
serial_flush (device->port, SERIAL_QUEUE_BOTH); status = dc_serial_set_rts (device->port, 1);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the RTS line.");
goto error_close;
}
dc_serial_sleep (device->port, 100);
dc_serial_purge (device->port, DC_DIRECTION_ALL);
*out = (dc_device_t *) device; *out = (dc_device_t *) device;
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -142,10 +141,12 @@ cressi_leonardo_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
cressi_leonardo_device_t *device = (cressi_leonardo_device_t *) abstract; cressi_leonardo_device_t *device = (cressi_leonardo_device_t *) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -170,6 +171,7 @@ cressi_leonardo_device_set_fingerprint (dc_device_t *abstract, const unsigned ch
static dc_status_t static dc_status_t
cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
cressi_leonardo_device_t *device = (cressi_leonardo_device_t *) abstract; cressi_leonardo_device_t *device = (cressi_leonardo_device_t *) abstract;
// Erase the current contents of the buffer and // Erase the current contents of the buffer and
@ -186,18 +188,18 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
// Send the command header to the dive computer. // Send the command header to the dive computer.
const unsigned char command[] = {0x7B, 0x31, 0x32, 0x33, 0x44, 0x42, 0x41, 0x7d}; const unsigned char command[] = {0x7B, 0x31, 0x32, 0x33, 0x44, 0x42, 0x41, 0x7d};
int n = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (n != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Receive the header packet. // Receive the header packet.
unsigned char header[7] = {0}; unsigned char header[7] = {0};
n = serial_read (device->port, header, sizeof (header)); status = dc_serial_read (device->port, header, sizeof (header), NULL);
if (n != sizeof (header)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the header packet. // Verify the header packet.
@ -215,8 +217,9 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
unsigned int len = 1024; unsigned int len = 1024;
// Increase the packet size if more data is immediately available. // Increase the packet size if more data is immediately available.
int available = serial_get_received (device->port); size_t available = 0;
if (available > len) status = dc_serial_get_available (device->port, &available);
if (status == DC_STATUS_SUCCESS && available > len)
len = available; len = available;
// Limit the packet size to the total size. // Limit the packet size to the total size.
@ -224,10 +227,10 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
len = SZ_MEMORY - nbytes; len = SZ_MEMORY - nbytes;
// Read the packet. // Read the packet.
n = serial_read (device->port, data + nbytes, len); status = dc_serial_read (device->port, data + nbytes, len, NULL);
if (n != len) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Update and emit a progress event. // Update and emit a progress event.
@ -239,10 +242,10 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
// Receive the trailer packet. // Receive the trailer packet.
unsigned char trailer[4] = {0}; unsigned char trailer[4] = {0};
n = serial_read (device->port, trailer, sizeof (trailer)); status = dc_serial_read (device->port, trailer, sizeof (trailer), NULL);
if (n != sizeof (trailer)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Convert to a binary checksum. // Convert to a binary checksum.

View File

@ -33,11 +33,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &diverite_nitekq_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &diverite_nitekq_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define KEEPALIVE 0x3E // '<' #define KEEPALIVE 0x3E // '<'
#define BLOCK 0x42 // 'B' #define BLOCK 0x42 // 'B'
#define DISCONNECT 0x44 // 'D' #define DISCONNECT 0x44 // 'D'
@ -57,7 +52,7 @@
typedef struct diverite_nitekq_device_t { typedef struct diverite_nitekq_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
unsigned char version[32]; unsigned char version[32];
unsigned char fingerprint[SZ_LOGBOOK]; unsigned char fingerprint[SZ_LOGBOOK];
} diverite_nitekq_device_t; } diverite_nitekq_device_t;
@ -82,6 +77,7 @@ static const dc_device_vtable_t diverite_nitekq_device_vtable = {
static dc_status_t static dc_status_t
diverite_nitekq_send (diverite_nitekq_device_t *device, unsigned char cmd) diverite_nitekq_send (diverite_nitekq_device_t *device, unsigned char cmd)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
@ -89,10 +85,10 @@ diverite_nitekq_send (diverite_nitekq_device_t *device, unsigned char cmd)
// Send the command. // Send the command.
unsigned char command[] = {cmd}; unsigned char command[] = {cmd};
int n = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (n != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
@ -102,21 +98,22 @@ diverite_nitekq_send (diverite_nitekq_device_t *device, unsigned char cmd)
static dc_status_t static dc_status_t
diverite_nitekq_receive (diverite_nitekq_device_t *device, unsigned char data[], unsigned int size) diverite_nitekq_receive (diverite_nitekq_device_t *device, unsigned char data[], unsigned int size)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
// Read the answer. // Read the answer.
int n = serial_read (device->port, data, size); status = dc_serial_read (device->port, data, size, NULL);
if (n != size) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Read the checksum. // Read the checksum.
unsigned char checksum[2] = {0}; unsigned char checksum[2] = {0};
n = serial_read (device->port, checksum, sizeof (checksum)); status = dc_serial_read (device->port, checksum, sizeof (checksum), NULL);
if (n != sizeof (checksum)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the checksum."); ERROR (abstract->context, "Failed to receive the checksum.");
return EXITCODE (n); return status;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
@ -126,21 +123,22 @@ diverite_nitekq_receive (diverite_nitekq_device_t *device, unsigned char data[],
static dc_status_t static dc_status_t
diverite_nitekq_handshake (diverite_nitekq_device_t *device) diverite_nitekq_handshake (diverite_nitekq_device_t *device)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
// Send the command. // Send the command.
unsigned char command[] = {HANDSHAKE}; unsigned char command[] = {HANDSHAKE};
int n = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (n != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Read the answer. // Read the answer.
n = serial_read (device->port, device->version, sizeof (device->version)); status = dc_serial_read (device->port, device->version, sizeof (device->version), NULL);
if (n != sizeof (device->version)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
@ -168,31 +166,29 @@ diverite_nitekq_device_open (dc_device_t **out, dc_context_t *context, const cha
memset (device->fingerprint, 0, sizeof (device->fingerprint)); memset (device->fingerprint, 0, sizeof (device->fingerprint));
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (9600 8N1). // Set the serial communication protocol (9600 8N1).
rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (1000ms). // Set the timeout for receiving data (1000ms).
if (serial_set_timeout (device->port, 1000) == -1) { status = dc_serial_set_timeout (device->port, 1000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_sleep (device->port, 100); dc_serial_sleep (device->port, 100);
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
// Perform the handshaking. // Perform the handshaking.
status = diverite_nitekq_handshake (device); status = diverite_nitekq_handshake (device);
@ -206,7 +202,7 @@ diverite_nitekq_device_open (dc_device_t **out, dc_context_t *context, const cha
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -218,13 +214,15 @@ diverite_nitekq_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
diverite_nitekq_device_t *device = (diverite_nitekq_device_t*) abstract; diverite_nitekq_device_t *device = (diverite_nitekq_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Disconnect. // Disconnect.
diverite_nitekq_send (device, DISCONNECT); diverite_nitekq_send (device, DISCONNECT);
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;

View File

@ -32,11 +32,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &divesystem_idive_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &divesystem_idive_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define IX3M_EASY 0x22 #define IX3M_EASY 0x22
#define IX3M_DEEP 0x23 #define IX3M_DEEP 0x23
#define IX3M_TEC 0x24 #define IX3M_TEC 0x24
@ -67,7 +62,7 @@ typedef struct divesystem_idive_commands_t {
typedef struct divesystem_idive_device_t { typedef struct divesystem_idive_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
unsigned char fingerprint[4]; unsigned char fingerprint[4];
unsigned int model; unsigned int model;
} divesystem_idive_device_t; } divesystem_idive_device_t;
@ -130,38 +125,36 @@ divesystem_idive_device_open2 (dc_device_t **out, dc_context_t *context, const c
device->model = model; device->model = model;
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (115200 8N1). // Set the serial communication protocol (115200 8N1).
rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (1000ms). // Set the timeout for receiving data (1000ms).
if (serial_set_timeout (device->port, 1000) == -1) { status = dc_serial_set_timeout (device->port, 1000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_sleep (device->port, 300); dc_serial_sleep (device->port, 300);
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
*out = (dc_device_t *) device; *out = (dc_device_t *) device;
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -173,10 +166,12 @@ divesystem_idive_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
divesystem_idive_device_t *device = (divesystem_idive_device_t*) abstract; divesystem_idive_device_t *device = (divesystem_idive_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -203,6 +198,7 @@ divesystem_idive_device_set_fingerprint (dc_device_t *abstract, const unsigned c
static dc_status_t static dc_status_t
divesystem_idive_send (divesystem_idive_device_t *device, const unsigned char command[], unsigned int csize) divesystem_idive_send (divesystem_idive_device_t *device, const unsigned char command[], unsigned int csize)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
unsigned char packet[MAXPACKET + 4]; unsigned char packet[MAXPACKET + 4];
unsigned short crc = 0; unsigned short crc = 0;
@ -222,10 +218,10 @@ divesystem_idive_send (divesystem_idive_device_t *device, const unsigned char co
packet[csize + 3] = (crc ) & 0xFF; packet[csize + 3] = (crc ) & 0xFF;
// Send the data packet. // Send the data packet.
int n = serial_write (device->port, packet, csize + 4); status = dc_serial_write (device->port, packet, csize + 4, NULL);
if (n != csize + 4) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
@ -235,9 +231,9 @@ divesystem_idive_send (divesystem_idive_device_t *device, const unsigned char co
static dc_status_t static dc_status_t
divesystem_idive_receive (divesystem_idive_device_t *device, unsigned char answer[], unsigned int *asize) divesystem_idive_receive (divesystem_idive_device_t *device, unsigned char answer[], unsigned int *asize)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
unsigned char packet[MAXPACKET + 4]; unsigned char packet[MAXPACKET + 4];
int n = 0;
if (asize == NULL || *asize < MAXPACKET) { if (asize == NULL || *asize < MAXPACKET) {
ERROR (abstract->context, "Invalid arguments."); ERROR (abstract->context, "Invalid arguments.");
@ -246,10 +242,10 @@ divesystem_idive_receive (divesystem_idive_device_t *device, unsigned char answe
// Read the packet start byte. // Read the packet start byte.
while (1) { while (1) {
n = serial_read (device->port, packet + 0, 1); status = dc_serial_read (device->port, packet + 0, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the packet start byte."); ERROR (abstract->context, "Failed to receive the packet start byte.");
return EXITCODE (n); return status;
} }
if (packet[0] == START) if (packet[0] == START)
@ -257,10 +253,10 @@ divesystem_idive_receive (divesystem_idive_device_t *device, unsigned char answe
} }
// Read the packet length. // Read the packet length.
n = serial_read (device->port, packet + 1, 1); status = dc_serial_read (device->port, packet + 1, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the packet length."); ERROR (abstract->context, "Failed to receive the packet length.");
return EXITCODE (n); return status;
} }
unsigned int len = packet[1]; unsigned int len = packet[1];
@ -270,10 +266,10 @@ divesystem_idive_receive (divesystem_idive_device_t *device, unsigned char answe
} }
// Read the packet payload and checksum. // Read the packet payload and checksum.
n = serial_read (device->port, packet + 2, len + 2); status = dc_serial_read (device->port, packet + 2, len + 2, NULL);
if (n != len + 2) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the packet payload and checksum."); ERROR (abstract->context, "Failed to receive the packet payload and checksum.");
return EXITCODE (n); return status;
} }
// Verify the checksum. // Verify the checksum.
@ -346,7 +342,7 @@ divesystem_idive_transfer (divesystem_idive_device_t *device, const unsigned cha
return DC_STATUS_PROTOCOL; return DC_STATUS_PROTOCOL;
// Delay the next attempt. // Delay the next attempt.
serial_sleep(device->port, 100); dc_serial_sleep(device->port, 100);
} }
// Verify the length of the packet. // Verify the length of the packet.

View File

@ -33,11 +33,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &hw_frog_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &hw_frog_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define SZ_DISPLAY 15 #define SZ_DISPLAY 15
#define SZ_CUSTOMTEXT 13 #define SZ_CUSTOMTEXT 13
#define SZ_VERSION (SZ_CUSTOMTEXT + 4) #define SZ_VERSION (SZ_CUSTOMTEXT + 4)
@ -61,7 +56,7 @@
typedef struct hw_frog_device_t { typedef struct hw_frog_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
unsigned char fingerprint[5]; unsigned char fingerprint[5];
} hw_frog_device_t; } hw_frog_device_t;
@ -110,6 +105,7 @@ hw_frog_transfer (hw_frog_device_t *device,
unsigned char output[], unsigned char output[],
unsigned int osize) unsigned int osize)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
@ -117,19 +113,19 @@ hw_frog_transfer (hw_frog_device_t *device,
// Send the command. // Send the command.
unsigned char command[1] = {cmd}; unsigned char command[1] = {cmd};
int n = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (n != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
if (cmd != INIT && cmd != HEADER) { if (cmd != INIT && cmd != HEADER) {
// Read the echo. // Read the echo.
unsigned char answer[1] = {0}; unsigned char answer[1] = {0};
n = serial_read (device->port, answer, sizeof (answer)); status = dc_serial_read (device->port, answer, sizeof (answer), NULL);
if (n != sizeof (answer)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the echo."); ERROR (abstract->context, "Failed to receive the echo.");
return EXITCODE (n); return status;
} }
// Verify the echo. // Verify the echo.
@ -141,10 +137,10 @@ hw_frog_transfer (hw_frog_device_t *device,
if (input) { if (input) {
// Send the input data packet. // Send the input data packet.
n = serial_write (device->port, input, isize); status = dc_serial_write (device->port, input, isize, NULL);
if (n != isize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the data packet."); ERROR (abstract->context, "Failed to send the data packet.");
return EXITCODE (n); return status;
} }
} }
@ -155,8 +151,9 @@ hw_frog_transfer (hw_frog_device_t *device,
unsigned int len = 1024; unsigned int len = 1024;
// Increase the packet size if more data is immediately available. // Increase the packet size if more data is immediately available.
int available = serial_get_received (device->port); size_t available = 0;
if (available > len) status = dc_serial_get_available (device->port, &available);
if (status == DC_STATUS_SUCCESS && available > len)
len = available; len = available;
// Limit the packet size to the total size. // Limit the packet size to the total size.
@ -164,10 +161,10 @@ hw_frog_transfer (hw_frog_device_t *device,
len = osize - nbytes; len = osize - nbytes;
// Read the packet. // Read the packet.
n = serial_read (device->port, output + nbytes, len); status = dc_serial_read (device->port, output + nbytes, len, NULL);
if (n != len) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Update and emit a progress event. // Update and emit a progress event.
@ -183,10 +180,10 @@ hw_frog_transfer (hw_frog_device_t *device,
if (cmd != EXIT) { if (cmd != EXIT) {
// Read the ready byte. // Read the ready byte.
unsigned char answer[1] = {0}; unsigned char answer[1] = {0};
n = serial_read (device->port, answer, sizeof (answer)); status = dc_serial_read (device->port, answer, sizeof (answer), NULL);
if (n != sizeof (answer)) { if (status != sizeof (answer)) {
ERROR (abstract->context, "Failed to receive the ready byte."); ERROR (abstract->context, "Failed to receive the ready byte.");
return EXITCODE (n); return status;
} }
// Verify the ready byte. // Verify the ready byte.
@ -221,31 +218,29 @@ hw_frog_device_open (dc_device_t **out, dc_context_t *context, const char *name)
memset (device->fingerprint, 0, sizeof (device->fingerprint)); memset (device->fingerprint, 0, sizeof (device->fingerprint));
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (115200 8N1). // Set the serial communication protocol (115200 8N1).
rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (3000ms). // Set the timeout for receiving data (3000ms).
if (serial_set_timeout (device->port, 3000) == -1) { status = dc_serial_set_timeout (device->port, 3000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_sleep (device->port, 300); dc_serial_sleep (device->port, 300);
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
// Send the init command. // Send the init command.
status = hw_frog_transfer (device, NULL, INIT, NULL, 0, NULL, 0); status = hw_frog_transfer (device, NULL, INIT, NULL, 0, NULL, 0);
@ -259,7 +254,7 @@ hw_frog_device_open (dc_device_t **out, dc_context_t *context, const char *name)
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -281,8 +276,9 @@ hw_frog_device_close (dc_device_t *abstract)
} }
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;

View File

@ -33,11 +33,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &hw_ostc_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &hw_ostc_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define C_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) #define C_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
#define MAXRETRIES 9 #define MAXRETRIES 9
@ -64,7 +59,7 @@
typedef struct hw_ostc_device_t { typedef struct hw_ostc_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
unsigned char fingerprint[5]; unsigned char fingerprint[5];
} hw_ostc_device_t; } hw_ostc_device_t;
@ -93,23 +88,24 @@ static const dc_device_vtable_t hw_ostc_device_vtable = {
static dc_status_t static dc_status_t
hw_ostc_send (hw_ostc_device_t *device, unsigned char cmd, unsigned int echo) hw_ostc_send (hw_ostc_device_t *device, unsigned char cmd, unsigned int echo)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
// Send the command. // Send the command.
unsigned char command[1] = {cmd}; unsigned char command[1] = {cmd};
int n = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (n != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
if (echo) { if (echo) {
// Read the echo. // Read the echo.
unsigned char answer[1] = {0}; unsigned char answer[1] = {0};
n = serial_read (device->port, answer, sizeof (answer)); status = dc_serial_read (device->port, answer, sizeof (answer), NULL);
if (n != sizeof (answer)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the echo."); ERROR (abstract->context, "Failed to receive the echo.");
return EXITCODE (n); return status;
} }
// Verify the echo. // Verify the echo.
@ -144,38 +140,36 @@ hw_ostc_device_open (dc_device_t **out, dc_context_t *context, const char *name)
memset (device->fingerprint, 0, sizeof (device->fingerprint)); memset (device->fingerprint, 0, sizeof (device->fingerprint));
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (115200 8N1). // Set the serial communication protocol (115200 8N1).
rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data. // Set the timeout for receiving data.
if (serial_set_timeout (device->port, 4000) == -1) { status = dc_serial_set_timeout (device->port, 4000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_sleep (device->port, 100); dc_serial_sleep (device->port, 100);
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
*out = (dc_device_t*) device; *out = (dc_device_t*) device;
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -187,10 +181,12 @@ hw_ostc_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
hw_ostc_device_t *device = (hw_ostc_device_t*) abstract; hw_ostc_device_t *device = (hw_ostc_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -217,6 +213,7 @@ hw_ostc_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[
static dc_status_t static dc_status_t
hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
hw_ostc_device_t *device = (hw_ostc_device_t*) abstract; hw_ostc_device_t *device = (hw_ostc_device_t*) abstract;
// Erase the current contents of the buffer. // Erase the current contents of the buffer.
@ -232,18 +229,18 @@ hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
// Send the command. // Send the command.
unsigned char command[1] = {'a'}; unsigned char command[1] = {'a'};
int rc = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (rc != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (rc); return status;
} }
// Read the header. // Read the header.
unsigned char header[SZ_HEADER] = {0}; unsigned char header[SZ_HEADER] = {0};
int n = serial_read (device->port, header, sizeof (header)); status = dc_serial_read (device->port, header, sizeof (header), NULL);
if (n != sizeof (header)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the header."); ERROR (abstract->context, "Failed to receive the header.");
return EXITCODE (n); return status;
} }
// Verify the header. // Verify the header.
@ -285,8 +282,9 @@ hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
unsigned int len = 1024; unsigned int len = 1024;
// Increase the packet size if more data is immediately available. // Increase the packet size if more data is immediately available.
int available = serial_get_received (device->port); size_t available = 0;
if (available > len) status = dc_serial_get_available (device->port, &available);
if (status == DC_STATUS_SUCCESS && available > len)
len = available; len = available;
// Limit the packet size to the total size. // Limit the packet size to the total size.
@ -294,10 +292,10 @@ hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
len = size - nbytes; len = size - nbytes;
// Read the packet. // Read the packet.
int n = serial_read (device->port, data + nbytes, len); status = dc_serial_read (device->port, data + nbytes, len, NULL);
if (n != len) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Update and emit a progress event. // Update and emit a progress event.
@ -351,6 +349,7 @@ hw_ostc_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
dc_status_t dc_status_t
hw_ostc_device_md2hash (dc_device_t *abstract, unsigned char data[], unsigned int size) hw_ostc_device_md2hash (dc_device_t *abstract, unsigned char data[], unsigned int size)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; hw_ostc_device_t *device = (hw_ostc_device_t *) abstract;
if (!ISINSTANCE (abstract)) if (!ISINSTANCE (abstract))
@ -367,10 +366,10 @@ hw_ostc_device_md2hash (dc_device_t *abstract, unsigned char data[], unsigned in
return rc; return rc;
// Read the answer. // Read the answer.
int n = serial_read (device->port, data, SZ_MD2HASH); status = dc_serial_read (device->port, data, SZ_MD2HASH, NULL);
if (n != SZ_MD2HASH) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
@ -380,6 +379,7 @@ hw_ostc_device_md2hash (dc_device_t *abstract, unsigned char data[], unsigned in
dc_status_t dc_status_t
hw_ostc_device_clock (dc_device_t *abstract, const dc_datetime_t *datetime) hw_ostc_device_clock (dc_device_t *abstract, const dc_datetime_t *datetime)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; hw_ostc_device_t *device = (hw_ostc_device_t *) abstract;
if (!ISINSTANCE (abstract)) if (!ISINSTANCE (abstract))
@ -399,10 +399,10 @@ hw_ostc_device_clock (dc_device_t *abstract, const dc_datetime_t *datetime)
unsigned char packet[6] = { unsigned char packet[6] = {
datetime->hour, datetime->minute, datetime->second, datetime->hour, datetime->minute, datetime->second,
datetime->month, datetime->day, datetime->year - 2000}; datetime->month, datetime->day, datetime->year - 2000};
int n = serial_write (device->port, packet, sizeof (packet)); status = dc_serial_write (device->port, packet, sizeof (packet), NULL);
if (n != sizeof (packet)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the data packet."); ERROR (abstract->context, "Failed to send the data packet.");
return EXITCODE (n); return status;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
@ -412,6 +412,7 @@ hw_ostc_device_clock (dc_device_t *abstract, const dc_datetime_t *datetime)
dc_status_t dc_status_t
hw_ostc_device_eeprom_read (dc_device_t *abstract, unsigned int bank, unsigned char data[], unsigned int size) hw_ostc_device_eeprom_read (dc_device_t *abstract, unsigned int bank, unsigned char data[], unsigned int size)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; hw_ostc_device_t *device = (hw_ostc_device_t *) abstract;
if (!ISINSTANCE (abstract)) if (!ISINSTANCE (abstract))
@ -434,10 +435,10 @@ hw_ostc_device_eeprom_read (dc_device_t *abstract, unsigned int bank, unsigned c
return rc; return rc;
// Read the answer. // Read the answer.
int n = serial_read (device->port, data, SZ_EEPROM); status = dc_serial_read (device->port, data, SZ_EEPROM, NULL);
if (n != SZ_EEPROM) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
@ -499,6 +500,7 @@ hw_ostc_device_reset (dc_device_t *abstract)
dc_status_t dc_status_t
hw_ostc_device_screenshot (dc_device_t *abstract, dc_buffer_t *buffer, hw_ostc_format_t format) hw_ostc_device_screenshot (dc_device_t *abstract, dc_buffer_t *buffer, hw_ostc_format_t format)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; hw_ostc_device_t *device = (hw_ostc_device_t *) abstract;
if (!ISINSTANCE (abstract)) if (!ISINSTANCE (abstract))
@ -554,13 +556,13 @@ hw_ostc_device_screenshot (dc_device_t *abstract, dc_buffer_t *buffer, hw_ostc_f
unsigned int npixels = 0; unsigned int npixels = 0;
while (npixels < WIDTH * HEIGHT) { while (npixels < WIDTH * HEIGHT) {
unsigned char raw[3] = {0}; unsigned char raw[3] = {0};
int n = serial_read (device->port, raw, 1); status = dc_serial_read (device->port, raw, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the packet."); ERROR (abstract->context, "Failed to receive the packet.");
return EXITCODE (n); return status;
} }
unsigned int nbytes = n; unsigned int nbytes = 1;
unsigned int count = raw[0]; unsigned int count = raw[0];
if ((count & 0x80) == 0x00) { if ((count & 0x80) == 0x00) {
// Black pixel. // Black pixel.
@ -572,13 +574,13 @@ hw_ostc_device_screenshot (dc_device_t *abstract, dc_buffer_t *buffer, hw_ostc_f
count &= 0x3F; count &= 0x3F;
} else { } else {
// Color pixel. // Color pixel.
n = serial_read (device->port, raw + 1, 2); status = dc_serial_read (device->port, raw + 1, 2, NULL);
if (n != 2) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the packet."); ERROR (abstract->context, "Failed to receive the packet.");
return EXITCODE (n); return status;
} }
nbytes += n; nbytes += 2;
count &= 0x3F; count &= 0x3F;
} }
count++; count++;
@ -767,22 +769,23 @@ hw_ostc_firmware_readfile (hw_ostc_firmware_t *firmware, dc_context_t *context,
static dc_status_t static dc_status_t
hw_ostc_firmware_setup_internal (hw_ostc_device_t *device) hw_ostc_firmware_setup_internal (hw_ostc_device_t *device)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
// Send the command. // Send the command.
unsigned char command[1] = {0xC1}; unsigned char command[1] = {0xC1};
int n = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (n != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Read the response. // Read the response.
unsigned char answer[2] = {0}; unsigned char answer[2] = {0};
n = serial_read (device->port, answer, sizeof (answer)); status = dc_serial_read (device->port, answer, sizeof (answer), NULL);
if (n != sizeof (answer)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the response."); ERROR (abstract->context, "Failed to receive the response.");
return EXITCODE (n); return status;
} }
// Verify the response. // Verify the response.
@ -818,21 +821,22 @@ hw_ostc_firmware_setup (hw_ostc_device_t *device, unsigned int maxretries)
static dc_status_t static dc_status_t
hw_ostc_firmware_write_internal (hw_ostc_device_t *device, unsigned char *data, unsigned int size) hw_ostc_firmware_write_internal (hw_ostc_device_t *device, unsigned char *data, unsigned int size)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
// Send the packet. // Send the packet.
int n = serial_write (device->port, data, size); status = dc_serial_write (device->port, data, size, NULL);
if (n != size) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the packet."); ERROR (abstract->context, "Failed to send the packet.");
return EXITCODE (n); return status;
} }
// Read the response. // Read the response.
unsigned char answer[1] = {0}; unsigned char answer[1] = {0};
n = serial_read (device->port, answer, sizeof (answer)); status = dc_serial_read (device->port, answer, sizeof (answer), NULL);
if (n != sizeof (answer)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the response."); ERROR (abstract->context, "Failed to receive the response.");
return EXITCODE (n); return status;
} }
// Verify the response. // Verify the response.
@ -901,16 +905,17 @@ hw_ostc_device_fwupdate (dc_device_t *abstract, const char *filename)
// bootloader needs to be send repeatedly, until the response packet is // bootloader needs to be send repeatedly, until the response packet is
// received. Thus the time between each two attempts is directly controlled // received. Thus the time between each two attempts is directly controlled
// by the timeout value. // by the timeout value.
serial_set_timeout (device->port, 300); dc_serial_set_timeout (device->port, 300);
// Setup the bootloader. // Setup the bootloader.
const unsigned int baudrates[] = {19200, 115200}; const unsigned int baudrates[] = {19200, 115200};
for (unsigned int i = 0; i < C_ARRAY_SIZE(baudrates); ++i) { for (unsigned int i = 0; i < C_ARRAY_SIZE(baudrates); ++i) {
// Adjust the baudrate. // Adjust the baudrate.
if (serial_configure (device->port, baudrates[i], 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE) == -1) { rc = dc_serial_configure (device->port, baudrates[i], 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to set the terminal attributes."); ERROR (abstract->context, "Failed to set the terminal attributes.");
free (firmware); free (firmware);
return DC_STATUS_IO; return rc;
} }
// Try to setup the bootloader. // Try to setup the bootloader.
@ -926,7 +931,7 @@ hw_ostc_device_fwupdate (dc_device_t *abstract, const char *filename)
} }
// Increase the timeout again. // Increase the timeout again.
serial_set_timeout (device->port, 1000); dc_serial_set_timeout (device->port, 1000);
// Enable progress notifications. // Enable progress notifications.
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;

View File

@ -38,11 +38,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &hw_ostc3_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &hw_ostc3_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define SZ_DISPLAY 16 #define SZ_DISPLAY 16
#define SZ_CUSTOMTEXT 60 #define SZ_CUSTOMTEXT 60
#define SZ_VERSION (SZ_CUSTOMTEXT + 4) #define SZ_VERSION (SZ_CUSTOMTEXT + 4)
@ -98,7 +93,7 @@ typedef enum hw_ostc3_state_t {
typedef struct hw_ostc3_device_t { typedef struct hw_ostc3_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
unsigned int hardware; unsigned int hardware;
unsigned char fingerprint[5]; unsigned char fingerprint[5];
hw_ostc3_state_t state; hw_ostc3_state_t state;
@ -188,6 +183,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
unsigned int delay) unsigned int delay)
{ {
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
dc_status_t status = DC_STATUS_SUCCESS;
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
@ -197,18 +193,18 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
// Send the command. // Send the command.
unsigned char command[1] = {cmd}; unsigned char command[1] = {cmd};
int n = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (n != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Read the echo. // Read the echo.
unsigned char echo[1] = {0}; unsigned char echo[1] = {0};
n = serial_read (device->port, echo, sizeof (echo)); status = dc_serial_read (device->port, echo, sizeof (echo), NULL);
if (n != sizeof (echo)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the echo."); ERROR (abstract->context, "Failed to receive the echo.");
return EXITCODE (n); return status;
} }
// Verify the echo. // Verify the echo.
@ -234,10 +230,10 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
len = isize - nbytes; len = isize - nbytes;
// Write the packet. // Write the packet.
n = serial_write (device->port, input + nbytes, len); status = dc_serial_write (device->port, input + nbytes, len, NULL);
if (n != len) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the data packet."); ERROR (abstract->context, "Failed to send the data packet.");
return EXITCODE (n); return status;
} }
// Update and emit a progress event. // Update and emit a progress event.
@ -257,8 +253,9 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
unsigned int len = 1024; unsigned int len = 1024;
// Increase the packet size if more data is immediately available. // Increase the packet size if more data is immediately available.
int available = serial_get_received (device->port); size_t available = 0;
if (available > len) status = dc_serial_get_available (device->port, &available);
if (status == DC_STATUS_SUCCESS && available > len)
len = available; len = available;
// Limit the packet size to the total size. // Limit the packet size to the total size.
@ -266,10 +263,10 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
len = osize - nbytes; len = osize - nbytes;
// Read the packet. // Read the packet.
n = serial_read (device->port, output + nbytes, len); status = dc_serial_read (device->port, output + nbytes, len, NULL);
if (n != len) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Update and emit a progress event. // Update and emit a progress event.
@ -285,20 +282,22 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
if (delay) { if (delay) {
unsigned int count = delay / 100; unsigned int count = delay / 100;
for (unsigned int i = 0; i < count; ++i) { for (unsigned int i = 0; i < count; ++i) {
if (serial_get_received (device->port) > 0) size_t available = 0;
status = dc_serial_get_available (device->port, &available);
if (status == DC_STATUS_SUCCESS && available > 0)
break; break;
serial_sleep (device->port, 100); dc_serial_sleep (device->port, 100);
} }
} }
if (cmd != EXIT) { if (cmd != EXIT) {
// Read the ready byte. // Read the ready byte.
unsigned char answer[1] = {0}; unsigned char answer[1] = {0};
n = serial_read (device->port, answer, sizeof (answer)); status = dc_serial_read (device->port, answer, sizeof (answer), NULL);
if (n != sizeof (answer)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the ready byte."); ERROR (abstract->context, "Failed to receive the ready byte.");
return EXITCODE (n); return status;
} }
// Verify the ready byte. // Verify the ready byte.
@ -334,31 +333,29 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name
memset (device->fingerprint, 0, sizeof (device->fingerprint)); memset (device->fingerprint, 0, sizeof (device->fingerprint));
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (115200 8N1). // Set the serial communication protocol (115200 8N1).
rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (3000ms). // Set the timeout for receiving data (3000ms).
if (serial_set_timeout (device->port, 3000) == -1) { status = dc_serial_set_timeout (device->port, 3000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_sleep (device->port, 300); dc_serial_sleep (device->port, 300);
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
device->state = OPEN; device->state = OPEN;
@ -367,7 +364,7 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -396,28 +393,28 @@ hw_ostc3_device_init_download (hw_ostc3_device_t *device)
static dc_status_t static dc_status_t
hw_ostc3_device_init_service (hw_ostc3_device_t *device) hw_ostc3_device_init_service (hw_ostc3_device_t *device)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
dc_context_t *context = (abstract ? abstract->context : NULL); dc_context_t *context = (abstract ? abstract->context : NULL);
unsigned char command[] = {0xAA, 0xAB, 0xCD, 0xEF}; unsigned char command[] = {0xAA, 0xAB, 0xCD, 0xEF};
unsigned char output[5]; unsigned char output[5];
int n = 0;
// We cant use hw_ostc3_transfer here, due to the different echos // We cant use hw_ostc3_transfer here, due to the different echos
n = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (n != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to send the command."); ERROR (context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Give the device some time to enter service mode // Give the device some time to enter service mode
serial_sleep (device->port, 100); dc_serial_sleep (device->port, 100);
// Read the response // Read the response
n = serial_read (device->port, output, sizeof (output)); status = dc_serial_read (device->port, output, sizeof (output), NULL);
if (n != sizeof (output)) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to receive the echo."); ERROR (context, "Failed to receive the echo.");
return EXITCODE (n); return status;
} }
// Verify the response to service mode // Verify the response to service mode
@ -500,8 +497,9 @@ hw_ostc3_device_close (dc_device_t *abstract)
} }
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;

View File

@ -39,16 +39,19 @@
#endif #endif
#include "irda.h" #include "irda.h"
#include "common-private.h"
#include "context-private.h" #include "context-private.h"
#include "array.h" #include "array.h"
#ifdef _WIN32 #ifdef _WIN32
typedef int s_ssize_t;
#define S_ERRNO WSAGetLastError () #define S_ERRNO WSAGetLastError ()
#define S_EAGAIN WSAEWOULDBLOCK #define S_EAGAIN WSAEWOULDBLOCK
#define S_INVALID INVALID_SOCKET #define S_INVALID INVALID_SOCKET
#define S_IOCTL ioctlsocket #define S_IOCTL ioctlsocket
#define S_CLOSE closesocket #define S_CLOSE closesocket
#else #else
typedef ssize_t s_ssize_t;
#define S_ERRNO errno #define S_ERRNO errno
#define S_EAGAIN EAGAIN #define S_EAGAIN EAGAIN
#define S_INVALID -1 #define S_INVALID -1
@ -60,32 +63,34 @@
#define snprintf _snprintf #define snprintf _snprintf
#endif #endif
struct irda_t { struct dc_irda_t {
dc_context_t *context; dc_context_t *context;
#ifdef _WIN32 #ifdef _WIN32
SOCKET fd; SOCKET fd;
#else #else
int fd; int fd;
#endif #endif
long timeout; int timeout;
}; };
dc_status_t
int dc_irda_open (dc_irda_t **out, dc_context_t *context)
irda_socket_open (irda_t **out, dc_context_t *context)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_irda_t *device = NULL;
if (out == NULL) if (out == NULL)
return -1; // EINVAL (Invalid argument) return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
irda_t *device = (irda_t *) malloc (sizeof (irda_t)); device = (dc_irda_t *) malloc (sizeof (dc_irda_t));
if (device == NULL) { if (device == NULL) {
#ifdef _WIN32 #ifdef _WIN32
SYSERROR (context, ERROR_OUTOFMEMORY); SYSERROR (context, ERROR_OUTOFMEMORY);
#else #else
SYSERROR (context, ENOMEM); SYSERROR (context, ENOMEM);
#endif #endif
return -1; // ENOMEM (Not enough space) return DC_STATUS_NOMEMORY;
} }
// Library context. // Library context.
@ -101,6 +106,7 @@ irda_socket_open (irda_t **out, dc_context_t *context)
int rc = WSAStartup (wVersionRequested, &wsaData); int rc = WSAStartup (wVersionRequested, &wsaData);
if (rc != 0) { if (rc != 0) {
SYSERROR (context, rc); SYSERROR (context, rc);
status = DC_STATUS_UNSUPPORTED;
goto error_free; goto error_free;
} }
@ -110,6 +116,7 @@ irda_socket_open (irda_t **out, dc_context_t *context)
if (LOBYTE (wsaData.wVersion) != 2 || if (LOBYTE (wsaData.wVersion) != 2 ||
HIBYTE (wsaData.wVersion) != 2) { HIBYTE (wsaData.wVersion) != 2) {
ERROR (context, "Incorrect winsock version."); ERROR (context, "Incorrect winsock version.");
status = DC_STATUS_UNSUPPORTED;
goto error_wsacleanup; goto error_wsacleanup;
} }
#endif #endif
@ -118,12 +125,13 @@ irda_socket_open (irda_t **out, dc_context_t *context)
device->fd = socket (AF_IRDA, SOCK_STREAM, 0); device->fd = socket (AF_IRDA, SOCK_STREAM, 0);
if (device->fd == S_INVALID) { if (device->fd == S_INVALID) {
SYSERROR (context, S_ERRNO); SYSERROR (context, S_ERRNO);
status = DC_STATUS_IO;
goto error_wsacleanup; goto error_wsacleanup;
} }
*out = device; *out = device;
return 0; return DC_STATUS_SUCCESS;
error_wsacleanup: error_wsacleanup:
#ifdef _WIN32 #ifdef _WIN32
@ -131,17 +139,16 @@ error_wsacleanup:
error_free: error_free:
#endif #endif
free (device); free (device);
return -1; return status;
} }
dc_status_t
int dc_irda_close (dc_irda_t *device)
irda_socket_close (irda_t *device)
{ {
int errcode = 0; dc_status_t status = DC_STATUS_SUCCESS;
if (device == NULL) if (device == NULL)
return -1; return DC_STATUS_SUCCESS;
// Terminate all send and receive operations. // Terminate all send and receive operations.
shutdown (device->fd, 0); shutdown (device->fd, 0);
@ -149,35 +156,34 @@ irda_socket_close (irda_t *device)
// Close the socket. // Close the socket.
if (S_CLOSE (device->fd) != 0) { if (S_CLOSE (device->fd) != 0) {
SYSERROR (device->context, S_ERRNO); SYSERROR (device->context, S_ERRNO);
errcode = -1; dc_status_set_error(&status, DC_STATUS_IO);
} }
#ifdef _WIN32 #ifdef _WIN32
// Terminate the winsock dll. // Terminate the winsock dll.
if (WSACleanup () != 0) { if (WSACleanup () != 0) {
SYSERROR (device->context, S_ERRNO); SYSERROR (device->context, S_ERRNO);
errcode = -1; dc_status_set_error(&status, DC_STATUS_IO);
} }
#endif #endif
// Free memory. // Free memory.
free (device); free (device);
return errcode; return status;
} }
dc_status_t
int dc_irda_set_timeout (dc_irda_t *device, int timeout)
irda_socket_set_timeout (irda_t *device, long timeout)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return DC_STATUS_INVALIDARGS;
INFO (device->context, "Timeout: value=%li", timeout); INFO (device->context, "Timeout: value=%i", timeout);
device->timeout = timeout; device->timeout = timeout;
return 0; return DC_STATUS_SUCCESS;
} }
@ -192,11 +198,11 @@ irda_socket_set_timeout (irda_t *device, long timeout)
sizeof (struct irda_device_info) * (DISCOVER_MAX_DEVICES - 1) sizeof (struct irda_device_info) * (DISCOVER_MAX_DEVICES - 1)
#endif #endif
int dc_status_t
irda_socket_discover (irda_t *device, irda_callback_t callback, void *userdata) dc_irda_discover (dc_irda_t *device, dc_irda_callback_t callback, void *userdata)
{ {
if (device == NULL) if (device == NULL)
return -1; return DC_STATUS_INVALIDARGS;
unsigned char data[DISCOVER_BUFSIZE] = {0}; unsigned char data[DISCOVER_BUFSIZE] = {0};
#ifdef _WIN32 #ifdef _WIN32
@ -223,13 +229,13 @@ irda_socket_discover (irda_t *device, irda_callback_t callback, void *userdata)
if (rc != 0) { if (rc != 0) {
if (S_ERRNO != S_EAGAIN) { if (S_ERRNO != S_EAGAIN) {
SYSERROR (device->context, S_ERRNO); SYSERROR (device->context, S_ERRNO);
return -1; // Error during getsockopt call. return DC_STATUS_IO;
} }
} }
// Abort if the maximum number of retries is reached. // Abort if the maximum number of retries is reached.
if (nretries++ >= DISCOVER_MAX_RETRIES) if (nretries++ >= DISCOVER_MAX_RETRIES)
return 0; return DC_STATUS_SUCCESS;
// Restore the size parameter in case it was // Restore the size parameter in case it was
// modified by the previous getsockopt call. // modified by the previous getsockopt call.
@ -266,15 +272,14 @@ irda_socket_discover (irda_t *device, irda_callback_t callback, void *userdata)
} }
} }
return 0; return DC_STATUS_SUCCESS;
} }
dc_status_t
int dc_irda_connect_name (dc_irda_t *device, unsigned int address, const char *name)
irda_socket_connect_name (irda_t *device, unsigned int address, const char *name)
{ {
if (device == NULL) if (device == NULL)
return -1; return DC_STATUS_INVALIDARGS;
INFO (device->context, "Connect: address=%08x, name=%s", address, name ? name : ""); INFO (device->context, "Connect: address=%08x, name=%s", address, name ? name : "");
@ -301,17 +306,17 @@ irda_socket_connect_name (irda_t *device, unsigned int address, const char *name
if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) { if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) {
SYSERROR (device->context, S_ERRNO); SYSERROR (device->context, S_ERRNO);
return -1; return DC_STATUS_IO;
} }
return 0; return DC_STATUS_SUCCESS;
} }
int dc_status_t
irda_socket_connect_lsap (irda_t *device, unsigned int address, unsigned int lsap) dc_irda_connect_lsap (dc_irda_t *device, unsigned int address, unsigned int lsap)
{ {
if (device == NULL) if (device == NULL)
return -1; return DC_STATUS_INVALIDARGS;
INFO (device->context, "Connect: address=%08x, lsap=%u", address, lsap); INFO (device->context, "Connect: address=%08x, lsap=%u", address, lsap);
@ -333,18 +338,17 @@ irda_socket_connect_lsap (irda_t *device, unsigned int address, unsigned int lsa
if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) { if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) {
SYSERROR (device->context, S_ERRNO); SYSERROR (device->context, S_ERRNO);
return -1; return DC_STATUS_IO;
} }
return 0; return DC_STATUS_SUCCESS;
} }
dc_status_t
int dc_irda_get_available (dc_irda_t *device, size_t *value)
irda_socket_available (irda_t *device)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return DC_STATUS_INVALIDARGS;
#ifdef _WIN32 #ifdef _WIN32
unsigned long bytes = 0; unsigned long bytes = 0;
@ -354,18 +358,25 @@ irda_socket_available (irda_t *device)
if (S_IOCTL (device->fd, FIONREAD, &bytes) != 0) { if (S_IOCTL (device->fd, FIONREAD, &bytes) != 0) {
SYSERROR (device->context, S_ERRNO); SYSERROR (device->context, S_ERRNO);
return -1; return DC_STATUS_IO;
} }
return bytes; if (value)
*value = bytes;
return DC_STATUS_SUCCESS;
} }
dc_status_t
int dc_irda_read (dc_irda_t *device, void *data, size_t size, size_t *actual)
irda_socket_read (irda_t *device, void *data, unsigned int size)
{ {
if (device == NULL) dc_status_t status = DC_STATUS_SUCCESS;
return -1; // EINVAL (Invalid argument) size_t nbytes = 0;
if (device == NULL) {
status = DC_STATUS_INVALIDARGS;
goto out;
}
struct timeval tv; struct timeval tv;
if (device->timeout >= 0) { if (device->timeout >= 0) {
@ -377,20 +388,21 @@ irda_socket_read (irda_t *device, void *data, unsigned int size)
FD_ZERO (&fds); FD_ZERO (&fds);
FD_SET (device->fd, &fds); FD_SET (device->fd, &fds);
unsigned int nbytes = 0;
while (nbytes < size) { while (nbytes < size) {
int rc = select (device->fd + 1, &fds, NULL, NULL, (device->timeout >= 0 ? &tv : NULL)); int rc = select (device->fd + 1, &fds, NULL, NULL, (device->timeout >= 0 ? &tv : NULL));
if (rc < 0) { if (rc < 0) {
SYSERROR (device->context, S_ERRNO); SYSERROR (device->context, S_ERRNO);
return -1; // Error during select call. status = DC_STATUS_IO;
goto out;
} else if (rc == 0) { } else if (rc == 0) {
break; // Timeout. break; // Timeout.
} }
int n = recv (device->fd, (char*) data + nbytes, size - nbytes, 0); s_ssize_t n = recv (device->fd, (char*) data + nbytes, size - nbytes, 0);
if (n < 0) { if (n < 0) {
SYSERROR (device->context, S_ERRNO); SYSERROR (device->context, S_ERRNO);
return -1; // Error during recv call. status = DC_STATUS_IO;
goto out;
} else if (n == 0) { } else if (n == 0) {
break; // EOF reached. break; // EOF reached.
} }
@ -398,30 +410,50 @@ irda_socket_read (irda_t *device, void *data, unsigned int size)
nbytes += n; nbytes += n;
} }
if (nbytes != size) {
status = DC_STATUS_TIMEOUT;
}
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes); HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes);
return nbytes; if (actual)
*actual = nbytes;
return status;
} }
dc_status_t
int dc_irda_write (dc_irda_t *device, const void *data, size_t size, size_t *actual)
irda_socket_write (irda_t *device, const void *data, unsigned int size)
{ {
if (device == NULL) dc_status_t status = DC_STATUS_SUCCESS;
return -1; // EINVAL (Invalid argument) size_t nbytes = 0;
if (device == NULL) {
status = DC_STATUS_INVALIDARGS;
goto out;
}
unsigned int nbytes = 0;
while (nbytes < size) { while (nbytes < size) {
int n = send (device->fd, (char*) data + nbytes, size - nbytes, 0); s_ssize_t n = send (device->fd, (char*) data + nbytes, size - nbytes, 0);
if (n < 0) { if (n < 0) {
SYSERROR (device->context, S_ERRNO); SYSERROR (device->context, S_ERRNO);
return -1; // Error during send call. status = DC_STATUS_IO;
goto out;
} }
nbytes += n; nbytes += n;
} }
if (nbytes != size) {
status = DC_STATUS_TIMEOUT;
}
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes); HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes);
return nbytes; if (actual)
*actual = nbytes;
return status;
} }

View File

@ -19,37 +19,161 @@
* MA 02110-1301 USA * MA 02110-1301 USA
*/ */
#ifndef IRDA_H #ifndef DC_IRDA_H
#define IRDA_H #define DC_IRDA_H
#include <libdivecomputer/common.h>
#include <libdivecomputer/context.h> #include <libdivecomputer/context.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
typedef struct irda_t irda_t; /**
* Opaque object representing an IrDA connection.
*/
typedef struct dc_irda_t dc_irda_t;
typedef void (*irda_callback_t) (unsigned int address, const char *name, unsigned int charset, unsigned int hints, void *userdata); /**
* IrDA enumeration callback.
*
* @param[in] address The IrDA device address.
* @param[in] name The IrDA device name.
* @param[in] charset The IrDA device character set.
* @param[in] hints The IrDA device hints.
* @param[in] userdata The user data pointer.
*/
typedef void (*dc_irda_callback_t) (unsigned int address, const char *name, unsigned int charset, unsigned int hints, void *userdata);
int irda_socket_open (irda_t **device, dc_context_t *context); /**
* Open an IrDA connection.
*
* @param[out] irda A location to store the IrDA connection.
* @param[in] context A valid context object.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_irda_open (dc_irda_t **irda, dc_context_t *context);
int irda_socket_close (irda_t *device); /**
* Close the IrDA connection and free all resources.
*
* @param[in] irda A valid IrDA connection.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_irda_close (dc_irda_t *irda);
int irda_socket_set_timeout (irda_t *device, long timeout); /**
* Set the read timeout.
*
* There are three distinct modes available:
*
* 1. Blocking (timeout < 0):
*
* The read operation is blocked until all the requested bytes have
* been received. If the requested number of bytes does not arrive,
* the operation will block forever.
*
* 2. Non-blocking (timeout == 0):
*
* The read operation returns immediately with the bytes that have
* already been received, even if no bytes have been received.
*
* 3. Timeout (timeout > 0):
*
* The read operation is blocked until all the requested bytes have
* been received. If the requested number of bytes does not arrive
* within the specified amount of time, the operation will return
* with the bytes that have already been received.
*
* @param[in] irda A valid IrDA connection.
* @param[in] timeout The timeout in milliseconds.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_irda_set_timeout (dc_irda_t *irda, int timeout);
int irda_socket_discover (irda_t *device, irda_callback_t callback, void *userdata); /**
* Enumerate the IrDA devices.
*
* @param[in] irda A valid IrDA connection.
* @param[in] callback The callback function to call.
* @param[in] userdata User data to pass to the callback function.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_irda_discover (dc_irda_t *irda, dc_irda_callback_t callback, void *userdata);
int irda_socket_connect_name (irda_t *device, unsigned int address, const char *name); /**
int irda_socket_connect_lsap (irda_t *device, unsigned int address, unsigned int lsap); * Connect to an IrDA device.
*
* @param[in] irda A valid IrDA connection.
* @param[in] address The IrDA device address.
* @param[in] name The IrDA service name.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_irda_connect_name (dc_irda_t *irda, unsigned int address, const char *name);
int irda_socket_available (irda_t *device); /**
* Connect to an IrDA device.
*
* @param[in] irda A valid IrDA connection.
* @param[in] address The IrDA device address.
* @param[in] lsap The IrDA LSAP number.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_irda_connect_lsap (dc_irda_t *irda, unsigned int address, unsigned int lsap);
int irda_socket_read (irda_t *device, void *data, unsigned int size); /**
* Query the number of available bytes in the input buffer.
*
* @param[in] irda A valid IrDA connection.
* @param[out] value A location to store the number of bytes in the
* input buffer.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_irda_get_available (dc_irda_t *irda, size_t *value);
int irda_socket_write (irda_t *device, const void *data, unsigned int size); /**
* Read data from the IrDA connection.
*
* @param[in] irda A valid IrDA connection.
* @param[out] data The memory buffer to read the data into.
* @param[in] size The number of bytes to read.
* @param[out] actual An (optional) location to store the actual
* number of bytes transferred.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_irda_read (dc_irda_t *irda, void *data, size_t size, size_t *actual);
/**
* Write data to the IrDA connection.
*
* @param[in] irda A valid IrDA connection.
* @param[in] data The memory buffer to write the data from.
* @param[in] size The number of bytes to write.
* @param[out] actual An (optional) location to store the actual
* number of bytes transferred.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_irda_write (dc_irda_t *irda, const void *data, size_t size, size_t *actual);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif /* IRDA_H */ #endif /* DC_IRDA_H */

View File

@ -23,65 +23,56 @@
#include "irda.h" #include "irda.h"
dc_status_t
int dc_irda_open (dc_irda_t **out, dc_context_t *context)
irda_socket_open (irda_t **out, dc_context_t *context)
{ {
return -1; return DC_STATUS_UNSUPPORTED;
} }
dc_status_t
int dc_irda_close (dc_irda_t *device)
irda_socket_close (irda_t *device)
{ {
return -1; return DC_STATUS_UNSUPPORTED;
} }
dc_status_t
int dc_irda_set_timeout (dc_irda_t *device, int timeout)
irda_socket_set_timeout (irda_t *device, long timeout)
{ {
return -1; return DC_STATUS_UNSUPPORTED;
} }
dc_status_t
int dc_irda_discover (dc_irda_t *device, dc_irda_callback_t callback, void *userdata)
irda_socket_discover (irda_t *device, irda_callback_t callback, void *userdata)
{ {
return -1; return DC_STATUS_UNSUPPORTED;
} }
dc_status_t
int dc_irda_connect_name (dc_irda_t *device, unsigned int address, const char *name)
irda_socket_connect_name (irda_t *device, unsigned int address, const char *name)
{ {
return -1; return DC_STATUS_UNSUPPORTED;
} }
dc_status_t
int dc_irda_connect_lsap (dc_irda_t *device, unsigned int address, unsigned int lsap)
irda_socket_connect_lsap (irda_t *device, unsigned int address, unsigned int lsap)
{ {
return -1; return DC_STATUS_UNSUPPORTED;
} }
dc_status_t
int dc_irda_get_available (dc_irda_t *device, size_t *value)
irda_socket_available (irda_t *device)
{ {
return -1; return DC_STATUS_UNSUPPORTED;
} }
dc_status_t
int dc_irda_read (dc_irda_t *device, void *data, size_t size, size_t *actual)
irda_socket_read (irda_t *device, void *data, unsigned int size)
{ {
return -1; return DC_STATUS_UNSUPPORTED;
} }
dc_status_t
int dc_irda_write (dc_irda_t *device, const void *data, size_t size, size_t *actual)
irda_socket_write (irda_t *device, const void *data, unsigned int size)
{ {
return -1; return DC_STATUS_UNSUPPORTED;
} }

View File

@ -28,11 +28,6 @@
#include "checksum.h" #include "checksum.h"
#include "array.h" #include "array.h"
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define MAXRETRIES 4 #define MAXRETRIES 4
#define FP_OFFSET 8 #define FP_OFFSET 8
@ -86,29 +81,30 @@ mares_common_make_ascii (const unsigned char raw[], unsigned int rsize, unsigned
static dc_status_t static dc_status_t
mares_common_packet (mares_common_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) mares_common_packet (mares_common_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
if (device->delay) { if (device->delay) {
serial_sleep (device->port, device->delay); dc_serial_sleep (device->port, device->delay);
} }
// Send the command to the device. // Send the command to the device.
int n = serial_write (device->port, command, csize); status = dc_serial_write (device->port, command, csize, NULL);
if (n != csize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
if (device->echo) { if (device->echo) {
// Receive the echo of the command. // Receive the echo of the command.
unsigned char echo[PACKETSIZE] = {0}; unsigned char echo[PACKETSIZE] = {0};
n = serial_read (device->port, echo, csize); status = dc_serial_read (device->port, echo, csize, NULL);
if (n != csize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the echo."); ERROR (abstract->context, "Failed to receive the echo.");
return EXITCODE (n); return status;
} }
// Verify the echo. // Verify the echo.
@ -118,10 +114,10 @@ mares_common_packet (mares_common_device_t *device, const unsigned char command[
} }
// Receive the answer of the device. // Receive the answer of the device.
n = serial_read (device->port, answer, asize); status = dc_serial_read (device->port, answer, asize, NULL);
if (n != asize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the header and trailer of the packet. // Verify the header and trailer of the packet.
@ -159,8 +155,8 @@ mares_common_transfer (mares_common_device_t *device, const unsigned char comman
return rc; return rc;
// Discard any garbage bytes. // Discard any garbage bytes.
serial_sleep (device->port, 100); dc_serial_sleep (device->port, 100);
serial_flush (device->port, SERIAL_QUEUE_INPUT); dc_serial_purge (device->port, DC_DIRECTION_INPUT);
} }
return rc; return rc;

View File

@ -41,7 +41,7 @@ typedef struct mares_common_layout_t {
typedef struct mares_common_device_t { typedef struct mares_common_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
unsigned int echo; unsigned int echo;
unsigned int delay; unsigned int delay;
} mares_common_device_t; } mares_common_device_t;

View File

@ -122,39 +122,43 @@ mares_darwin_device_open (dc_device_t **out, dc_context_t *context, const char *
device->layout = &mares_darwin_layout; device->layout = &mares_darwin_layout;
// Open the device. // Open the device.
int rc = serial_open (&device->base.port, context, name); status = dc_serial_open (&device->base.port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (9600 8N1). // Set the serial communication protocol (9600 8N1).
rc = serial_configure (device->base.port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->base.port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (1000 ms). // Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->base.port, 1000) == -1) { status = dc_serial_set_timeout (device->base.port, 1000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the DTR/RTS lines. // Set the DTR line.
if (serial_set_dtr (device->base.port, 1) == -1 || status = dc_serial_set_dtr (device->base.port, 1);
serial_set_rts (device->base.port, 1) == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the DTR/RTS line."); ERROR (context, "Failed to set the DTR line.");
status = DC_STATUS_IO; goto error_close;
}
// Set the RTS line.
status = dc_serial_set_rts (device->base.port, 1);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the RTS line.");
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_sleep (device->base.port, 100); dc_serial_sleep (device->base.port, 100);
serial_flush (device->base.port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->base.port, DC_DIRECTION_ALL);
// Override the base class values. // Override the base class values.
device->base.echo = 1; device->base.echo = 1;
@ -165,7 +169,7 @@ mares_darwin_device_open (dc_device_t **out, dc_context_t *context, const char *
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->base.port); dc_serial_close (device->base.port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -176,10 +180,12 @@ mares_darwin_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
mares_darwin_device_t *device = (mares_darwin_device_t *) abstract; mares_darwin_device_t *device = (mares_darwin_device_t *) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->base.port) == -1) { rc = dc_serial_close (device->base.port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;

View File

@ -34,11 +34,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &mares_iconhd_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &mares_iconhd_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define MATRIX 0x0F #define MATRIX 0x0F
#define SMART 0x000010 #define SMART 0x000010
#define SMARTAPNEA 0x010010 #define SMARTAPNEA 0x010010
@ -69,7 +64,7 @@ typedef struct mares_iconhd_model_t {
typedef struct mares_iconhd_device_t { typedef struct mares_iconhd_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
const mares_iconhd_layout_t *layout; const mares_iconhd_layout_t *layout;
unsigned char fingerprint[10]; unsigned char fingerprint[10];
unsigned char version[140]; unsigned char version[140];
@ -150,6 +145,7 @@ mares_iconhd_transfer (mares_iconhd_device_t *device,
const unsigned char command[], unsigned int csize, const unsigned char command[], unsigned int csize,
unsigned char answer[], unsigned int asize) unsigned char answer[], unsigned int asize)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
assert (csize >= 2); assert (csize >= 2);
@ -158,18 +154,18 @@ mares_iconhd_transfer (mares_iconhd_device_t *device,
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
// Send the command header to the dive computer. // Send the command header to the dive computer.
int n = serial_write (device->port, command, 2); status = dc_serial_write (device->port, command, 2, NULL);
if (n != 2) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Receive the header byte. // Receive the header byte.
unsigned char header[1] = {0}; unsigned char header[1] = {0};
n = serial_read (device->port, header, sizeof (header)); status = dc_serial_read (device->port, header, sizeof (header), NULL);
if (n != sizeof (header)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the header byte. // Verify the header byte.
@ -180,26 +176,26 @@ mares_iconhd_transfer (mares_iconhd_device_t *device,
// Send the command payload to the dive computer. // Send the command payload to the dive computer.
if (csize > 2) { if (csize > 2) {
n = serial_write (device->port, command + 2, csize - 2); status = dc_serial_write (device->port, command + 2, csize - 2, NULL);
if (n != csize - 2) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
} }
// Read the packet. // Read the packet.
n = serial_read (device->port, answer, asize); status = dc_serial_read (device->port, answer, asize, NULL);
if (n != asize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Receive the trailer byte. // Receive the trailer byte.
unsigned char trailer[1] = {0}; unsigned char trailer[1] = {0};
n = serial_read (device->port, trailer, sizeof (trailer)); status = dc_serial_read (device->port, trailer, sizeof (trailer), NULL);
if (n != sizeof (trailer)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the trailer byte. // Verify the trailer byte.
@ -237,39 +233,42 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char *
device->packetsize = 0; device->packetsize = 0;
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (115200 8E1). // Set the serial communication protocol (115200 8E1).
rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_EVEN, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_EVEN, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (1000 ms). // Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->port, 1000) == -1) { status = dc_serial_set_timeout (device->port, 1000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the DTR/RTS lines. // Clear the DTR line.
if (serial_set_dtr (device->port, 0) == -1 || status = dc_serial_set_dtr (device->port, 0);
serial_set_rts (device->port, 0) == -1) if (status != DC_STATUS_SUCCESS) {
{ ERROR (context, "Failed to clear the DTR line.");
ERROR (context, "Failed to set the DTR/RTS line."); goto error_close;
status = DC_STATUS_IO; }
// Clear the RTS line.
status = dc_serial_set_rts (device->port, 0);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to clear the RTS line.");
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
// Send the version command. // Send the version command.
unsigned char command[] = {0xC2, 0x67}; unsigned char command[] = {0xC2, 0x67};
@ -312,7 +311,7 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char *
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -324,10 +323,12 @@ mares_iconhd_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
mares_iconhd_device_t *device = (mares_iconhd_device_t*) abstract; mares_iconhd_device_t *device = (mares_iconhd_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;

View File

@ -33,11 +33,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &mares_nemo_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &mares_nemo_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#ifdef PACKETSIZE #ifdef PACKETSIZE
#undef PACKETSIZE /* Override the common value. */ #undef PACKETSIZE /* Override the common value. */
#endif #endif
@ -51,7 +46,7 @@
typedef struct mares_nemo_device_t { typedef struct mares_nemo_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
unsigned char fingerprint[5]; unsigned char fingerprint[5];
} mares_nemo_device_t; } mares_nemo_device_t;
@ -109,45 +104,49 @@ mares_nemo_device_open (dc_device_t **out, dc_context_t *context, const char *na
memset (device->fingerprint, 0, sizeof (device->fingerprint)); memset (device->fingerprint, 0, sizeof (device->fingerprint));
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (9600 8N1). // Set the serial communication protocol (9600 8N1).
rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (1000 ms). // Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->port, 1000) == -1) { status = dc_serial_set_timeout (device->port, 1000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the DTR/RTS lines. // Set the DTR line.
if (serial_set_dtr (device->port, 1) == -1 || status = dc_serial_set_dtr (device->port, 1);
serial_set_rts (device->port, 1) == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the DTR/RTS line."); ERROR (context, "Failed to set the DTR line.");
status = DC_STATUS_IO; goto error_close;
}
// Set the RTS line.
status = dc_serial_set_rts (device->port, 1);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the RTS line.");
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
*out = (dc_device_t*) device; *out = (dc_device_t*) device;
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -159,10 +158,12 @@ mares_nemo_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
mares_nemo_device_t *device = (mares_nemo_device_t*) abstract; mares_nemo_device_t *device = (mares_nemo_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -189,6 +190,7 @@ mares_nemo_device_set_fingerprint (dc_device_t *abstract, const unsigned char da
static dc_status_t static dc_status_t
mares_nemo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) mares_nemo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
mares_nemo_device_t *device = (mares_nemo_device_t *) abstract; mares_nemo_device_t *device = (mares_nemo_device_t *) abstract;
// Erase the current contents of the buffer and // Erase the current contents of the buffer and
@ -204,21 +206,22 @@ mares_nemo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
// Wait until some data arrives. // Wait until some data arrives.
while (serial_get_received (device->port) == 0) { size_t available = 0;
while (dc_serial_get_available (device->port, &available) == DC_STATUS_SUCCESS && available == 0) {
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
device_event_emit (abstract, DC_EVENT_WAITING, NULL); device_event_emit (abstract, DC_EVENT_WAITING, NULL);
serial_sleep (device->port, 100); dc_serial_sleep (device->port, 100);
} }
// Receive the header of the package. // Receive the header of the package.
unsigned char header = 0x00; unsigned char header = 0x00;
for (unsigned int i = 0; i < 20;) { for (unsigned int i = 0; i < 20;) {
int n = serial_read (device->port, &header, 1); status = dc_serial_read (device->port, &header, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the header."); ERROR (abstract->context, "Failed to receive the header.");
return EXITCODE (n); return status;
} }
if (header == 0xEE) { if (header == 0xEE) {
i++; // Continue. i++; // Continue.
@ -235,10 +238,10 @@ mares_nemo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
while (nbytes < MEMORYSIZE) { while (nbytes < MEMORYSIZE) {
// Read the packet. // Read the packet.
unsigned char packet[(PACKETSIZE + 1) * 2] = {0}; unsigned char packet[(PACKETSIZE + 1) * 2] = {0};
int n = serial_read (device->port, packet, sizeof (packet)); status = dc_serial_read (device->port, packet, sizeof (packet), NULL);
if (n != sizeof (packet)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the checksums of the packet. // Verify the checksums of the packet.

View File

@ -110,38 +110,42 @@ mares_puck_device_open (dc_device_t **out, dc_context_t *context, const char *na
memset (device->fingerprint, 0, sizeof (device->fingerprint)); memset (device->fingerprint, 0, sizeof (device->fingerprint));
// Open the device. // Open the device.
int rc = serial_open (&device->base.port, context, name); status = dc_serial_open (&device->base.port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (38400 8N1). // Set the serial communication protocol (38400 8N1).
rc = serial_configure (device->base.port, 38400, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->base.port, 38400, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (1000 ms). // Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->base.port, 1000) == -1) { status = dc_serial_set_timeout (device->base.port, 1000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Clear the DTR/RTS lines. // Clear the DTR line.
if (serial_set_dtr (device->base.port, 0) == -1 || status = dc_serial_set_dtr (device->base.port, 0);
serial_set_rts (device->base.port, 0) == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the DTR/RTS line."); ERROR (context, "Failed to clear the DTR line.");
status = DC_STATUS_IO; goto error_close;
}
// Clear the RTS line.
status = dc_serial_set_rts (device->base.port, 0);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to clear the RTS line.");
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_flush (device->base.port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->base.port, DC_DIRECTION_ALL);
// Identify the model number. // Identify the model number.
unsigned char header[PACKETSIZE] = {0}; unsigned char header[PACKETSIZE] = {0};
@ -172,7 +176,7 @@ mares_puck_device_open (dc_device_t **out, dc_context_t *context, const char *na
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->base.port); dc_serial_close (device->base.port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -184,10 +188,12 @@ mares_puck_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
mares_puck_device_t *device = (mares_puck_device_t*) abstract; mares_puck_device_t *device = (mares_puck_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->base.port) == -1) { rc = dc_serial_close (device->base.port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;

View File

@ -40,11 +40,6 @@
#define MAXDELAY 16 #define MAXDELAY 16
#define INVALID 0xFFFFFFFF #define INVALID 0xFFFFFFFF
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define CMD_INIT 0xA8 #define CMD_INIT 0xA8
#define CMD_VERSION 0x84 #define CMD_VERSION 0x84
#define CMD_READ1 0xB1 #define CMD_READ1 0xB1
@ -59,7 +54,7 @@
typedef struct oceanic_atom2_device_t { typedef struct oceanic_atom2_device_t {
oceanic_common_device_t base; oceanic_common_device_t base;
serial_t *port; dc_serial_t *port;
unsigned int delay; unsigned int delay;
unsigned int bigpage; unsigned int bigpage;
unsigned char cache[256]; unsigned char cache[256];
@ -422,20 +417,21 @@ static const oceanic_common_layout_t aqualung_i450t_layout = {
static dc_status_t static dc_status_t
oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int crc_size) oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int crc_size)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
if (device->delay) { if (device->delay) {
serial_sleep (device->port, device->delay); dc_serial_sleep (device->port, device->delay);
} }
// Send the command to the dive computer. // Send the command to the dive computer.
int n = serial_write (device->port, command, csize); status = dc_serial_write (device->port, command, csize, NULL);
if (n != csize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Get the correct ACK byte. // Get the correct ACK byte.
@ -446,10 +442,10 @@ oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char comman
// Receive the response (ACK/NAK) of the dive computer. // Receive the response (ACK/NAK) of the dive computer.
unsigned char response = 0; unsigned char response = 0;
n = serial_read (device->port, &response, 1); status = dc_serial_read (device->port, &response, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the response of the dive computer. // Verify the response of the dive computer.
@ -460,10 +456,10 @@ oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char comman
if (asize) { if (asize) {
// Receive the answer of the dive computer. // Receive the answer of the dive computer.
int n = serial_read (device->port, answer, asize); status = dc_serial_read (device->port, answer, asize, NULL);
if (n != asize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the checksum of the answer. // Verify the checksum of the answer.
@ -509,8 +505,8 @@ oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char comm
device->delay++; device->delay++;
// Delay the next attempt. // Delay the next attempt.
serial_sleep (device->port, 100); dc_serial_sleep (device->port, 100);
serial_flush (device->port, SERIAL_QUEUE_INPUT); dc_serial_purge (device->port, DC_DIRECTION_INPUT);
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
@ -564,10 +560,9 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char
memset(device->cache, 0, sizeof(device->cache)); memset(device->cache, 0, sizeof(device->cache));
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
@ -578,29 +573,28 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char
} }
// Set the serial communication protocol (38400 8N1). // Set the serial communication protocol (38400 8N1).
rc = serial_configure (device->port, baudrate, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, baudrate, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (1000 ms). // Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->port, 1000) == -1) { status = dc_serial_set_timeout (device->port, 1000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Give the interface 100 ms to settle and draw power up. // Give the interface 100 ms to settle and draw power up.
serial_sleep (device->port, 100); dc_serial_sleep (device->port, 100);
// Set the DTR/RTS lines. // Set the DTR/RTS lines.
serial_set_dtr(device->port, 1); dc_serial_set_dtr(device->port, 1);
serial_set_rts(device->port, 1); dc_serial_set_rts(device->port, 1);
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
// Switch the device from surface mode into download mode. Before sending // Switch the device from surface mode into download mode. Before sending
// this command, the device needs to be in PC mode (automatically activated // this command, the device needs to be in PC mode (automatically activated
@ -662,7 +656,7 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -674,13 +668,15 @@ oceanic_atom2_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
oceanic_atom2_device_t *device = (oceanic_atom2_device_t*) abstract; oceanic_atom2_device_t *device = (oceanic_atom2_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Send the quit command. // Send the quit command.
oceanic_atom2_quit (device); oceanic_atom2_quit (device);
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;

View File

@ -36,17 +36,12 @@
#define MAXRETRIES 2 #define MAXRETRIES 2
#define MULTIPAGE 4 #define MULTIPAGE 4
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define ACK 0x5A #define ACK 0x5A
#define NAK 0xA5 #define NAK 0xA5
typedef struct oceanic_veo250_device_t { typedef struct oceanic_veo250_device_t {
oceanic_common_device_t base; oceanic_common_device_t base;
serial_t *port; dc_serial_t *port;
unsigned int last; unsigned int last;
} oceanic_veo250_device_t; } oceanic_veo250_device_t;
@ -91,27 +86,28 @@ static const oceanic_common_layout_t oceanic_veo250_layout = {
static dc_status_t static dc_status_t
oceanic_veo250_send (oceanic_veo250_device_t *device, const unsigned char command[], unsigned int csize) oceanic_veo250_send (oceanic_veo250_device_t *device, const unsigned char command[], unsigned int csize)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
// Discard garbage bytes. // Discard garbage bytes.
serial_flush (device->port, SERIAL_QUEUE_INPUT); dc_serial_purge (device->port, DC_DIRECTION_INPUT);
// Send the command to the dive computer. // Send the command to the dive computer.
int n = serial_write (device->port, command, csize); status = dc_serial_write (device->port, command, csize, NULL);
if (n != csize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Receive the response (ACK/NAK) of the dive computer. // Receive the response (ACK/NAK) of the dive computer.
unsigned char response = NAK; unsigned char response = NAK;
n = serial_read (device->port, &response, 1); status = dc_serial_read (device->port, &response, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the response of the dive computer. // Verify the response of the dive computer.
@ -127,6 +123,7 @@ oceanic_veo250_send (oceanic_veo250_device_t *device, const unsigned char comman
static dc_status_t static dc_status_t
oceanic_veo250_transfer (oceanic_veo250_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) oceanic_veo250_transfer (oceanic_veo250_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
// Send the command to the device. If the device responds with an // Send the command to the device. If the device responds with an
@ -146,14 +143,14 @@ oceanic_veo250_transfer (oceanic_veo250_device_t *device, const unsigned char co
return rc; return rc;
// Delay the next attempt. // Delay the next attempt.
serial_sleep (device->port, 100); dc_serial_sleep (device->port, 100);
} }
// Receive the answer of the dive computer. // Receive the answer of the dive computer.
int n = serial_read (device->port, answer, asize); status = dc_serial_read (device->port, answer, asize, NULL);
if (n != asize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the last byte of the answer. // Verify the last byte of the answer.
@ -169,24 +166,26 @@ oceanic_veo250_transfer (oceanic_veo250_device_t *device, const unsigned char co
static dc_status_t static dc_status_t
oceanic_veo250_init (oceanic_veo250_device_t *device) oceanic_veo250_init (oceanic_veo250_device_t *device)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
// Send the command to the dive computer. // Send the command to the dive computer.
unsigned char command[2] = {0x55, 0x00}; unsigned char command[2] = {0x55, 0x00};
int n = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (n != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Receive the answer of the dive computer. // Receive the answer of the dive computer.
size_t n = 0;
unsigned char answer[13] = {0}; unsigned char answer[13] = {0};
n = serial_read (device->port, answer, sizeof (answer)); status = dc_serial_read (device->port, answer, sizeof (answer), &n);
if (n != sizeof (answer)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
if (n == 0) if (n == 0)
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
return EXITCODE (n); return status;
} }
// Verify the answer. // Verify the answer.
@ -205,14 +204,15 @@ oceanic_veo250_init (oceanic_veo250_device_t *device)
static dc_status_t static dc_status_t
oceanic_veo250_quit (oceanic_veo250_device_t *device) oceanic_veo250_quit (oceanic_veo250_device_t *device)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
// Send the command to the dive computer. // Send the command to the dive computer.
unsigned char command[2] = {0x98, 0x00}; unsigned char command[2] = {0x98, 0x00};
int n = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (n != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
@ -247,41 +247,45 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char
device->last = 0; device->last = 0;
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (9600 8N1). // Set the serial communication protocol (9600 8N1).
rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (3000 ms). // Set the timeout for receiving data (3000 ms).
if (serial_set_timeout (device->port, 3000) == -1) { status = dc_serial_set_timeout (device->port, 3000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the DTR and RTS lines. // Set the DTR line.
if (serial_set_dtr (device->port, 1) == -1 || status = dc_serial_set_dtr (device->port, 1);
serial_set_rts (device->port, 1) == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the DTR/RTS line."); ERROR (context, "Failed to set the DTR line.");
status = DC_STATUS_IO; goto error_close;
}
// Set the RTS line.
status = dc_serial_set_rts (device->port, 1);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the RTS line.");
goto error_close; goto error_close;
} }
// Give the interface 100 ms to settle and draw power up. // Give the interface 100 ms to settle and draw power up.
serial_sleep (device->port, 100); dc_serial_sleep (device->port, 100);
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
// Initialize the data cable (PPS mode). // Initialize the data cable (PPS mode).
status = oceanic_veo250_init (device); status = oceanic_veo250_init (device);
@ -290,7 +294,7 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char
} }
// Delay the sending of the version command. // Delay the sending of the version command.
serial_sleep (device->port, 100); dc_serial_sleep (device->port, 100);
// Switch the device from surface mode into download mode. Before sending // Switch the device from surface mode into download mode. Before sending
// this command, the device needs to be in PC mode (manually activated by // this command, the device needs to be in PC mode (manually activated by
@ -305,7 +309,7 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -317,13 +321,15 @@ oceanic_veo250_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
oceanic_veo250_device_t *device = (oceanic_veo250_device_t*) abstract; oceanic_veo250_device_t *device = (oceanic_veo250_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Switch the device back to surface mode. // Switch the device back to surface mode.
oceanic_veo250_quit (device); oceanic_veo250_quit (device);
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;

View File

@ -36,18 +36,13 @@
#define MAXRETRIES 2 #define MAXRETRIES 2
#define MULTIPAGE 4 #define MULTIPAGE 4
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define ACK 0x5A #define ACK 0x5A
#define NAK 0xA5 #define NAK 0xA5
#define END 0x51 #define END 0x51
typedef struct oceanic_vtpro_device_t { typedef struct oceanic_vtpro_device_t {
oceanic_common_device_t base; oceanic_common_device_t base;
serial_t *port; dc_serial_t *port;
} oceanic_vtpro_device_t; } oceanic_vtpro_device_t;
static dc_status_t oceanic_vtpro_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); static dc_status_t oceanic_vtpro_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size);
@ -107,24 +102,25 @@ static const oceanic_common_layout_t oceanic_wisdom_layout = {
static dc_status_t static dc_status_t
oceanic_vtpro_send (oceanic_vtpro_device_t *device, const unsigned char command[], unsigned int csize) oceanic_vtpro_send (oceanic_vtpro_device_t *device, const unsigned char command[], unsigned int csize)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
// Send the command to the dive computer. // Send the command to the dive computer.
int n = serial_write (device->port, command, csize); status = dc_serial_write (device->port, command, csize, NULL);
if (n != csize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Receive the response (ACK/NAK) of the dive computer. // Receive the response (ACK/NAK) of the dive computer.
unsigned char response = NAK; unsigned char response = NAK;
n = serial_read (device->port, &response, 1); status = dc_serial_read (device->port, &response, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the response of the dive computer. // Verify the response of the dive computer.
@ -140,6 +136,7 @@ oceanic_vtpro_send (oceanic_vtpro_device_t *device, const unsigned char command[
static dc_status_t static dc_status_t
oceanic_vtpro_transfer (oceanic_vtpro_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) oceanic_vtpro_transfer (oceanic_vtpro_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
// Send the command to the device. If the device responds with an // Send the command to the device. If the device responds with an
@ -160,10 +157,10 @@ oceanic_vtpro_transfer (oceanic_vtpro_device_t *device, const unsigned char comm
} }
// Receive the answer of the dive computer. // Receive the answer of the dive computer.
int n = serial_read (device->port, answer, asize); status = dc_serial_read (device->port, answer, asize, NULL);
if (n != asize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
@ -173,22 +170,23 @@ oceanic_vtpro_transfer (oceanic_vtpro_device_t *device, const unsigned char comm
static dc_status_t static dc_status_t
oceanic_vtpro_init (oceanic_vtpro_device_t *device) oceanic_vtpro_init (oceanic_vtpro_device_t *device)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
// Send the command to the dive computer. // Send the command to the dive computer.
unsigned char command[2] = {0xAA, 0x00}; unsigned char command[2] = {0xAA, 0x00};
int n = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (n != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Receive the answer of the dive computer. // Receive the answer of the dive computer.
unsigned char answer[13] = {0}; unsigned char answer[13] = {0};
n = serial_read (device->port, answer, sizeof (answer)); status = dc_serial_read (device->port, answer, sizeof (answer), NULL);
if (n != sizeof (answer)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the answer. // Verify the answer.
@ -236,9 +234,9 @@ oceanic_vtpro_calibrate (oceanic_vtpro_device_t *device)
// device needs approximately 6 seconds to respond. // device needs approximately 6 seconds to respond.
unsigned char answer[2] = {0}; unsigned char answer[2] = {0};
unsigned char command[2] = {0x18, 0x00}; unsigned char command[2] = {0x18, 0x00};
serial_set_timeout (device->port, 9000); dc_serial_set_timeout (device->port, 9000);
dc_status_t rc = oceanic_vtpro_transfer (device, command, sizeof (command), answer, sizeof (answer)); dc_status_t rc = oceanic_vtpro_transfer (device, command, sizeof (command), answer, sizeof (answer));
serial_set_timeout (device->port, 3000); dc_serial_set_timeout (device->port, 3000);
if (rc != DC_STATUS_SUCCESS) if (rc != DC_STATUS_SUCCESS)
return rc; return rc;
@ -278,41 +276,45 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char
device->port = NULL; device->port = NULL;
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (9600 8N1). // Set the serial communication protocol (9600 8N1).
rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (3000 ms). // Set the timeout for receiving data (3000 ms).
if (serial_set_timeout (device->port, 3000) == -1) { status = dc_serial_set_timeout (device->port, 3000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the DTR and RTS lines. // Set the DTR line.
if (serial_set_dtr (device->port, 1) == -1 || status = dc_serial_set_dtr (device->port, 1);
serial_set_rts (device->port, 1) == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the DTR/RTS line."); ERROR (context, "Failed to set the DTR line.");
status = DC_STATUS_IO; goto error_close;
}
// Set the RTS line.
status = dc_serial_set_rts (device->port, 1);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the RTS line.");
goto error_close; goto error_close;
} }
// Give the interface 100 ms to settle and draw power up. // Give the interface 100 ms to settle and draw power up.
serial_sleep (device->port, 100); dc_serial_sleep (device->port, 100);
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
// Initialize the data cable (MOD mode). // Initialize the data cable (MOD mode).
status = oceanic_vtpro_init (device); status = oceanic_vtpro_init (device);
@ -348,7 +350,7 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -360,13 +362,15 @@ oceanic_vtpro_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t*) abstract; oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Switch the device back to surface mode. // Switch the device back to surface mode.
oceanic_vtpro_quit (device); oceanic_vtpro_quit (device);
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;

View File

@ -32,17 +32,12 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &reefnet_sensus_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &reefnet_sensus_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define SZ_MEMORY 32768 #define SZ_MEMORY 32768
#define SZ_HANDSHAKE 10 #define SZ_HANDSHAKE 10
typedef struct reefnet_sensus_device_t { typedef struct reefnet_sensus_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
unsigned char handshake[SZ_HANDSHAKE]; unsigned char handshake[SZ_HANDSHAKE];
unsigned int waiting; unsigned int waiting;
unsigned int timestamp; unsigned int timestamp;
@ -70,14 +65,15 @@ static const dc_device_vtable_t reefnet_sensus_device_vtable = {
static dc_status_t static dc_status_t
reefnet_sensus_cancel (reefnet_sensus_device_t *device) reefnet_sensus_cancel (reefnet_sensus_device_t *device)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
// Send the command to the device. // Send the command to the device.
unsigned char command = 0x00; unsigned char command = 0x00;
int n = serial_write (device->port, &command, 1); status = dc_serial_write (device->port, &command, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// The device leaves the waiting state. // The device leaves the waiting state.
@ -112,37 +108,35 @@ reefnet_sensus_device_open (dc_device_t **out, dc_context_t *context, const char
memset (device->handshake, 0, sizeof (device->handshake)); memset (device->handshake, 0, sizeof (device->handshake));
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (19200 8N1). // Set the serial communication protocol (19200 8N1).
rc = serial_configure (device->port, 19200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 19200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (3000 ms). // Set the timeout for receiving data (3000 ms).
if (serial_set_timeout (device->port, 3000) == -1) { status = dc_serial_set_timeout (device->port, 3000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
*out = (dc_device_t*) device; *out = (dc_device_t*) device;
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -154,15 +148,18 @@ reefnet_sensus_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
reefnet_sensus_device_t *device = (reefnet_sensus_device_t*) abstract; reefnet_sensus_device_t *device = (reefnet_sensus_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Safely close the connection if the last handshake was // Safely close the connection if the last handshake was
// successful, but no data transfer was ever initiated. // successful, but no data transfer was ever initiated.
if (device->waiting) if (device->waiting)
reefnet_sensus_cancel (device); reefnet_sensus_cancel (device);
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -208,22 +205,23 @@ reefnet_sensus_device_set_fingerprint (dc_device_t *abstract, const unsigned cha
static dc_status_t static dc_status_t
reefnet_sensus_handshake (reefnet_sensus_device_t *device) reefnet_sensus_handshake (reefnet_sensus_device_t *device)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
// Send the command to the device. // Send the command to the device.
unsigned char command = 0x0A; unsigned char command = 0x0A;
int n = serial_write (device->port, &command, 1); status = dc_serial_write (device->port, &command, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Receive the answer from the device. // Receive the answer from the device.
unsigned char handshake[SZ_HANDSHAKE + 2] = {0}; unsigned char handshake[SZ_HANDSHAKE + 2] = {0};
n = serial_read (device->port, handshake, sizeof (handshake)); status = dc_serial_read (device->port, handshake, sizeof (handshake), NULL);
if (n != sizeof (handshake)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the handshake."); ERROR (abstract->context, "Failed to receive the handshake.");
return EXITCODE (n); return status;
} }
// Verify the header of the packet. // Verify the header of the packet.
@ -264,7 +262,7 @@ reefnet_sensus_handshake (reefnet_sensus_device_t *device)
// Wait at least 10 ms to ensures the data line is // Wait at least 10 ms to ensures the data line is
// clear before transmission from the host begins. // clear before transmission from the host begins.
serial_sleep (device->port, 10); dc_serial_sleep (device->port, 10);
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
} }
@ -273,6 +271,7 @@ reefnet_sensus_handshake (reefnet_sensus_device_t *device)
static dc_status_t static dc_status_t
reefnet_sensus_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) reefnet_sensus_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
reefnet_sensus_device_t *device = (reefnet_sensus_device_t*) abstract; reefnet_sensus_device_t *device = (reefnet_sensus_device_t*) abstract;
// Erase the current contents of the buffer and // Erase the current contents of the buffer and
@ -294,10 +293,10 @@ reefnet_sensus_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
// Send the command to the device. // Send the command to the device.
unsigned char command = 0x40; unsigned char command = 0x40;
int n = serial_write (device->port, &command, 1); status = dc_serial_write (device->port, &command, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// The device leaves the waiting state. // The device leaves the waiting state.
@ -311,10 +310,10 @@ reefnet_sensus_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
if (len > 128) if (len > 128)
len = 128; len = 128;
n = serial_read (device->port, answer + nbytes, len); status = dc_serial_read (device->port, answer + nbytes, len, NULL);
if (n != len) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Update and emit a progress event. // Update and emit a progress event.

View File

@ -32,17 +32,12 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &reefnet_sensuspro_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &reefnet_sensuspro_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define SZ_MEMORY 56320 #define SZ_MEMORY 56320
#define SZ_HANDSHAKE 10 #define SZ_HANDSHAKE 10
typedef struct reefnet_sensuspro_device_t { typedef struct reefnet_sensuspro_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
unsigned char handshake[SZ_HANDSHAKE]; unsigned char handshake[SZ_HANDSHAKE];
unsigned int timestamp; unsigned int timestamp;
unsigned int devtime; unsigned int devtime;
@ -90,37 +85,35 @@ reefnet_sensuspro_device_open (dc_device_t **out, dc_context_t *context, const c
memset (device->handshake, 0, sizeof (device->handshake)); memset (device->handshake, 0, sizeof (device->handshake));
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (19200 8N1). // Set the serial communication protocol (19200 8N1).
rc = serial_configure (device->port, 19200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 19200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (3000ms). // Set the timeout for receiving data (3000ms).
if (serial_set_timeout (device->port, 3000) == -1) { status = dc_serial_set_timeout (device->port, 3000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
*out = (dc_device_t*) device; *out = (dc_device_t*) device;
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -132,10 +125,12 @@ reefnet_sensuspro_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
reefnet_sensuspro_device_t *device = (reefnet_sensuspro_device_t*) abstract; reefnet_sensuspro_device_t *device = (reefnet_sensuspro_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -181,21 +176,22 @@ reefnet_sensuspro_device_set_fingerprint (dc_device_t *abstract, const unsigned
static dc_status_t static dc_status_t
reefnet_sensuspro_handshake (reefnet_sensuspro_device_t *device) reefnet_sensuspro_handshake (reefnet_sensuspro_device_t *device)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
// Assert a break condition. // Assert a break condition.
serial_set_break (device->port, 1); dc_serial_set_break (device->port, 1);
// Receive the handshake from the dive computer. // Receive the handshake from the dive computer.
unsigned char handshake[SZ_HANDSHAKE + 2] = {0}; unsigned char handshake[SZ_HANDSHAKE + 2] = {0};
int rc = serial_read (device->port, handshake, sizeof (handshake)); status = dc_serial_read (device->port, handshake, sizeof (handshake), NULL);
if (rc != sizeof (handshake)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the handshake."); ERROR (abstract->context, "Failed to receive the handshake.");
return EXITCODE (rc); return status;
} }
// Clear the break condition again. // Clear the break condition again.
serial_set_break (device->port, 0); dc_serial_set_break (device->port, 0);
// Verify the checksum of the handshake packet. // Verify the checksum of the handshake packet.
unsigned short crc = array_uint16_le (handshake + SZ_HANDSHAKE); unsigned short crc = array_uint16_le (handshake + SZ_HANDSHAKE);
@ -231,7 +227,7 @@ reefnet_sensuspro_handshake (reefnet_sensuspro_device_t *device)
vendor.size = sizeof (device->handshake); vendor.size = sizeof (device->handshake);
device_event_emit (abstract, DC_EVENT_VENDOR, &vendor); device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
serial_sleep (device->port, 10); dc_serial_sleep (device->port, 10);
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
} }
@ -240,6 +236,7 @@ reefnet_sensuspro_handshake (reefnet_sensuspro_device_t *device)
static dc_status_t static dc_status_t
reefnet_sensuspro_send (reefnet_sensuspro_device_t *device, unsigned char command) reefnet_sensuspro_send (reefnet_sensuspro_device_t *device, unsigned char command)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
// Wake-up the device. // Wake-up the device.
@ -248,10 +245,10 @@ reefnet_sensuspro_send (reefnet_sensuspro_device_t *device, unsigned char comman
return rc; return rc;
// Send the instruction code to the device. // Send the instruction code to the device.
int n = serial_write (device->port, &command, 1); status = dc_serial_write (device->port, &command, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
@ -261,6 +258,7 @@ reefnet_sensuspro_send (reefnet_sensuspro_device_t *device, unsigned char comman
static dc_status_t static dc_status_t
reefnet_sensuspro_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) reefnet_sensuspro_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
reefnet_sensuspro_device_t *device = (reefnet_sensuspro_device_t*) abstract; reefnet_sensuspro_device_t *device = (reefnet_sensuspro_device_t*) abstract;
// Erase the current contents of the buffer and // Erase the current contents of the buffer and
@ -287,10 +285,10 @@ reefnet_sensuspro_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
if (len > 256) if (len > 256)
len = 256; len = 256;
int n = serial_read (device->port, answer + nbytes, len); status = dc_serial_read (device->port, answer + nbytes, len, NULL);
if (n != len) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Update and emit a progress event. // Update and emit a progress event.
@ -338,6 +336,7 @@ reefnet_sensuspro_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
dc_status_t dc_status_t
reefnet_sensuspro_device_write_interval (dc_device_t *abstract, unsigned char interval) reefnet_sensuspro_device_write_interval (dc_device_t *abstract, unsigned char interval)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
reefnet_sensuspro_device_t *device = (reefnet_sensuspro_device_t*) abstract; reefnet_sensuspro_device_t *device = (reefnet_sensuspro_device_t*) abstract;
if (!ISINSTANCE (abstract)) if (!ISINSTANCE (abstract))
@ -351,12 +350,12 @@ reefnet_sensuspro_device_write_interval (dc_device_t *abstract, unsigned char in
if (rc != DC_STATUS_SUCCESS) if (rc != DC_STATUS_SUCCESS)
return rc; return rc;
serial_sleep (device->port, 10); dc_serial_sleep (device->port, 10);
int n = serial_write (device->port, &interval, 1); status = dc_serial_write (device->port, &interval, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the data packet."); ERROR (abstract->context, "Failed to send the data packet.");
return EXITCODE (n); return status;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;

View File

@ -33,11 +33,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &reefnet_sensusultra_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &reefnet_sensusultra_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define SZ_PACKET 512 #define SZ_PACKET 512
#define SZ_MEMORY 2080768 #define SZ_MEMORY 2080768
#define SZ_USER 16384 #define SZ_USER 16384
@ -51,7 +46,7 @@
typedef struct reefnet_sensusultra_device_t { typedef struct reefnet_sensusultra_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
unsigned char handshake[SZ_HANDSHAKE]; unsigned char handshake[SZ_HANDSHAKE];
unsigned int timestamp; unsigned int timestamp;
unsigned int devtime; unsigned int devtime;
@ -99,37 +94,35 @@ reefnet_sensusultra_device_open (dc_device_t **out, dc_context_t *context, const
memset (device->handshake, 0, sizeof (device->handshake)); memset (device->handshake, 0, sizeof (device->handshake));
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (115200 8N1). // Set the serial communication protocol (115200 8N1).
rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (3000ms). // Set the timeout for receiving data (3000ms).
if (serial_set_timeout (device->port, 3000) == -1) { status = dc_serial_set_timeout (device->port, 3000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
*out = (dc_device_t*) device; *out = (dc_device_t*) device;
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -141,10 +134,12 @@ reefnet_sensusultra_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
reefnet_sensusultra_device_t *device = (reefnet_sensusultra_device_t*) abstract; reefnet_sensusultra_device_t *device = (reefnet_sensusultra_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -190,14 +185,15 @@ reefnet_sensusultra_device_set_fingerprint (dc_device_t *abstract, const unsigne
static dc_status_t static dc_status_t
reefnet_sensusultra_send_uchar (reefnet_sensusultra_device_t *device, unsigned char value) reefnet_sensusultra_send_uchar (reefnet_sensusultra_device_t *device, unsigned char value)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
// Wait for the prompt byte. // Wait for the prompt byte.
unsigned char prompt = 0; unsigned char prompt = 0;
int rc = serial_read (device->port, &prompt, 1); status = dc_serial_read (device->port, &prompt, 1, NULL);
if (rc != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the prompt byte"); ERROR (abstract->context, "Failed to receive the prompt byte");
return EXITCODE (rc); return status;
} }
// Verify the prompt byte. // Verify the prompt byte.
@ -207,10 +203,10 @@ reefnet_sensusultra_send_uchar (reefnet_sensusultra_device_t *device, unsigned c
} }
// Send the value to the device. // Send the value to the device.
rc = serial_write (device->port, &value, 1); status = dc_serial_write (device->port, &value, 1, NULL);
if (rc != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the value."); ERROR (abstract->context, "Failed to send the value.");
return EXITCODE (rc); return status;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
@ -239,18 +235,19 @@ reefnet_sensusultra_send_ushort (reefnet_sensusultra_device_t *device, unsigned
static dc_status_t static dc_status_t
reefnet_sensusultra_packet (reefnet_sensusultra_device_t *device, unsigned char *data, unsigned int size, unsigned int header) reefnet_sensusultra_packet (reefnet_sensusultra_device_t *device, unsigned char *data, unsigned int size, unsigned int header)
{ {
assert (size >= header + 2); dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
assert (size >= header + 2);
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
// Receive the data packet. // Receive the data packet.
int rc = serial_read (device->port, data, size); status = dc_serial_read (device->port, data, size, NULL);
if (rc != size) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the packet."); ERROR (abstract->context, "Failed to receive the packet.");
return EXITCODE (rc); return status;
} }
// Verify the checksum of the packet. // Verify the checksum of the packet.
@ -349,7 +346,7 @@ static dc_status_t
reefnet_sensusultra_send (reefnet_sensusultra_device_t *device, unsigned short command) reefnet_sensusultra_send (reefnet_sensusultra_device_t *device, unsigned short command)
{ {
// Flush the input and output buffers. // Flush the input and output buffers.
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
// Wake-up the device and send the instruction code. // Wake-up the device and send the instruction code.
unsigned int nretries = 0; unsigned int nretries = 0;
@ -369,8 +366,8 @@ reefnet_sensusultra_send (reefnet_sensusultra_device_t *device, unsigned short c
// not accidentally buffered by the host and (mis)interpreted as part // not accidentally buffered by the host and (mis)interpreted as part
// of the next packet. // of the next packet.
serial_sleep (device->port, 250); dc_serial_sleep (device->port, 250);
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;

View File

@ -19,101 +19,303 @@
* MA 02110-1301 USA * MA 02110-1301 USA
*/ */
#ifndef SERIAL_H #ifndef DC_SERIAL_H
#define SERIAL_H #define DC_SERIAL_H
#include <libdivecomputer/common.h>
#include <libdivecomputer/context.h> #include <libdivecomputer/context.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
typedef struct serial_t serial_t; /**
* Opaque object representing a serial connection.
*/
typedef struct dc_serial_t dc_serial_t;
typedef enum serial_parity_t { /**
SERIAL_PARITY_NONE, * The parity checking scheme.
SERIAL_PARITY_EVEN, */
SERIAL_PARITY_ODD typedef enum dc_parity_t {
} serial_parity_t; DC_PARITY_NONE, /**< No parity */
DC_PARITY_ODD, /**< Odd parity */
DC_PARITY_EVEN, /**< Even parity */
DC_PARITY_MARK, /**< Mark parity (always 1) */
DC_PARITY_SPACE /**< Space parity (alwasy 0) */
} dc_parity_t;
typedef enum serial_flowcontrol_t { /**
SERIAL_FLOWCONTROL_NONE, * The number of stop bits.
SERIAL_FLOWCONTROL_HARDWARE, */
SERIAL_FLOWCONTROL_SOFTWARE typedef enum dc_stopbits_t {
} serial_flowcontrol_t; DC_STOPBITS_ONE, /**< 1 stop bit */
DC_STOPBITS_ONEPOINTFIVE, /**< 1.5 stop bits*/
DC_STOPBITS_TWO /**< 2 stop bits */
} dc_stopbits_t;
typedef enum serial_queue_t { /**
SERIAL_QUEUE_INPUT = 0x01, * The flow control.
SERIAL_QUEUE_OUTPUT = 0x02, */
SERIAL_QUEUE_BOTH = SERIAL_QUEUE_INPUT | SERIAL_QUEUE_OUTPUT typedef enum dc_flowcontrol_t {
} serial_queue_t; DC_FLOWCONTROL_NONE, /**< No flow control */
DC_FLOWCONTROL_HARDWARE, /**< Hardware (RTS/CTS) flow control */
DC_FLOWCONTROL_SOFTWARE /**< Software (XON/XOFF) flow control */
} dc_flowcontrol_t;
typedef enum serial_line_t { /**
SERIAL_LINE_DCD, // Data carrier detect * The direction of the data transmission.
SERIAL_LINE_CTS, // Clear to send */
SERIAL_LINE_DSR, // Data set ready typedef enum dc_direction_t {
SERIAL_LINE_RNG, // Ring indicator DC_DIRECTION_INPUT = 0x01, /**< Input direction */
} serial_line_t; DC_DIRECTION_OUTPUT = 0x02, /**< Output direction */
DC_DIRECTION_ALL = DC_DIRECTION_INPUT | DC_DIRECTION_OUTPUT /**< All directions */
} dc_direction_t;
typedef void (*serial_callback_t) (const char *name, void *userdata); /**
* The serial line signals.
*/
typedef enum dc_line_t {
DC_LINE_DCD = 0x01, /**< Data carrier detect */
DC_LINE_CTS = 0x02, /**< Clear to send */
DC_LINE_DSR = 0x04, /**< Data set ready */
DC_LINE_RNG = 0x08, /**< Ring indicator */
} dc_line_t;
int serial_enumerate (serial_callback_t callback, void *userdata); /**
* Serial enumeration callback.
*
* @param[in] name The name of the device node.
* @param[in] userdata The user data pointer.
*/
typedef void (*dc_serial_callback_t) (const char *name, void *userdata);
int serial_open (serial_t **device, dc_context_t *context, const char* name); /**
* Enumerate the serial ports.
*
* @param[in] callback The callback function to call.
* @param[in] userdata User data to pass to the callback function.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_serial_enumerate (dc_serial_callback_t callback, void *userdata);
int serial_close (serial_t *device); /**
* Open a serial connection.
*
* @param[out] serial A location to store the serial connection.
* @param[in] context A valid context object.
* @param[in] name The name of the device node.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_serial_open (dc_serial_t **serial, dc_context_t *context, const char *name);
int serial_configure (serial_t *device, int baudrate, int databits, int parity, int stopbits, int flowcontrol); /**
* Close the serial connection and free all resources.
*
* @param[in] serial A valid serial connection.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_serial_close (dc_serial_t *serial);
// /**
// Available read modes: * Configure the serial line settings of the connection.
// *
// * Blocking (timeout < 0): * @param[in] serial A valid serial connection.
// * @param[in] baudrate The baud rate setting.
// The read function is blocked until all the requested bytes have * @param[in] databits The number of data bits.
// been received. If the requested number of bytes does not arrive, * @param[in] parity The parity setting.
// the function will block forever. * @param[in] stopbits The number of stop bits.
// * @param[in] flowcontrol The flow control setting.
// * Non-blocking (timeout == 0): * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
// * on failure.
// The read function returns immediately with the bytes that have already */
// been received, even if no bytes have been received. dc_status_t
// dc_serial_configure (dc_serial_t *serial, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol);
// * Timeout (timeout > 0):
//
// The read function is blocked until all the requested bytes have
// been received. If the requested number of bytes does not arrive
// within the specified amount of time, the function will return
// with the bytes that have already been received.
//
int serial_set_timeout (serial_t *device, long timeout /* milliseconds */); /**
* Set the read timeout.
*
* There are three distinct modes available:
*
* 1. Blocking (timeout < 0):
*
* The read operation is blocked until all the requested bytes have
* been received. If the requested number of bytes does not arrive,
* the operation will block forever.
*
* 2. Non-blocking (timeout == 0):
*
* The read operation returns immediately with the bytes that have
* already been received, even if no bytes have been received.
*
* 3. Timeout (timeout > 0):
*
* The read operation is blocked until all the requested bytes have
* been received. If the requested number of bytes does not arrive
* within the specified amount of time, the operation will return
* with the bytes that have already been received.
*
* @param[in] serial A valid serial connection.
* @param[in] timeout The timeout in milliseconds.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_serial_set_timeout (dc_serial_t *serial, int timeout);
int serial_set_queue_size (serial_t *device, unsigned int input, unsigned int output); /**
* Set the state of the half duplex emulation.
*
* @param[in] serial A valid serial connection.
* @param[in] value The half duplex state.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_serial_set_halfduplex (dc_serial_t *serial, unsigned int value);
int serial_set_halfduplex (serial_t *device, int value); /**
* Set the receive latency.
*
* The effect of this setting is highly platform and driver specific. On
* Windows it does nothing at all, on Linux it controls the low latency
* flag (e.g. only zero vs non-zero latency), and on Mac OS X it sets
* the receive latency as requested.
*
* @param[in] serial A valid serial connection.
* @param[in] value The latency in milliseconds.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_serial_set_latency (dc_serial_t *serial, unsigned int value);
int serial_set_latency (serial_t *device, unsigned int milliseconds); /**
* Read data from the serial connection.
*
* @param[in] serial A valid serial connection.
* @param[out] data The memory buffer to read the data into.
* @param[in] size The number of bytes to read.
* @param[out] actual An (optional) location to store the actual
* number of bytes transferred.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_serial_read (dc_serial_t *serial, void *data, size_t size, size_t *actual);
int serial_read (serial_t *device, void* data, unsigned int size); /**
int serial_write (serial_t *device, const void* data, unsigned int size); * Write data to the serial connection.
*
* @param[in] serial A valid serial connection.
* @param[in] data The memory buffer to write the data from.
* @param[in] size The number of bytes to write.
* @param[out] actual An (optional) location to store the actual
* number of bytes transferred.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_serial_write (dc_serial_t *serial, const void *data, size_t size, size_t *actual);
int serial_flush (serial_t *device, int queue); /**
* Flush the internal output buffer and wait until the data has been
* transmitted.
*
* @param[in] serial A valid serial connection.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_serial_flush (dc_serial_t *serial);
int serial_send_break (serial_t *device); /**
* Discards all data from the internal buffers.
*
* @param[in] serial A valid serial connection.
* @param[in] direction The direction of the buffer(s).
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_serial_purge (dc_serial_t *serial, dc_direction_t direction);
int serial_set_break (serial_t *device, int level); /**
int serial_set_dtr (serial_t *device, int level); * Set the state of the break condition.
int serial_set_rts (serial_t *device, int level); *
* @param[in] serial A valid serial connection.
* @param[in] value The break condition state.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_serial_set_break (dc_serial_t *serial, unsigned int value);
int serial_get_received (serial_t *device); /**
int serial_get_transmitted (serial_t *device); * Set the state of the DTR line.
*
* @param[in] serial A valid serial connection.
* @param[in] value The DTR line state.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_serial_set_dtr (dc_serial_t *serial, unsigned int value);
int serial_get_line (serial_t *device, int line); /**
* Set the state of the RTS line.
*
* @param[in] serial A valid serial connection.
* @param[in] value The RTS line state.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_serial_set_rts (dc_serial_t *serial, unsigned int value);
int serial_sleep (serial_t *device, unsigned long timeout /* milliseconds */); /**
* Query the number of available bytes in the input buffer.
*
* @param[in] serial A valid serial connection.
* @param[out] value A location to store the number of bytes in the
* input buffer.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_serial_get_available (dc_serial_t *serial, size_t *value);
/**
* Query the state of the line signals.
*
* @param[in] serial A valid serial connection.
* @param[out] value A location to store the bitmap with the state of
* the line signals.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_serial_get_lines (dc_serial_t *serial, unsigned int *value);
/**
* Suspend execution of the current thread for the specified amount of
* time.
*
* @param[in] serial A valid serial connection.
* @param[in] milliseconds The number of milliseconds to sleep.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_serial_sleep (dc_serial_t *serial, unsigned int milliseconds);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif /* SERIAL_H */ #endif /* DC_SERIAL_H */

View File

@ -54,16 +54,17 @@
#endif #endif
#include "serial.h" #include "serial.h"
#include "common-private.h"
#include "context-private.h" #include "context-private.h"
struct serial_t { struct dc_serial_t {
/* Library context. */ /* Library context. */
dc_context_t *context; dc_context_t *context;
/* /*
* The file descriptor corresponding to the serial port. * The file descriptor corresponding to the serial port.
*/ */
int fd; int fd;
long timeout; int timeout;
/* /*
* Serial port settings are saved into this variable immediately * Serial port settings are saved into this variable immediately
* after the port is opened. These settings are restored when the * after the port is opened. These settings are restored when the
@ -77,8 +78,8 @@ struct serial_t {
}; };
int dc_status_t
serial_enumerate (serial_callback_t callback, void *userdata) dc_serial_enumerate (dc_serial_callback_t callback, void *userdata)
{ {
DIR *dp = NULL; DIR *dp = NULL;
struct dirent *ep = NULL; struct dirent *ep = NULL;
@ -97,7 +98,7 @@ serial_enumerate (serial_callback_t callback, void *userdata)
dp = opendir (dirname); dp = opendir (dirname);
if (dp == NULL) { if (dp == NULL) {
return -1; return DC_STATUS_IO;
} }
while ((ep = readdir (dp)) != NULL) { while ((ep = readdir (dp)) != NULL) {
@ -107,7 +108,7 @@ serial_enumerate (serial_callback_t callback, void *userdata)
int n = snprintf (filename, sizeof (filename), "%s/%s", dirname, ep->d_name); int n = snprintf (filename, sizeof (filename), "%s/%s", dirname, ep->d_name);
if (n >= sizeof (filename)) { if (n >= sizeof (filename)) {
closedir (dp); closedir (dp);
return -1; return DC_STATUS_NOMEMORY;
} }
callback (filename, userdata); callback (filename, userdata);
@ -118,27 +119,24 @@ serial_enumerate (serial_callback_t callback, void *userdata)
closedir (dp); closedir (dp);
return 0; return DC_STATUS_SUCCESS;
} }
dc_status_t
// dc_serial_open (dc_serial_t **out, dc_context_t *context, const char *name)
// Open the serial port.
//
int
serial_open (serial_t **out, dc_context_t *context, const char* name)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
if (out == NULL) if (out == NULL)
return -1; // EINVAL (Invalid argument) return DC_STATUS_INVALIDARGS;
INFO (context, "Open: name=%s", name ? name : ""); INFO (context, "Open: name=%s", name ? name : "");
// Allocate memory. // Allocate memory.
serial_t *device = (serial_t *) malloc (sizeof (serial_t)); dc_serial_t *device = (dc_serial_t *) malloc (sizeof (dc_serial_t));
if (device == NULL) { if (device == NULL) {
SYSERROR (context, ENOMEM); SYSERROR (context, ENOMEM);
return -1; // ENOMEM (Not enough space) return DC_STATUS_NOMEMORY;
} }
// Library context. // Library context.
@ -157,6 +155,7 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
device->fd = open (name, O_RDWR | O_NOCTTY | O_NONBLOCK); device->fd = open (name, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (device->fd == -1) { if (device->fd == -1) {
SYSERROR (context, errno); SYSERROR (context, errno);
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
@ -164,6 +163,7 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
// Enable exclusive access mode. // Enable exclusive access mode.
if (ioctl (device->fd, TIOCEXCL, NULL) != 0) { if (ioctl (device->fd, TIOCEXCL, NULL) != 0) {
SYSERROR (context, errno); SYSERROR (context, errno);
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
#endif #endif
@ -174,36 +174,33 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
// file descriptor represents a terminal device. // file descriptor represents a terminal device.
if (tcgetattr (device->fd, &device->tty) != 0) { if (tcgetattr (device->fd, &device->tty) != 0) {
SYSERROR (context, errno); SYSERROR (context, errno);
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
*out = device; *out = device;
return 0; return DC_STATUS_SUCCESS;
error_close: error_close:
close (device->fd); close (device->fd);
error_free: error_free:
free (device); free (device);
return -1; return status;
} }
// dc_status_t
// Close the serial port. dc_serial_close (dc_serial_t *device)
//
int
serial_close (serial_t *device)
{ {
int errcode = 0; dc_status_t status = DC_STATUS_SUCCESS;
if (device == NULL) if (device == NULL)
return 0; return DC_STATUS_SUCCESS;
// Restore the initial terminal attributes. // Restore the initial terminal attributes.
if (tcsetattr (device->fd, TCSANOW, &device->tty) != 0) { if (tcsetattr (device->fd, TCSANOW, &device->tty) != 0) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
errcode = -1; dc_status_set_error(&status, DC_STATUS_IO);
} }
#ifndef ENABLE_PTY #ifndef ENABLE_PTY
@ -214,24 +211,20 @@ serial_close (serial_t *device)
// Close the device. // Close the device.
if (close (device->fd) != 0) { if (close (device->fd) != 0) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
errcode = -1; dc_status_set_error(&status, DC_STATUS_IO);
} }
// Free memory. // Free memory.
free (device); free (device);
return errcode; return status;
} }
// dc_status_t
// Configure the serial port (baudrate, databits, parity, stopbits and flowcontrol). dc_serial_configure (dc_serial_t *device, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol)
//
int
serial_configure (serial_t *device, int baudrate, int databits, int parity, int stopbits, int flowcontrol)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return DC_STATUS_INVALIDARGS;
INFO (device->context, "Configure: baudrate=%i, databits=%i, parity=%i, stopbits=%i, flowcontrol=%i", INFO (device->context, "Configure: baudrate=%i, databits=%i, parity=%i, stopbits=%i, flowcontrol=%i",
baudrate, databits, parity, stopbits, flowcontrol); baudrate, databits, parity, stopbits, flowcontrol);
@ -241,7 +234,7 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int
memset (&tty, 0, sizeof (tty)); memset (&tty, 0, sizeof (tty));
if (tcgetattr (device->fd, &tty) != 0) { if (tcgetattr (device->fd, &tty) != 0) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return DC_STATUS_IO;
} }
// Setup raw input/output mode without echo. // Setup raw input/output mode without echo.
@ -337,7 +330,7 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int
if (cfsetispeed (&tty, baud) != 0 || if (cfsetispeed (&tty, baud) != 0 ||
cfsetospeed (&tty, baud) != 0) { cfsetospeed (&tty, baud) != 0) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return DC_STATUS_IO;
} }
// Set the character size. // Set the character size.
@ -356,70 +349,70 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int
tty.c_cflag |= CS8; tty.c_cflag |= CS8;
break; break;
default: default:
return -1; return DC_STATUS_INVALIDARGS;
} }
// Set the parity type. // Set the parity type.
tty.c_cflag &= ~(PARENB | PARODD); tty.c_cflag &= ~(PARENB | PARODD);
tty.c_iflag &= ~(IGNPAR | PARMRK | INPCK); tty.c_iflag &= ~(IGNPAR | PARMRK | INPCK);
switch (parity) { switch (parity) {
case SERIAL_PARITY_NONE: // No parity case DC_PARITY_NONE:
tty.c_iflag |= IGNPAR; tty.c_iflag |= IGNPAR;
break; break;
case SERIAL_PARITY_EVEN: // Even parity case DC_PARITY_EVEN:
tty.c_cflag |= PARENB; tty.c_cflag |= PARENB;
tty.c_iflag |= INPCK; tty.c_iflag |= INPCK;
break; break;
case SERIAL_PARITY_ODD: // Odd parity case DC_PARITY_ODD:
tty.c_cflag |= (PARENB | PARODD); tty.c_cflag |= (PARENB | PARODD);
tty.c_iflag |= INPCK; tty.c_iflag |= INPCK;
break; break;
default: default:
return -1; return DC_STATUS_INVALIDARGS;
} }
// Set the number of stop bits. // Set the number of stop bits.
switch (stopbits) { switch (stopbits) {
case 1: // One stopbit case DC_STOPBITS_ONE:
tty.c_cflag &= ~CSTOPB; tty.c_cflag &= ~CSTOPB;
break; break;
case 2: // Two stopbits case DC_STOPBITS_TWO:
tty.c_cflag |= CSTOPB; tty.c_cflag |= CSTOPB;
break; break;
default: default:
return -1; return DC_STATUS_INVALIDARGS;
} }
// Set the flow control. // Set the flow control.
switch (flowcontrol) { switch (flowcontrol) {
case SERIAL_FLOWCONTROL_NONE: // No flow control. case DC_FLOWCONTROL_NONE:
#ifdef CRTSCTS #ifdef CRTSCTS
tty.c_cflag &= ~CRTSCTS; tty.c_cflag &= ~CRTSCTS;
#endif #endif
tty.c_iflag &= ~(IXON | IXOFF | IXANY); tty.c_iflag &= ~(IXON | IXOFF | IXANY);
break; break;
case SERIAL_FLOWCONTROL_HARDWARE: // Hardware (RTS/CTS) flow control. case DC_FLOWCONTROL_HARDWARE:
#ifdef CRTSCTS #ifdef CRTSCTS
tty.c_cflag |= CRTSCTS; tty.c_cflag |= CRTSCTS;
tty.c_iflag &= ~(IXON | IXOFF | IXANY); tty.c_iflag &= ~(IXON | IXOFF | IXANY);
break; break;
#else #else
return -1; // Hardware flow control is unsupported. return DC_STATUS_UNSUPPORTED;
#endif #endif
case SERIAL_FLOWCONTROL_SOFTWARE: // Software (XON/XOFF) flow control. case DC_FLOWCONTROL_SOFTWARE:
#ifdef CRTSCTS #ifdef CRTSCTS
tty.c_cflag &= ~CRTSCTS; tty.c_cflag &= ~CRTSCTS;
#endif #endif
tty.c_iflag |= (IXON | IXOFF); tty.c_iflag |= (IXON | IXOFF);
break; break;
default: default:
return -1; return DC_STATUS_INVALIDARGS;
} }
// Apply the new settings. // Apply the new settings.
if (tcsetattr (device->fd, TCSANOW, &tty) != 0 && NOPTY) { if (tcsetattr (device->fd, TCSANOW, &tty) != 0 && NOPTY) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return DC_STATUS_IO;
} }
// Configure a custom baudrate if necessary. // Configure a custom baudrate if necessary.
@ -429,7 +422,7 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int
struct serial_struct ss; struct serial_struct ss;
if (ioctl (device->fd, TIOCGSERIAL, &ss) != 0 && NOPTY) { if (ioctl (device->fd, TIOCGSERIAL, &ss) != 0 && NOPTY) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return DC_STATUS_IO;
} }
// Set the custom divisor. // Set the custom divisor.
@ -440,81 +433,62 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int
// Apply the new settings. // Apply the new settings.
if (ioctl (device->fd, TIOCSSERIAL, &ss) != 0 && NOPTY) { if (ioctl (device->fd, TIOCSSERIAL, &ss) != 0 && NOPTY) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return DC_STATUS_IO;
} }
#elif defined(IOSSIOSPEED) #elif defined(IOSSIOSPEED)
speed_t speed = baudrate; speed_t speed = baudrate;
if (ioctl (device->fd, IOSSIOSPEED, &speed) != 0 && NOPTY) { if (ioctl (device->fd, IOSSIOSPEED, &speed) != 0 && NOPTY) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return DC_STATUS_IO;
} }
#else #else
// Custom baudrates are not supported. // Custom baudrates are not supported.
return -1; return DC_STATUS_UNSUPPORTED;
#endif #endif
} }
device->baudrate = baudrate; device->baudrate = baudrate;
device->nbits = 1 + databits + stopbits + (parity ? 1 : 0); device->nbits = 1 + databits + stopbits + (parity ? 1 : 0);
return 0; return DC_STATUS_SUCCESS;
} }
// dc_status_t
// Configure the serial port (timeouts). dc_serial_set_timeout (dc_serial_t *device, int timeout)
//
int
serial_set_timeout (serial_t *device, long timeout)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return DC_STATUS_INVALIDARGS;
INFO (device->context, "Timeout: value=%li", timeout); INFO (device->context, "Timeout: value=%i", timeout);
device->timeout = timeout; device->timeout = timeout;
return 0; return DC_STATUS_SUCCESS;
} }
dc_status_t
// dc_serial_set_halfduplex (dc_serial_t *device, unsigned int value)
// Configure the serial port (recommended size of the input/output buffers).
//
int
serial_set_queue_size (serial_t *device, unsigned int input, unsigned int output)
{ {
if (device == NULL) if (device == NULL)
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) return DC_STATUS_INVALIDARGS;
return 0;
}
int
serial_set_halfduplex (serial_t *device, int value)
{
if (device == NULL)
return -1; // EINVAL (Invalid argument)
device->halfduplex = value; device->halfduplex = value;
return 0; return DC_STATUS_SUCCESS;
} }
int dc_status_t
serial_set_latency (serial_t *device, unsigned int milliseconds) dc_serial_set_latency (dc_serial_t *device, unsigned int milliseconds)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return DC_STATUS_INVALIDARGS;
#if defined(TIOCGSERIAL) && defined(TIOCSSERIAL) && !defined(__ANDROID__) #if defined(TIOCGSERIAL) && defined(TIOCSSERIAL) && !defined(__ANDROID__)
// Get the current settings. // Get the current settings.
struct serial_struct ss; struct serial_struct ss;
if (ioctl (device->fd, TIOCGSERIAL, &ss) != 0 && NOPTY) { if (ioctl (device->fd, TIOCGSERIAL, &ss) != 0 && NOPTY) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return DC_STATUS_IO;
} }
// Set or clear the low latency flag. // Set or clear the low latency flag.
@ -527,7 +501,7 @@ serial_set_latency (serial_t *device, unsigned int milliseconds)
// Apply the new settings. // Apply the new settings.
if (ioctl (device->fd, TIOCSSERIAL, &ss) != 0 && NOPTY) { if (ioctl (device->fd, TIOCSSERIAL, &ss) != 0 && NOPTY) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return DC_STATUS_IO;
} }
#elif defined(IOSSDATALAT) #elif defined(IOSSDATALAT)
// Set the receive latency in microseconds. Serial drivers use this // Set the receive latency in microseconds. Serial drivers use this
@ -536,27 +510,31 @@ serial_set_latency (serial_t *device, unsigned int milliseconds)
unsigned long usec = (milliseconds == 0 ? 1 : milliseconds * 1000); unsigned long usec = (milliseconds == 0 ? 1 : milliseconds * 1000);
if (ioctl (device->fd, IOSSDATALAT, &usec) != 0 && NOPTY) { if (ioctl (device->fd, IOSSDATALAT, &usec) != 0 && NOPTY) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return DC_STATUS_IO;
} }
#endif #endif
return 0; return DC_STATUS_SUCCESS;
} }
int dc_status_t
serial_read (serial_t *device, void *data, unsigned int size) dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual)
{ {
if (device == NULL) dc_status_t status = DC_STATUS_SUCCESS;
return -1; // EINVAL (Invalid argument) size_t nbytes = 0;
if (device == NULL) {
status = DC_STATUS_INVALIDARGS;
goto out;
}
// The total timeout. // The total timeout.
long timeout = device->timeout; int timeout = device->timeout;
// The absolute target time. // The absolute target time.
struct timeval tve; struct timeval tve;
int init = 1; int init = 1;
unsigned int nbytes = 0;
while (nbytes < size) { while (nbytes < size) {
fd_set fds; fd_set fds;
FD_ZERO (&fds); FD_ZERO (&fds);
@ -567,7 +545,8 @@ serial_read (serial_t *device, void *data, unsigned int size)
struct timeval now; struct timeval now;
if (gettimeofday (&now, NULL) != 0) { if (gettimeofday (&now, NULL) != 0) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; status = DC_STATUS_IO;
goto out;
} }
if (init) { if (init) {
@ -593,17 +572,19 @@ serial_read (serial_t *device, void *data, unsigned int size)
if (errno == EINTR) if (errno == EINTR)
continue; // Retry. continue; // Retry.
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; // Error during select call. status = DC_STATUS_IO;
goto out;
} else if (rc == 0) { } else if (rc == 0) {
break; // Timeout. break; // Timeout.
} }
int n = read (device->fd, (char *) data + nbytes, size - nbytes); ssize_t n = read (device->fd, (char *) data + nbytes, size - nbytes);
if (n < 0) { if (n < 0) {
if (errno == EINTR || errno == EAGAIN) if (errno == EINTR || errno == EAGAIN)
continue; // Retry. continue; // Retry.
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; // Error during read call. status = DC_STATUS_IO;
goto out;
} else if (n == 0) { } else if (n == 0) {
break; // EOF. break; // EOF.
} }
@ -611,28 +592,40 @@ serial_read (serial_t *device, void *data, unsigned int size)
nbytes += n; nbytes += n;
} }
if (nbytes != size) {
status = DC_STATUS_TIMEOUT;
}
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes); HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes);
return nbytes; if (actual)
*actual = nbytes;
return status;
} }
dc_status_t
int dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *actual)
serial_write (serial_t *device, const void *data, unsigned int size)
{ {
if (device == NULL) dc_status_t status = DC_STATUS_SUCCESS;
return -1; // EINVAL (Invalid argument) size_t nbytes = 0;
if (device == NULL) {
status = DC_STATUS_INVALIDARGS;
goto out;
}
struct timeval tve, tvb; struct timeval tve, tvb;
if (device->halfduplex) { if (device->halfduplex) {
// Get the current time. // Get the current time.
if (gettimeofday (&tvb, NULL) != 0) { if (gettimeofday (&tvb, NULL) != 0) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; status = DC_STATUS_IO;
goto out;
} }
} }
unsigned int nbytes = 0;
while (nbytes < size) { while (nbytes < size) {
fd_set fds; fd_set fds;
FD_ZERO (&fds); FD_ZERO (&fds);
@ -643,17 +636,19 @@ serial_write (serial_t *device, const void *data, unsigned int size)
if (errno == EINTR) if (errno == EINTR)
continue; // Retry. continue; // Retry.
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; // Error during select call. status = DC_STATUS_IO;
goto out;
} else if (rc == 0) { } else if (rc == 0) {
break; // Timeout. break; // Timeout.
} }
int n = write (device->fd, (char *) data + nbytes, size - nbytes); ssize_t n = write (device->fd, (const char *) data + nbytes, size - nbytes);
if (n < 0) { if (n < 0) {
if (errno == EINTR || errno == EAGAIN) if (errno == EINTR || errno == EAGAIN)
continue; // Retry. continue; // Retry.
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; // Error during write call. status = DC_STATUS_IO;
goto out;
} else if (n == 0) { } else if (n == 0) {
break; // EOF. break; // EOF.
} }
@ -670,7 +665,8 @@ serial_write (serial_t *device, const void *data, unsigned int size)
#endif #endif
if (errno != EINTR ) { if (errno != EINTR ) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; status = DC_STATUS_IO;
goto out;
} }
} }
@ -678,7 +674,8 @@ serial_write (serial_t *device, const void *data, unsigned int size)
// Get the current time. // Get the current time.
if (gettimeofday (&tve, NULL) != 0) { if (gettimeofday (&tve, NULL) != 0) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; status = DC_STATUS_IO;
goto out;
} }
// Calculate the elapsed time (microseconds). // Calculate the elapsed time (microseconds).
@ -697,69 +694,67 @@ serial_write (serial_t *device, const void *data, unsigned int size)
// The remaining time is rounded up to the nearest millisecond to // The remaining time is rounded up to the nearest millisecond to
// match the Windows implementation. The higher resolution is // match the Windows implementation. The higher resolution is
// pointless anyway, since we already added a fudge factor above. // pointless anyway, since we already added a fudge factor above.
serial_sleep (device, (remaining + 999) / 1000); dc_serial_sleep (device, (remaining + 999) / 1000);
} }
} }
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes); HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes);
return nbytes; if (actual)
*actual = nbytes;
return status;
} }
dc_status_t
int dc_serial_purge (dc_serial_t *device, dc_direction_t direction)
serial_flush (serial_t *device, int queue)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return DC_STATUS_INVALIDARGS;
INFO (device->context, "Flush: queue=%u, input=%i, output=%i", queue, INFO (device->context, "Purge: direction=%u", direction);
serial_get_received (device),
serial_get_transmitted (device));
int flags = 0; int flags = 0;
switch (queue) { switch (direction) {
case SERIAL_QUEUE_INPUT: case DC_DIRECTION_INPUT:
flags = TCIFLUSH; flags = TCIFLUSH;
break; break;
case SERIAL_QUEUE_OUTPUT: case DC_DIRECTION_OUTPUT:
flags = TCOFLUSH; flags = TCOFLUSH;
break; break;
default: case DC_DIRECTION_ALL:
flags = TCIOFLUSH; flags = TCIOFLUSH;
break; break;
default:
return DC_STATUS_INVALIDARGS;
} }
if (tcflush (device->fd, flags) != 0) { if (tcflush (device->fd, flags) != 0) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return DC_STATUS_IO;
} }
return 0; return DC_STATUS_SUCCESS;
} }
dc_status_t
int dc_serial_flush (dc_serial_t *device)
serial_send_break (serial_t *device)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return DC_STATUS_INVALIDARGS;
if (tcsendbreak (device->fd, 0) != 0) { INFO (device->context, "Flush: none");
SYSERROR (device->context, errno);
return -1; return DC_STATUS_SUCCESS;
}
return 0;
} }
dc_status_t
int dc_serial_set_break (dc_serial_t *device, unsigned int level)
serial_set_break (serial_t *device, int level)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return DC_STATUS_INVALIDARGS;
INFO (device->context, "Break: value=%i", level); INFO (device->context, "Break: value=%i", level);
@ -767,18 +762,17 @@ serial_set_break (serial_t *device, int level)
if (ioctl (device->fd, action, NULL) != 0 && NOPTY) { if (ioctl (device->fd, action, NULL) != 0 && NOPTY) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return DC_STATUS_IO;
} }
return 0; return DC_STATUS_SUCCESS;
} }
dc_status_t
int dc_serial_set_dtr (dc_serial_t *device, unsigned int level)
serial_set_dtr (serial_t *device, int level)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return DC_STATUS_INVALIDARGS;
INFO (device->context, "DTR: value=%i", level); INFO (device->context, "DTR: value=%i", level);
@ -787,18 +781,17 @@ serial_set_dtr (serial_t *device, int level)
int value = TIOCM_DTR; int value = TIOCM_DTR;
if (ioctl (device->fd, action, &value) != 0 && NOPTY) { if (ioctl (device->fd, action, &value) != 0 && NOPTY) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return DC_STATUS_IO;
} }
return 0; return DC_STATUS_SUCCESS;
} }
dc_status_t
int dc_serial_set_rts (dc_serial_t *device, unsigned int level)
serial_set_rts (serial_t *device, int level)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return DC_STATUS_INVALIDARGS;
INFO (device->context, "RTS: value=%i", level); INFO (device->context, "RTS: value=%i", level);
@ -807,81 +800,66 @@ serial_set_rts (serial_t *device, int level)
int value = TIOCM_RTS; int value = TIOCM_RTS;
if (ioctl (device->fd, action, &value) != 0 && NOPTY) { if (ioctl (device->fd, action, &value) != 0 && NOPTY) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return DC_STATUS_IO;
} }
return 0; return DC_STATUS_SUCCESS;
} }
dc_status_t
int dc_serial_get_available (dc_serial_t *device, size_t *value)
serial_get_received (serial_t *device)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return DC_STATUS_INVALIDARGS;
int bytes = 0; int bytes = 0;
if (ioctl (device->fd, TIOCINQ, &bytes) != 0) { if (ioctl (device->fd, TIOCINQ, &bytes) != 0) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return DC_STATUS_IO;
} }
return bytes; if (value)
*value = bytes;
return DC_STATUS_SUCCESS;
} }
dc_status_t
int dc_serial_get_lines (dc_serial_t *device, unsigned int *value)
serial_get_transmitted (serial_t *device)
{ {
unsigned int lines = 0;
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return DC_STATUS_INVALIDARGS;
int bytes = 0;
if (ioctl (device->fd, TIOCOUTQ, &bytes) != 0) {
SYSERROR (device->context, errno);
return -1;
}
return bytes;
}
int
serial_get_line (serial_t *device, int line)
{
if (device == NULL)
return -1; // EINVAL (Invalid argument)
int status = 0; int status = 0;
if (ioctl (device->fd, TIOCMGET, &status) != 0) { if (ioctl (device->fd, TIOCMGET, &status) != 0) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return DC_STATUS_IO;
} }
switch (line) { if (status & TIOCM_CAR)
case SERIAL_LINE_DCD: lines |= DC_LINE_DCD;
return (status & TIOCM_CAR) == TIOCM_CAR; if (status & TIOCM_CTS)
case SERIAL_LINE_CTS: lines |= DC_LINE_CTS;
return (status & TIOCM_CTS) == TIOCM_CTS; if (status & TIOCM_DSR)
case SERIAL_LINE_DSR: lines |= DC_LINE_DSR;
return (status & TIOCM_DSR) == TIOCM_DSR; if (status & TIOCM_RNG)
case SERIAL_LINE_RNG: lines |= DC_LINE_RNG;
return (status & TIOCM_RNG) == TIOCM_RNG;
default:
return -1;
}
return 0; if (value)
*value = lines;
return DC_STATUS_SUCCESS;
} }
dc_status_t
int dc_serial_sleep (dc_serial_t *device, unsigned int timeout)
serial_sleep (serial_t *device, unsigned long timeout)
{ {
if (device == NULL) if (device == NULL)
return -1; return DC_STATUS_INVALIDARGS;
INFO (device->context, "Sleep: value=%lu", timeout); INFO (device->context, "Sleep: value=%u", timeout);
struct timespec ts; struct timespec ts;
ts.tv_sec = (timeout / 1000); ts.tv_sec = (timeout / 1000);
@ -890,9 +868,9 @@ serial_sleep (serial_t *device, unsigned long timeout)
while (nanosleep (&ts, &ts) != 0) { while (nanosleep (&ts, &ts) != 0) {
if (errno != EINTR ) { if (errno != EINTR ) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return DC_STATUS_IO;
} }
} }
return 0; return DC_STATUS_SUCCESS;
} }

View File

@ -25,9 +25,10 @@
#include <windows.h> #include <windows.h>
#include "serial.h" #include "serial.h"
#include "common-private.h"
#include "context-private.h" #include "context-private.h"
struct serial_t { struct dc_serial_t {
/* Library context. */ /* Library context. */
dc_context_t *context; dc_context_t *context;
/* /*
@ -47,17 +48,17 @@ struct serial_t {
unsigned int nbits; unsigned int nbits;
}; };
int dc_status_t
serial_enumerate (serial_callback_t callback, void *userdata) dc_serial_enumerate (dc_serial_callback_t callback, void *userdata)
{ {
// Open the registry key. // Open the registry key.
HKEY hKey; HKEY hKey;
LONG rc = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE, &hKey); LONG rc = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE, &hKey);
if (rc != ERROR_SUCCESS) { if (rc != ERROR_SUCCESS) {
if (rc == ERROR_FILE_NOT_FOUND) if (rc == ERROR_FILE_NOT_FOUND)
return 0; return DC_STATUS_SUCCESS;
else else
return -1; return DC_STATUS_IO;
} }
// Get the number of values. // Get the number of values.
@ -65,7 +66,7 @@ serial_enumerate (serial_callback_t callback, void *userdata)
rc = RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL); rc = RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL);
if (rc != ERROR_SUCCESS) { if (rc != ERROR_SUCCESS) {
RegCloseKey(hKey); RegCloseKey(hKey);
return -1; return DC_STATUS_IO;
} }
for (DWORD i = 0; i < count; ++i) { for (DWORD i = 0; i < count; ++i) {
@ -77,7 +78,7 @@ serial_enumerate (serial_callback_t callback, void *userdata)
rc = RegEnumValueA (hKey, i, name, &name_len, NULL, &type, (LPBYTE) data, &data_len); rc = RegEnumValueA (hKey, i, name, &name_len, NULL, &type, (LPBYTE) data, &data_len);
if (rc != ERROR_SUCCESS) { if (rc != ERROR_SUCCESS) {
RegCloseKey(hKey); RegCloseKey(hKey);
return -1; return DC_STATUS_IO;
} }
// Ignore non-string values. // Ignore non-string values.
@ -87,7 +88,7 @@ serial_enumerate (serial_callback_t callback, void *userdata)
// Prevent a possible buffer overflow. // Prevent a possible buffer overflow.
if (data_len >= sizeof (data)) { if (data_len >= sizeof (data)) {
RegCloseKey(hKey); RegCloseKey(hKey);
return -1; return DC_STATUS_NOMEMORY;
} }
// Null terminate the string. // Null terminate the string.
@ -98,18 +99,16 @@ serial_enumerate (serial_callback_t callback, void *userdata)
RegCloseKey(hKey); RegCloseKey(hKey);
return 0; return DC_STATUS_SUCCESS;
} }
// dc_status_t
// Open the serial port. dc_serial_open (dc_serial_t **out, dc_context_t *context, const char *name)
//
int
serial_open (serial_t **out, dc_context_t *context, const char* name)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
if (out == NULL) if (out == NULL)
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) return DC_STATUS_INVALIDARGS;
INFO (context, "Open: name=%s", name ? name : ""); INFO (context, "Open: name=%s", name ? name : "");
@ -119,7 +118,7 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
if (name && strncmp (name, buffer, 4) != 0) { if (name && strncmp (name, buffer, 4) != 0) {
size_t length = strlen (name) + 1; size_t length = strlen (name) + 1;
if (length + 4 > sizeof (buffer)) if (length + 4 > sizeof (buffer))
return -1; return DC_STATUS_NOMEMORY;
memcpy (buffer + 4, name, length); memcpy (buffer + 4, name, length);
devname = buffer; devname = buffer;
} else { } else {
@ -127,10 +126,10 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
} }
// Allocate memory. // Allocate memory.
serial_t *device = (serial_t *) malloc (sizeof (serial_t)); dc_serial_t *device = (dc_serial_t *) malloc (sizeof (dc_serial_t));
if (device == NULL) { if (device == NULL) {
SYSERROR (context, ERROR_OUTOFMEMORY); SYSERROR (context, ERROR_OUTOFMEMORY);
return -1; // ERROR_OUTOFMEMORY (Not enough storage is available to complete this operation) return DC_STATUS_NOMEMORY;
} }
// Library context. // Library context.
@ -150,6 +149,7 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
NULL); NULL);
if (device->hFile == INVALID_HANDLE_VALUE) { if (device->hFile == INVALID_HANDLE_VALUE) {
SYSERROR (context, GetLastError ()); SYSERROR (context, GetLastError ());
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
@ -160,60 +160,53 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
if (!GetCommState (device->hFile, &device->dcb) || if (!GetCommState (device->hFile, &device->dcb) ||
!GetCommTimeouts (device->hFile, &device->timeouts)) { !GetCommTimeouts (device->hFile, &device->timeouts)) {
SYSERROR (context, GetLastError ()); SYSERROR (context, GetLastError ());
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
*out = device; *out = device;
return 0; return DC_STATUS_SUCCESS;
error_close: error_close:
CloseHandle (device->hFile); CloseHandle (device->hFile);
error_free: error_free:
free (device); free (device);
return -1; return status;
} }
// dc_status_t
// Close the serial port. dc_serial_close (dc_serial_t *device)
//
int
serial_close (serial_t *device)
{ {
int errcode = 0; dc_status_t status = DC_STATUS_SUCCESS;
if (device == NULL) if (device == NULL)
return 0; return DC_STATUS_SUCCESS;
// Restore the initial communication settings and timeouts. // Restore the initial communication settings and timeouts.
if (!SetCommState (device->hFile, &device->dcb) || if (!SetCommState (device->hFile, &device->dcb) ||
!SetCommTimeouts (device->hFile, &device->timeouts)) { !SetCommTimeouts (device->hFile, &device->timeouts)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
errcode = -1; dc_status_set_error(&status, DC_STATUS_IO);
} }
// Close the device. // Close the device.
if (!CloseHandle (device->hFile)) { if (!CloseHandle (device->hFile)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
errcode = -1; dc_status_set_error(&status, DC_STATUS_IO);
} }
// Free memory. // Free memory.
free (device); free (device);
return errcode; return status;
} }
// dc_status_t
// Configure the serial port (baudrate, databits, parity, stopbits and flowcontrol). dc_serial_configure (dc_serial_t *device, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol)
//
int
serial_configure (serial_t *device, int baudrate, int databits, int parity, int stopbits, int flowcontrol)
{ {
if (device == NULL) if (device == NULL)
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) return DC_STATUS_INVALIDARGS;
INFO (device->context, "Configure: baudrate=%i, databits=%i, parity=%i, stopbits=%i, flowcontrol=%i", INFO (device->context, "Configure: baudrate=%i, databits=%i, parity=%i, stopbits=%i, flowcontrol=%i",
baudrate, databits, parity, stopbits, flowcontrol); baudrate, databits, parity, stopbits, flowcontrol);
@ -222,7 +215,7 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int
DCB dcb; DCB dcb;
if (!GetCommState (device->hFile, &dcb)) { if (!GetCommState (device->hFile, &dcb)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
return -1; return DC_STATUS_IO;
} }
dcb.fBinary = TRUE; // Enable Binary Transmission dcb.fBinary = TRUE; // Enable Binary Transmission
@ -235,40 +228,41 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int
if (databits >= 5 && databits <= 8) if (databits >= 5 && databits <= 8)
dcb.ByteSize = databits; dcb.ByteSize = databits;
else else
return -1; return DC_STATUS_INVALIDARGS;
// Parity checking. // Parity checking.
switch (parity) { switch (parity) {
case SERIAL_PARITY_NONE: // No parity case DC_PARITY_NONE:
dcb.Parity = NOPARITY; dcb.Parity = NOPARITY;
dcb.fParity = FALSE; dcb.fParity = FALSE;
break; break;
case SERIAL_PARITY_EVEN: // Even parity case DC_PARITY_EVEN:
dcb.Parity = EVENPARITY; dcb.Parity = EVENPARITY;
dcb.fParity = TRUE; dcb.fParity = TRUE;
break; break;
case SERIAL_PARITY_ODD: // Odd parity case DC_PARITY_ODD:
dcb.Parity = ODDPARITY; dcb.Parity = ODDPARITY;
dcb.fParity = TRUE; dcb.fParity = TRUE;
break; break;
default: default:
return -1; return DC_STATUS_INVALIDARGS;
} }
// Stopbits. // Stopbits.
switch (stopbits) { switch (stopbits) {
case 1: // One stopbit case DC_STOPBITS_ONE:
dcb.StopBits = ONESTOPBIT; dcb.StopBits = ONESTOPBIT;
break; break;
case 2: // Two stopbits case DC_STOPBITS_TWO:
dcb.StopBits = TWOSTOPBITS; dcb.StopBits = TWOSTOPBITS;
break; break;
default: default:
return -1; return DC_STATUS_INVALIDARGS;
} }
// Flow control. // Flow control.
switch (flowcontrol) { switch (flowcontrol) {
case SERIAL_FLOWCONTROL_NONE: // No flow control. case DC_FLOWCONTROL_NONE:
dcb.fInX = FALSE; dcb.fInX = FALSE;
dcb.fOutX = FALSE; dcb.fOutX = FALSE;
dcb.fOutxCtsFlow = FALSE; dcb.fOutxCtsFlow = FALSE;
@ -276,7 +270,7 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int
dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fRtsControl = RTS_CONTROL_ENABLE; dcb.fRtsControl = RTS_CONTROL_ENABLE;
break; break;
case SERIAL_FLOWCONTROL_HARDWARE: // Hardware (RTS/CTS) flow control. case DC_FLOWCONTROL_HARDWARE:
dcb.fInX = FALSE; dcb.fInX = FALSE;
dcb.fOutX = FALSE; dcb.fOutX = FALSE;
dcb.fOutxCtsFlow = TRUE; dcb.fOutxCtsFlow = TRUE;
@ -284,7 +278,7 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
break; break;
case SERIAL_FLOWCONTROL_SOFTWARE: // Software (XON/XOFF) flow control. case DC_FLOWCONTROL_SOFTWARE:
dcb.fInX = TRUE; dcb.fInX = TRUE;
dcb.fOutX = TRUE; dcb.fOutX = TRUE;
dcb.fOutxCtsFlow = FALSE; dcb.fOutxCtsFlow = FALSE;
@ -293,38 +287,34 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int
dcb.fRtsControl = RTS_CONTROL_ENABLE; dcb.fRtsControl = RTS_CONTROL_ENABLE;
break; break;
default: default:
return -1; return DC_STATUS_INVALIDARGS;
} }
// Apply the new settings. // Apply the new settings.
if (!SetCommState (device->hFile, &dcb)) { if (!SetCommState (device->hFile, &dcb)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
return -1; return DC_STATUS_IO;
} }
device->baudrate = baudrate; device->baudrate = baudrate;
device->nbits = 1 + databits + stopbits + (parity ? 1 : 0); device->nbits = 1 + databits + stopbits + (parity ? 1 : 0);
return 0; return DC_STATUS_SUCCESS;
} }
// dc_status_t
// Configure the serial port (timeouts). dc_serial_set_timeout (dc_serial_t *device, int timeout)
//
int
serial_set_timeout (serial_t *device, long timeout)
{ {
if (device == NULL) if (device == NULL)
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) return DC_STATUS_INVALIDARGS;
INFO (device->context, "Timeout: value=%li", timeout); INFO (device->context, "Timeout: value=%i", timeout);
// Retrieve the current timeouts. // Retrieve the current timeouts.
COMMTIMEOUTS timeouts; COMMTIMEOUTS timeouts;
if (!GetCommTimeouts (device->hFile, &timeouts)) { if (!GetCommTimeouts (device->hFile, &timeouts)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
return -1; return DC_STATUS_IO;
} }
// Update the settings. // Update the settings.
@ -354,75 +344,72 @@ serial_set_timeout (serial_t *device, long timeout)
// Activate the new timeouts. // Activate the new timeouts.
if (!SetCommTimeouts (device->hFile, &timeouts)) { if (!SetCommTimeouts (device->hFile, &timeouts)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
return -1; return DC_STATUS_IO;
} }
return 0; return DC_STATUS_SUCCESS;
} }
// dc_status_t
// Configure the serial port (recommended size of the input/output buffers). dc_serial_set_halfduplex (dc_serial_t *device, unsigned int value)
//
int
serial_set_queue_size (serial_t *device, unsigned int input, unsigned int output)
{ {
if (device == NULL) if (device == NULL)
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) return DC_STATUS_INVALIDARGS;
if (!SetupComm (device->hFile, input, output)) {
SYSERROR (device->context, GetLastError ());
return -1;
}
return 0;
}
int
serial_set_halfduplex (serial_t *device, int value)
{
if (device == NULL)
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect)
device->halfduplex = value; device->halfduplex = value;
return 0; return DC_STATUS_SUCCESS;
} }
dc_status_t
int dc_serial_set_latency (dc_serial_t *device, unsigned int value)
serial_set_latency (serial_t *device, unsigned int milliseconds)
{ {
if (device == NULL) if (device == NULL)
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) return DC_STATUS_INVALIDARGS;
return 0; return DC_STATUS_SUCCESS;
} }
int dc_status_t
serial_read (serial_t *device, void* data, unsigned int size) dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual)
{ {
if (device == NULL) dc_status_t status = DC_STATUS_SUCCESS;
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect)
DWORD dwRead = 0; DWORD dwRead = 0;
if (!ReadFile (device->hFile, data, size, &dwRead, NULL)) {
SYSERROR (device->context, GetLastError ()); if (device == NULL) {
return -1; status = DC_STATUS_INVALIDARGS;
goto out;
} }
if (!ReadFile (device->hFile, data, size, &dwRead, NULL)) {
SYSERROR (device->context, GetLastError ());
status = DC_STATUS_IO;
goto out;
}
if (dwRead != size) {
status = DC_STATUS_TIMEOUT;
}
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, dwRead); HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, dwRead);
return dwRead; if (actual)
*actual = dwRead;
return status;
} }
dc_status_t
int dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *actual)
serial_write (serial_t *device, const void* data, unsigned int size)
{ {
if (device == NULL) dc_status_t status = DC_STATUS_SUCCESS;
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) DWORD dwWritten = 0;
if (device == NULL) {
status = DC_STATUS_INVALIDARGS;
goto out;
}
LARGE_INTEGER begin, end, freq; LARGE_INTEGER begin, end, freq;
if (device->halfduplex) { if (device->halfduplex) {
@ -430,21 +417,23 @@ serial_write (serial_t *device, const void* data, unsigned int size)
if (!QueryPerformanceFrequency(&freq) || if (!QueryPerformanceFrequency(&freq) ||
!QueryPerformanceCounter(&begin)) { !QueryPerformanceCounter(&begin)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
return -1; status = DC_STATUS_IO;
goto out;
} }
} }
DWORD dwWritten = 0;
if (!WriteFile (device->hFile, data, size, &dwWritten, NULL)) { if (!WriteFile (device->hFile, data, size, &dwWritten, NULL)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
return -1; status = DC_STATUS_IO;
goto out;
} }
if (device->halfduplex) { if (device->halfduplex) {
// Get the current time. // Get the current time.
if (!QueryPerformanceCounter(&end)) { if (!QueryPerformanceCounter(&end)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
return -1; status = DC_STATUS_IO;
goto out;
} }
// Calculate the elapsed time (microseconds). // Calculate the elapsed time (microseconds).
@ -461,99 +450,99 @@ serial_write (serial_t *device, const void* data, unsigned int size)
// The remaining time is rounded up to the nearest millisecond // The remaining time is rounded up to the nearest millisecond
// because the Windows Sleep() function doesn't have a higher // because the Windows Sleep() function doesn't have a higher
// resolution. // resolution.
serial_sleep (device, (remaining + 999) / 1000); dc_serial_sleep (device, (remaining + 999) / 1000);
} }
} }
if (dwWritten != size) {
status = DC_STATUS_TIMEOUT;
}
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, dwWritten); HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, dwWritten);
return dwWritten; if (actual)
*actual = dwWritten;
return status;
} }
dc_status_t
int dc_serial_purge (dc_serial_t *device, dc_direction_t direction)
serial_flush (serial_t *device, int queue)
{ {
if (device == NULL) if (device == NULL)
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) return DC_STATUS_INVALIDARGS;
INFO (device->context, "Flush: queue=%u, input=%i, output=%i", queue, INFO (device->context, "Purge: direction=%u", direction);
serial_get_received (device),
serial_get_transmitted (device));
DWORD flags = 0; DWORD flags = 0;
switch (queue) { switch (direction) {
case SERIAL_QUEUE_INPUT: case DC_DIRECTION_INPUT:
flags = PURGE_RXABORT | PURGE_RXCLEAR; flags = PURGE_RXABORT | PURGE_RXCLEAR;
break; break;
case SERIAL_QUEUE_OUTPUT: case DC_DIRECTION_OUTPUT:
flags = PURGE_TXABORT | PURGE_TXCLEAR; flags = PURGE_TXABORT | PURGE_TXCLEAR;
break; break;
default: case DC_DIRECTION_ALL:
flags = PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR; flags = PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR;
break; break;
default:
return DC_STATUS_INVALIDARGS;
} }
if (!PurgeComm (device->hFile, flags)) { if (!PurgeComm (device->hFile, flags)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
return -1; return DC_STATUS_IO;
} }
return 0; return DC_STATUS_SUCCESS;
} }
dc_status_t
int dc_serial_flush (dc_serial_t *device)
serial_send_break (serial_t *device)
{ {
if (device == NULL) if (device == NULL)
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) return DC_STATUS_INVALIDARGS;
if (!SetCommBreak (device->hFile)) { INFO (device->context, "Flush: none");
if (!FlushFileBuffers (device->hFile)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
return -1; return DC_STATUS_IO;
} }
Sleep (250); return DC_STATUS_SUCCESS;
if (!ClearCommBreak (device->hFile)) {
SYSERROR (device->context, GetLastError ());
return -1;
}
return 0;
} }
dc_status_t
int dc_serial_set_break (dc_serial_t *device, unsigned int level)
serial_set_break (serial_t *device, int level)
{ {
if (device == NULL) if (device == NULL)
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) return DC_STATUS_INVALIDARGS;
INFO (device->context, "Break: value=%i", level); INFO (device->context, "Break: value=%i", level);
if (level) { if (level) {
if (!SetCommBreak (device->hFile)) { if (!SetCommBreak (device->hFile)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
return -1; return DC_STATUS_IO;
} }
} else { } else {
if (!ClearCommBreak (device->hFile)) { if (!ClearCommBreak (device->hFile)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
return -1; return DC_STATUS_IO;
} }
} }
return 0; return DC_STATUS_SUCCESS;
} }
int dc_status_t
serial_set_dtr (serial_t *device, int level) dc_serial_set_dtr (dc_serial_t *device, unsigned int level)
{ {
if (device == NULL) if (device == NULL)
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) return DC_STATUS_INVALIDARGS;
INFO (device->context, "DTR: value=%i", level); INFO (device->context, "DTR: value=%i", level);
@ -561,18 +550,17 @@ serial_set_dtr (serial_t *device, int level)
if (!EscapeCommFunction (device->hFile, status)) { if (!EscapeCommFunction (device->hFile, status)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
return -1; return DC_STATUS_IO;
} }
return 0; return DC_STATUS_SUCCESS;
} }
dc_status_t
int dc_serial_set_rts (dc_serial_t *device, unsigned int level)
serial_set_rts (serial_t *device, int level)
{ {
if (device == NULL) if (device == NULL)
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) return DC_STATUS_INVALIDARGS;
INFO (device->context, "RTS: value=%i", level); INFO (device->context, "RTS: value=%i", level);
@ -580,85 +568,69 @@ serial_set_rts (serial_t *device, int level)
if (!EscapeCommFunction (device->hFile, status)) { if (!EscapeCommFunction (device->hFile, status)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
return -1; return DC_STATUS_IO;
} }
return 0; return DC_STATUS_SUCCESS;
} }
dc_status_t
int dc_serial_get_available (dc_serial_t *device, size_t *value)
serial_get_received (serial_t *device)
{ {
if (device == NULL) if (device == NULL)
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) return DC_STATUS_INVALIDARGS;
COMSTAT stats; COMSTAT stats;
if (!ClearCommError (device->hFile, NULL, &stats)) { if (!ClearCommError (device->hFile, NULL, &stats)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
return -1; return DC_STATUS_IO;
} }
return stats.cbInQue; if (value)
*value = stats.cbInQue;
return DC_STATUS_SUCCESS;
} }
dc_status_t
int dc_serial_get_lines (dc_serial_t *device, unsigned int *value)
serial_get_transmitted (serial_t *device)
{ {
unsigned int lines = 0;
if (device == NULL) if (device == NULL)
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) return DC_STATUS_INVALIDARGS;
COMSTAT stats;
if (!ClearCommError (device->hFile, NULL, &stats)) {
SYSERROR (device->context, GetLastError ());
return -1;
}
return stats.cbOutQue;
}
int
serial_get_line (serial_t *device, int line)
{
if (device == NULL)
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect)
DWORD stats = 0; DWORD stats = 0;
if (!GetCommModemStatus (device->hFile, &stats)) { if (!GetCommModemStatus (device->hFile, &stats)) {
SYSERROR (device->context, GetLastError ()); SYSERROR (device->context, GetLastError ());
return -1; return DC_STATUS_IO;
} }
switch (line) { if (stats & MS_RLSD_ON)
case SERIAL_LINE_DCD: lines |= DC_LINE_DCD;
return (stats & MS_RLSD_ON) == MS_RLSD_ON; if (stats & MS_CTS_ON)
case SERIAL_LINE_CTS: lines |= DC_LINE_CTS;
return (stats & MS_CTS_ON) == MS_CTS_ON; if (stats & MS_DSR_ON)
case SERIAL_LINE_DSR: lines |= DC_LINE_DSR;
return (stats & MS_DSR_ON) == MS_DSR_ON; if (stats & MS_RING_ON)
case SERIAL_LINE_RNG: lines |= DC_LINE_RNG;
return (stats & MS_RING_ON) == MS_RING_ON;
default:
return -1;
}
return 0; if (value)
*value = lines;
return DC_STATUS_SUCCESS;
} }
dc_status_t
int dc_serial_sleep (dc_serial_t *device, unsigned int timeout)
serial_sleep (serial_t *device, unsigned long timeout)
{ {
if (device == NULL) if (device == NULL)
return -1; return DC_STATUS_INVALIDARGS;
INFO (device->context, "Sleep: value=%lu", timeout); INFO (device->context, "Sleep: value=%u", timeout);
Sleep (timeout); Sleep (timeout);
return 0; return DC_STATUS_SUCCESS;
} }

View File

@ -35,43 +35,40 @@
#define ESC_END 0xDC #define ESC_END 0xDC
#define ESC_ESC 0xDD #define ESC_ESC 0xDD
#define EXITCODE(n) ((n) < 0 ? DC_STATUS_IO : DC_STATUS_TIMEOUT)
dc_status_t dc_status_t
shearwater_common_open (shearwater_common_device_t *device, dc_context_t *context, const char *name) shearwater_common_open (shearwater_common_device_t *device, dc_context_t *context, const char *name)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
return DC_STATUS_IO; return status;
} }
// Set the serial communication protocol (115200 8N1). // Set the serial communication protocol (115200 8N1).
rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (3000ms). // Set the timeout for receiving data (3000ms).
if (serial_set_timeout (device->port, 3000) == -1) { status = dc_serial_set_timeout (device->port, 3000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_sleep (device->port, 300); dc_serial_sleep (device->port, 300);
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
return status; return status;
} }
@ -80,11 +77,7 @@ dc_status_t
shearwater_common_close (shearwater_common_device_t *device) shearwater_common_close (shearwater_common_device_t *device)
{ {
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { return dc_serial_close (device->port);
return DC_STATUS_IO;
}
return DC_STATUS_SUCCESS;
} }
@ -150,7 +143,7 @@ shearwater_common_decompress_xor (unsigned char *data, unsigned int size)
static dc_status_t static dc_status_t
shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned char data[], unsigned int size) shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned char data[], unsigned int size)
{ {
int n = 0; dc_status_t status = DC_STATUS_SUCCESS;
const unsigned char end[] = {END}; const unsigned char end[] = {END};
const unsigned char esc_end[] = {ESC, ESC_END}; const unsigned char esc_end[] = {ESC, ESC_END};
const unsigned char esc_esc[] = {ESC, ESC_ESC}; const unsigned char esc_esc[] = {ESC, ESC_ESC};
@ -160,9 +153,9 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned
#if 0 #if 0
// Send an initial END character to flush out any data that may have // Send an initial END character to flush out any data that may have
// accumulated in the receiver due to line noise. // accumulated in the receiver due to line noise.
n = serial_write (device->port, end, sizeof (end)); status = dc_serial_write (device->port, end, sizeof (end), NULL);
if (n != sizeof (end)) { if (status != DC_STATUS_SUCCESS) {
return EXITCODE(n); return status;
} }
#endif #endif
@ -189,9 +182,9 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned
// Flush the buffer if necessary. // Flush the buffer if necessary.
if (nbytes + len + sizeof(end) > sizeof(buffer)) { if (nbytes + len + sizeof(end) > sizeof(buffer)) {
n = serial_write (device->port, buffer, nbytes); status = dc_serial_write (device->port, buffer, nbytes, NULL);
if (n != nbytes) { if (status != DC_STATUS_SUCCESS) {
return EXITCODE(n); return status;
} }
nbytes = 0; nbytes = 0;
@ -207,9 +200,9 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned
nbytes += sizeof(end); nbytes += sizeof(end);
// Flush the buffer. // Flush the buffer.
n = serial_write (device->port, buffer, nbytes); status = dc_serial_write (device->port, buffer, nbytes, NULL);
if (n != nbytes) { if (status != DC_STATUS_SUCCESS) {
return EXITCODE(n); return status;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
@ -219,6 +212,7 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned
static dc_status_t static dc_status_t
shearwater_common_slip_read (shearwater_common_device_t *device, unsigned char data[], unsigned int size, unsigned int *actual) shearwater_common_slip_read (shearwater_common_device_t *device, unsigned char data[], unsigned int size, unsigned int *actual)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
unsigned int received = 0; unsigned int received = 0;
// Read bytes until a complete packet has been received. If the // Read bytes until a complete packet has been received. If the
@ -227,12 +221,11 @@ shearwater_common_slip_read (shearwater_common_device_t *device, unsigned char d
// than the supplied buffer size. // than the supplied buffer size.
while (1) { while (1) {
unsigned char c = 0; unsigned char c = 0;
int n = 0;
// Get a single character to process. // Get a single character to process.
n = serial_read (device->port, &c, 1); status = dc_serial_read (device->port, &c, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
return EXITCODE(n); return status;
} }
switch (c) { switch (c) {
@ -249,9 +242,9 @@ shearwater_common_slip_read (shearwater_common_device_t *device, unsigned char d
case ESC: case ESC:
// If it's an ESC character, get another character and then // If it's an ESC character, get another character and then
// figure out what to store in the packet based on that. // figure out what to store in the packet based on that.
n = serial_read (device->port, &c, 1); status = dc_serial_read (device->port, &c, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
return EXITCODE(n); return status;
} }
// If it's not one of the two escaped characters, then we // If it's not one of the two escaped characters, then we

View File

@ -34,7 +34,7 @@ extern "C" {
typedef struct shearwater_common_device_t { typedef struct shearwater_common_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
} shearwater_common_device_t; } shearwater_common_device_t;
dc_status_t dc_status_t

View File

@ -33,11 +33,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), (const dc_device_vtable_t *) &suunto_d9_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), (const dc_device_vtable_t *) &suunto_d9_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define C_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) #define C_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
#define D4i 0x19 #define D4i 0x19
@ -49,7 +44,7 @@
typedef struct suunto_d9_device_t { typedef struct suunto_d9_device_t {
suunto_common2_device_t base; suunto_common2_device_t base;
serial_t *port; dc_serial_t *port;
} suunto_d9_device_t; } suunto_d9_device_t;
static dc_status_t suunto_d9_device_packet (dc_device_t *abstract, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size); static dc_status_t suunto_d9_device_packet (dc_device_t *abstract, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size);
@ -114,10 +109,10 @@ suunto_d9_device_autodetect (suunto_d9_device_t *device, unsigned int model)
unsigned int idx = (hint + i) % C_ARRAY_SIZE(baudrates); unsigned int idx = (hint + i) % C_ARRAY_SIZE(baudrates);
// Adjust the baudrate. // Adjust the baudrate.
int rc = serial_configure (device->port, baudrates[idx], 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, baudrates[idx], 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to set the terminal attributes."); ERROR (abstract->context, "Failed to set the terminal attributes.");
return DC_STATUS_IO; return status;
} }
// Try reading the version info. // Try reading the version info.
@ -153,40 +148,38 @@ suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *nam
device->port = NULL; device->port = NULL;
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (9600 8N1). // Set the serial communication protocol (9600 8N1).
rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (3000 ms). // Set the timeout for receiving data (3000 ms).
if (serial_set_timeout (device->port, 3000) == -1) { status = dc_serial_set_timeout (device->port, 3000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the DTR line (power supply for the interface). // Set the DTR line (power supply for the interface).
if (serial_set_dtr (device->port, 1) == -1) { status = dc_serial_set_dtr (device->port, 1);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the DTR line."); ERROR (context, "Failed to set the DTR line.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Give the interface 100 ms to settle and draw power up. // Give the interface 100 ms to settle and draw power up.
serial_sleep (device->port, 100); dc_serial_sleep (device->port, 100);
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
// Try to autodetect the protocol variant. // Try to autodetect the protocol variant.
status = suunto_d9_device_autodetect (device, model); status = suunto_d9_device_autodetect (device, model);
@ -210,7 +203,7 @@ suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *nam
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -222,10 +215,12 @@ suunto_d9_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
suunto_d9_device_t *device = (suunto_d9_device_t*) abstract; suunto_d9_device_t *device = (suunto_d9_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -235,28 +230,29 @@ suunto_d9_device_close (dc_device_t *abstract)
static dc_status_t static dc_status_t
suunto_d9_device_packet (dc_device_t *abstract, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size) suunto_d9_device_packet (dc_device_t *abstract, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
suunto_d9_device_t *device = (suunto_d9_device_t *) abstract; suunto_d9_device_t *device = (suunto_d9_device_t *) abstract;
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
// Clear RTS to send the command. // Clear RTS to send the command.
serial_set_rts (device->port, 0); dc_serial_set_rts (device->port, 0);
// Send the command to the dive computer. // Send the command to the dive computer.
int n = serial_write (device->port, command, csize); status = dc_serial_write (device->port, command, csize, NULL);
if (n != csize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Receive the echo. // Receive the echo.
unsigned char echo[128] = {0}; unsigned char echo[128] = {0};
assert (sizeof (echo) >= csize); assert (sizeof (echo) >= csize);
n = serial_read (device->port, echo, csize); status = dc_serial_read (device->port, echo, csize, NULL);
if (n != csize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the echo."); ERROR (abstract->context, "Failed to receive the echo.");
return EXITCODE (n); return status;
} }
// Verify the echo. // Verify the echo.
@ -266,13 +262,13 @@ suunto_d9_device_packet (dc_device_t *abstract, const unsigned char command[], u
} }
// Set RTS to receive the reply. // Set RTS to receive the reply.
serial_set_rts (device->port, 1); dc_serial_set_rts (device->port, 1);
// Receive the answer of the dive computer. // Receive the answer of the dive computer.
n = serial_read (device->port, answer, asize); status = dc_serial_read (device->port, answer, asize, NULL);
if (n != asize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the header of the package. // Verify the header of the package.

View File

@ -33,16 +33,11 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &suunto_eon_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &suunto_eon_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define SZ_MEMORY 0x900 #define SZ_MEMORY 0x900
typedef struct suunto_eon_device_t { typedef struct suunto_eon_device_t {
suunto_common_device_t base; suunto_common_device_t base;
serial_t *port; dc_serial_t *port;
} suunto_eon_device_t; } suunto_eon_device_t;
static dc_status_t suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer); static dc_status_t suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer);
@ -92,32 +87,30 @@ suunto_eon_device_open (dc_device_t **out, dc_context_t *context, const char *na
device->port = NULL; device->port = NULL;
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (1200 8N2). // Set the serial communication protocol (1200 8N2).
rc = serial_configure (device->port, 1200, 8, SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 1200, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (1000ms). // Set the timeout for receiving data (1000ms).
if (serial_set_timeout (device->port, 1000) == -1) { status = dc_serial_set_timeout (device->port, 1000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Clear the RTS line. // Clear the RTS line.
if (serial_set_rts (device->port, 0)) { status = dc_serial_set_rts (device->port, 0);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the DTR/RTS line."); ERROR (context, "Failed to set the DTR/RTS line.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
@ -126,7 +119,7 @@ suunto_eon_device_open (dc_device_t **out, dc_context_t *context, const char *na
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -138,10 +131,12 @@ suunto_eon_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
suunto_eon_device_t *device = (suunto_eon_device_t*) abstract; suunto_eon_device_t *device = (suunto_eon_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -151,6 +146,7 @@ suunto_eon_device_close (dc_device_t *abstract)
static dc_status_t static dc_status_t
suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
suunto_eon_device_t *device = (suunto_eon_device_t*) abstract; suunto_eon_device_t *device = (suunto_eon_device_t*) abstract;
// Erase the current contents of the buffer and // Erase the current contents of the buffer and
@ -167,10 +163,10 @@ suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
// Send the command. // Send the command.
unsigned char command[1] = {'P'}; unsigned char command[1] = {'P'};
int rc = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (rc != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (rc); return status;
} }
// Receive the answer. // Receive the answer.
@ -181,8 +177,9 @@ suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
unsigned int len = 64; unsigned int len = 64;
// Increase the packet size if more data is immediately available. // Increase the packet size if more data is immediately available.
int available = serial_get_received (device->port); size_t available = 0;
if (available > len) status = dc_serial_get_available (device->port, &available);
if (status == DC_STATUS_SUCCESS && available > len)
len = available; len = available;
// Limit the packet size to the total size. // Limit the packet size to the total size.
@ -190,10 +187,10 @@ suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
len = sizeof(answer) - nbytes; len = sizeof(answer) - nbytes;
// Read the packet. // Read the packet.
int n = serial_read (device->port, answer + nbytes, len); status = dc_serial_read (device->port, answer + nbytes, len, NULL);
if (n != len) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Update and emit a progress event. // Update and emit a progress event.
@ -254,6 +251,7 @@ suunto_eon_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
dc_status_t dc_status_t
suunto_eon_device_write_name (dc_device_t *abstract, unsigned char data[], unsigned int size) suunto_eon_device_write_name (dc_device_t *abstract, unsigned char data[], unsigned int size)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
suunto_eon_device_t *device = (suunto_eon_device_t*) abstract; suunto_eon_device_t *device = (suunto_eon_device_t*) abstract;
if (!ISINSTANCE (abstract)) if (!ISINSTANCE (abstract))
@ -265,10 +263,10 @@ suunto_eon_device_write_name (dc_device_t *abstract, unsigned char data[], unsig
// Send the command. // Send the command.
unsigned char command[21] = {'N'}; unsigned char command[21] = {'N'};
memcpy (command + 1, data, size); memcpy (command + 1, data, size);
int rc = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (rc != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (rc); return status;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
@ -278,6 +276,7 @@ suunto_eon_device_write_name (dc_device_t *abstract, unsigned char data[], unsig
dc_status_t dc_status_t
suunto_eon_device_write_interval (dc_device_t *abstract, unsigned char interval) suunto_eon_device_write_interval (dc_device_t *abstract, unsigned char interval)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
suunto_eon_device_t *device = (suunto_eon_device_t*) abstract; suunto_eon_device_t *device = (suunto_eon_device_t*) abstract;
if (!ISINSTANCE (abstract)) if (!ISINSTANCE (abstract))
@ -285,10 +284,10 @@ suunto_eon_device_write_interval (dc_device_t *abstract, unsigned char interval)
// Send the command. // Send the command.
unsigned char command[2] = {'T', interval}; unsigned char command[2] = {'T', interval};
int rc = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (rc != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (rc); return status;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;

View File

@ -32,11 +32,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &suunto_solution_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &suunto_solution_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define SZ_MEMORY 256 #define SZ_MEMORY 256
#define RB_PROFILE_BEGIN 0x020 #define RB_PROFILE_BEGIN 0x020
@ -44,7 +39,7 @@
typedef struct suunto_solution_device_t { typedef struct suunto_solution_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
} suunto_solution_device_t; } suunto_solution_device_t;
static dc_status_t suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer); static dc_status_t suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer);
@ -83,32 +78,30 @@ suunto_solution_device_open (dc_device_t **out, dc_context_t *context, const cha
device->port = NULL; device->port = NULL;
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (1200 8N2). // Set the serial communication protocol (1200 8N2).
rc = serial_configure (device->port, 1200, 8, SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 1200, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (1000ms). // Set the timeout for receiving data (1000ms).
if (serial_set_timeout (device->port, 1000) == -1) { status = dc_serial_set_timeout (device->port, 1000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Clear the RTS line. // Clear the RTS line.
if (serial_set_rts (device->port, 0)) { status = dc_serial_set_rts (device->port, 0);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the DTR/RTS line."); ERROR (context, "Failed to set the DTR/RTS line.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
@ -117,7 +110,7 @@ suunto_solution_device_open (dc_device_t **out, dc_context_t *context, const cha
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -129,10 +122,12 @@ suunto_solution_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
suunto_solution_device_t *device = (suunto_solution_device_t*) abstract; suunto_solution_device_t *device = (suunto_solution_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -142,6 +137,7 @@ suunto_solution_device_close (dc_device_t *abstract)
static dc_status_t static dc_status_t
suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
suunto_solution_device_t *device = (suunto_solution_device_t*) abstract; suunto_solution_device_t *device = (suunto_solution_device_t*) abstract;
// Erase the current contents of the buffer and // Erase the current contents of the buffer and
@ -158,20 +154,20 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
progress.maximum = SZ_MEMORY - 1 + 2; progress.maximum = SZ_MEMORY - 1 + 2;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
int n = 0;
unsigned char command[3] = {0}; unsigned char command[3] = {0};
unsigned char answer[3] = {0}; unsigned char answer[3] = {0};
// Assert DTR // Assert DTR
serial_set_dtr (device->port, 1); dc_serial_set_dtr (device->port, 1);
// Send: 0xFF // Send: 0xFF
command[0] = 0xFF; command[0] = 0xFF;
serial_write (device->port, command, 1); dc_serial_write (device->port, command, 1, NULL);
// Receive: 0x3F // Receive: 0x3F
n = serial_read (device->port, answer, 1); status = dc_serial_read (device->port, answer, 1, NULL);
if (n != 1) return EXITCODE (n); if (status != DC_STATUS_SUCCESS)
return status;
if (answer[0] != 0x3F) if (answer[0] != 0x3F)
WARNING (abstract->context, "Unexpected answer byte."); WARNING (abstract->context, "Unexpected answer byte.");
@ -179,7 +175,7 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
command[0] = 0x4D; command[0] = 0x4D;
command[1] = 0x01; command[1] = 0x01;
command[2] = 0x01; command[2] = 0x01;
serial_write (device->port, command, 3); dc_serial_write (device->port, command, 3, NULL);
// Update and emit a progress event. // Update and emit a progress event.
progress.current += 1; progress.current += 1;
@ -188,24 +184,26 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
data[0] = 0x00; data[0] = 0x00;
for (unsigned int i = 1; i < SZ_MEMORY; ++i) { for (unsigned int i = 1; i < SZ_MEMORY; ++i) {
// Receive: 0x01, i, data[i] // Receive: 0x01, i, data[i]
n = serial_read (device->port, answer, 3); status = dc_serial_read (device->port, answer, 3, NULL);
if (n != 3) return EXITCODE (n); if (status != DC_STATUS_SUCCESS)
return status;
if (answer[0] != 0x01 || answer[1] != i) if (answer[0] != 0x01 || answer[1] != i)
WARNING (abstract->context, "Unexpected answer byte."); WARNING (abstract->context, "Unexpected answer byte.");
// Send: i // Send: i
command[0] = i; command[0] = i;
serial_write (device->port, command, 1); dc_serial_write (device->port, command, 1, NULL);
// Receive: data[i] // Receive: data[i]
n = serial_read (device->port, data + i, 1); status = dc_serial_read (device->port, data + i, 1, NULL);
if (n != 1) return EXITCODE (n); if (status != DC_STATUS_SUCCESS)
return status;
if (data[i] != answer[2]) if (data[i] != answer[2])
WARNING (abstract->context, "Unexpected answer byte."); WARNING (abstract->context, "Unexpected answer byte.");
// Send: 0x0D // Send: 0x0D
command[0] = 0x0D; command[0] = 0x0D;
serial_write (device->port, command, 1); dc_serial_write (device->port, command, 1, NULL);
// Update and emit a progress event. // Update and emit a progress event.
progress.current += 1; progress.current += 1;
@ -213,28 +211,31 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
} }
// Receive: 0x02, 0x00, 0x80 // Receive: 0x02, 0x00, 0x80
n = serial_read (device->port, answer, 3); status = dc_serial_read (device->port, answer, 3, NULL);
if (n != 3) return EXITCODE (n); if (status != DC_STATUS_SUCCESS)
return status;
if (answer[0] != 0x02 || answer[1] != 0x00 || answer[2] != 0x80) if (answer[0] != 0x02 || answer[1] != 0x00 || answer[2] != 0x80)
WARNING (abstract->context, "Unexpected answer byte."); WARNING (abstract->context, "Unexpected answer byte.");
// Send: 0x80 // Send: 0x80
command[0] = 0x80; command[0] = 0x80;
serial_write (device->port, command, 1); dc_serial_write (device->port, command, 1, NULL);
// Receive: 0x80 // Receive: 0x80
n = serial_read (device->port, answer, 1); status = dc_serial_read (device->port, answer, 1, NULL);
if (n != 1) return EXITCODE (n); if (status != DC_STATUS_SUCCESS)
return status;
if (answer[0] != 0x80) if (answer[0] != 0x80)
WARNING (abstract->context, "Unexpected answer byte."); WARNING (abstract->context, "Unexpected answer byte.");
// Send: 0x20 // Send: 0x20
command[0] = 0x20; command[0] = 0x20;
serial_write (device->port, command, 1); dc_serial_write (device->port, command, 1, NULL);
// Receive: 0x3F // Receive: 0x3F
n = serial_read (device->port, answer, 1); status = dc_serial_read (device->port, answer, 1, NULL);
if (n != 1) return EXITCODE (n); if (status != DC_STATUS_SUCCESS)
return status;
if (answer[0] != 0x3F) if (answer[0] != 0x3F)
WARNING (abstract->context, "Unexpected answer byte."); WARNING (abstract->context, "Unexpected answer byte.");

View File

@ -34,11 +34,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &suunto_vyper_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &suunto_vyper_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MAX(a,b) (((a) > (b)) ? (a) : (b))
@ -52,7 +47,7 @@
typedef struct suunto_vyper_device_t { typedef struct suunto_vyper_device_t {
suunto_common_device_t base; suunto_common_device_t base;
serial_t *port; dc_serial_t *port;
} suunto_vyper_device_t; } suunto_vyper_device_t;
static dc_status_t suunto_vyper_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); static dc_status_t suunto_vyper_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size);
@ -112,47 +107,45 @@ suunto_vyper_device_open (dc_device_t **out, dc_context_t *context, const char *
device->port = NULL; device->port = NULL;
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status= DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (2400 8O1). // Set the serial communication protocol (2400 8O1).
rc = serial_configure (device->port, 2400, 8, SERIAL_PARITY_ODD, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 2400, 8, DC_PARITY_ODD, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (1000 ms). // Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->port, 1000) == -1) { status = dc_serial_set_timeout (device->port, 1000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the DTR line (power supply for the interface). // Set the DTR line (power supply for the interface).
if (serial_set_dtr (device->port, 1) == -1) { status = dc_serial_set_dtr (device->port, 1);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the DTR line."); ERROR (context, "Failed to set the DTR line.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Give the interface 100 ms to settle and draw power up. // Give the interface 100 ms to settle and draw power up.
serial_sleep (device->port, 100); dc_serial_sleep (device->port, 100);
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
*out = (dc_device_t*) device; *out = (dc_device_t*) device;
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -164,10 +157,12 @@ suunto_vyper_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
suunto_vyper_device_t *device = (suunto_vyper_device_t*) abstract; suunto_vyper_device_t *device = (suunto_vyper_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -177,18 +172,19 @@ suunto_vyper_device_close (dc_device_t *abstract)
static dc_status_t static dc_status_t
suunto_vyper_send (suunto_vyper_device_t *device, const unsigned char command[], unsigned int csize) suunto_vyper_send (suunto_vyper_device_t *device, const unsigned char command[], unsigned int csize)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
serial_sleep (device->port, 500); dc_serial_sleep (device->port, 500);
// Set RTS to send the command. // Set RTS to send the command.
serial_set_rts (device->port, 1); dc_serial_set_rts (device->port, 1);
// Send the command to the dive computer. // Send the command to the dive computer.
int n = serial_write (device->port, command, csize); status = dc_serial_write (device->port, command, csize, NULL);
if (n != csize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// If the interface sends an echo back (which is the case for many clone // If the interface sends an echo back (which is the case for many clone
@ -202,11 +198,11 @@ suunto_vyper_send (suunto_vyper_device_t *device, const unsigned char command[],
// receive the reply before RTS is cleared. We have to wait some time // receive the reply before RTS is cleared. We have to wait some time
// before clearing RTS (around 30ms). But if we wait too long (> 500ms), // before clearing RTS (around 30ms). But if we wait too long (> 500ms),
// the reply disappears again. // the reply disappears again.
serial_sleep (device->port, 200); dc_serial_sleep (device->port, 200);
serial_flush (device->port, SERIAL_QUEUE_INPUT); dc_serial_purge (device->port, DC_DIRECTION_INPUT);
// Clear RTS to receive the reply. // Clear RTS to receive the reply.
serial_set_rts (device->port, 0); dc_serial_set_rts (device->port, 0);
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
} }
@ -215,10 +211,11 @@ suunto_vyper_send (suunto_vyper_device_t *device, const unsigned char command[],
static dc_status_t static dc_status_t
suunto_vyper_transfer (suunto_vyper_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size) suunto_vyper_transfer (suunto_vyper_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size)
{ {
assert (asize >= size + 2); dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
assert (asize >= size + 2);
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
@ -230,10 +227,10 @@ suunto_vyper_transfer (suunto_vyper_device_t *device, const unsigned char comman
} }
// Receive the answer of the dive computer. // Receive the answer of the dive computer.
int n = serial_read (device->port, answer, asize); status = dc_serial_read (device->port, answer, asize, NULL);
if (n != asize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the header of the package. // Verify the header of the package.
@ -329,6 +326,7 @@ suunto_vyper_device_write (dc_device_t *abstract, unsigned int address, const un
static dc_status_t static dc_status_t
suunto_vyper_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init, dc_event_progress_t *progress) suunto_vyper_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init, dc_event_progress_t *progress)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
suunto_vyper_device_t *device = (suunto_vyper_device_t*) abstract; suunto_vyper_device_t *device = (suunto_vyper_device_t*) abstract;
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
@ -352,9 +350,10 @@ suunto_vyper_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init, dc
unsigned int nbytes = 0; unsigned int nbytes = 0;
for (unsigned int npackages = 0;; ++npackages) { for (unsigned int npackages = 0;; ++npackages) {
// Receive the header of the package. // Receive the header of the package.
size_t n = 0;
unsigned char answer[SZ_PACKET + 3] = {0}; unsigned char answer[SZ_PACKET + 3] = {0};
int n = serial_read (device->port, answer, 2); status = dc_serial_read (device->port, answer, 2, &n);
if (n != 2) { if (status != DC_STATUS_SUCCESS) {
// If no data is received because a timeout occured, we assume // If no data is received because a timeout occured, we assume
// the last package was already received and the transmission // the last package was already received and the transmission
// can be finished. Unfortunately this is not 100% reliable, // can be finished. Unfortunately this is not 100% reliable,
@ -366,7 +365,7 @@ suunto_vyper_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init, dc
if (n == 0 && npackages != 0) if (n == 0 && npackages != 0)
break; break;
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the header of the package. // Verify the header of the package.
@ -378,10 +377,10 @@ suunto_vyper_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init, dc
// Receive the remaining part of the package. // Receive the remaining part of the package.
unsigned char len = answer[1]; unsigned char len = answer[1];
n = serial_read (device->port, answer + 2, len + 1); status = dc_serial_read (device->port, answer + 2, len + 1, NULL);
if (n != len + 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the checksum of the package. // Verify the checksum of the package.

View File

@ -32,16 +32,11 @@
#define ISINSTANCE(device) dc_device_isinstance((device), (const dc_device_vtable_t *) &suunto_vyper2_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), (const dc_device_vtable_t *) &suunto_vyper2_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define HELO2 0x15 #define HELO2 0x15
typedef struct suunto_vyper2_device_t { typedef struct suunto_vyper2_device_t {
suunto_common2_device_t base; suunto_common2_device_t base;
serial_t *port; dc_serial_t *port;
} suunto_vyper2_device_t; } suunto_vyper2_device_t;
static dc_status_t suunto_vyper2_device_packet (dc_device_t *abstract, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size); static dc_status_t suunto_vyper2_device_packet (dc_device_t *abstract, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size);
@ -101,43 +96,41 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char
device->port = NULL; device->port = NULL;
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (9600 8N1). // Set the serial communication protocol (9600 8N1).
rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (3000 ms). // Set the timeout for receiving data (3000 ms).
if (serial_set_timeout (device->port, 3000) == -1) { status = dc_serial_set_timeout (device->port, 3000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the DTR line (power supply for the interface). // Set the DTR line (power supply for the interface).
if (serial_set_dtr (device->port, 1) == -1) { status = dc_serial_set_dtr (device->port, 1);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the DTR line."); ERROR (context, "Failed to set the DTR line.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Give the interface 100 ms to settle and draw power up. // Give the interface 100 ms to settle and draw power up.
serial_sleep (device->port, 100); dc_serial_sleep (device->port, 100);
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
// Enable half-duplex emulation. // Enable half-duplex emulation.
serial_set_halfduplex (device->port, 1); dc_serial_set_halfduplex (device->port, 1);
// Read the version info. // Read the version info.
status = suunto_common2_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version)); status = suunto_common2_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version));
@ -158,7 +151,7 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -170,10 +163,12 @@ suunto_vyper2_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
suunto_vyper2_device_t *device = (suunto_vyper2_device_t*) abstract; suunto_vyper2_device_t *device = (suunto_vyper2_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -183,31 +178,32 @@ suunto_vyper2_device_close (dc_device_t *abstract)
static dc_status_t static dc_status_t
suunto_vyper2_device_packet (dc_device_t *abstract, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size) suunto_vyper2_device_packet (dc_device_t *abstract, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
suunto_vyper2_device_t *device = (suunto_vyper2_device_t *) abstract; suunto_vyper2_device_t *device = (suunto_vyper2_device_t *) abstract;
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
serial_sleep (device->port, 600); dc_serial_sleep (device->port, 600);
// Set RTS to send the command. // Set RTS to send the command.
serial_set_rts (device->port, 1); dc_serial_set_rts (device->port, 1);
// Send the command to the dive computer. // Send the command to the dive computer.
int n = serial_write (device->port, command, csize); status = dc_serial_write (device->port, command, csize, NULL);
if (n != csize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Clear RTS to receive the reply. // Clear RTS to receive the reply.
serial_set_rts (device->port, 0); dc_serial_set_rts (device->port, 0);
// Receive the answer of the dive computer. // Receive the answer of the dive computer.
n = serial_read (device->port, answer, asize); status = dc_serial_read (device->port, answer, asize, NULL);
if (n != asize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the header of the package. // Verify the header of the package.

View File

@ -33,11 +33,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &uwatec_aladin_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &uwatec_aladin_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define SZ_MEMORY 2048 #define SZ_MEMORY 2048
#define RB_PROFILE_BEGIN 0x000 #define RB_PROFILE_BEGIN 0x000
@ -49,7 +44,7 @@
typedef struct uwatec_aladin_device_t { typedef struct uwatec_aladin_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
unsigned int timestamp; unsigned int timestamp;
unsigned int devtime; unsigned int devtime;
dc_ticks_t systime; dc_ticks_t systime;
@ -95,33 +90,37 @@ uwatec_aladin_device_open (dc_device_t **out, dc_context_t *context, const char
device->devtime = 0; device->devtime = 0;
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (19200 8N1). // Set the serial communication protocol (19200 8N1).
rc = serial_configure (device->port, 19200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 19200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (INFINITE). // Set the timeout for receiving data (INFINITE).
if (serial_set_timeout (device->port, -1) == -1) { status = dc_serial_set_timeout (device->port, -1);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Clear the RTS line and set the DTR line. // Set the DTR line.
if (serial_set_dtr (device->port, 1) == -1 || status = dc_serial_set_dtr (device->port, 1);
serial_set_rts (device->port, 0) == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the DTR/RTS line."); ERROR (context, "Failed to set the DTR line.");
status = DC_STATUS_IO; goto error_close;
}
// Clear the RTS line.
status = dc_serial_set_rts (device->port, 0);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to clear the RTS line.");
goto error_close; goto error_close;
} }
@ -130,7 +129,7 @@ uwatec_aladin_device_open (dc_device_t **out, dc_context_t *context, const char
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -142,10 +141,12 @@ uwatec_aladin_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
uwatec_aladin_device_t *device = (uwatec_aladin_device_t*) abstract; uwatec_aladin_device_t *device = (uwatec_aladin_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -172,6 +173,7 @@ uwatec_aladin_device_set_fingerprint (dc_device_t *abstract, const unsigned char
static dc_status_t static dc_status_t
uwatec_aladin_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) uwatec_aladin_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
uwatec_aladin_device_t *device = (uwatec_aladin_device_t*) abstract; uwatec_aladin_device_t *device = (uwatec_aladin_device_t*) abstract;
// Erase the current contents of the buffer and // Erase the current contents of the buffer and
@ -193,10 +195,10 @@ uwatec_aladin_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
int rc = serial_read (device->port, answer + i, 1); status = dc_serial_read (device->port, answer + i, 1, NULL);
if (rc != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (rc); return status;
} }
if (answer[i] == (i < 3 ? 0x55 : 0x00)) { if (answer[i] == (i < 3 ? 0x55 : 0x00)) {
i++; // Continue. i++; // Continue.
@ -214,10 +216,10 @@ uwatec_aladin_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
// Receive the remaining part of the package. // Receive the remaining part of the package.
int rc = serial_read (device->port, answer + 4, sizeof (answer) - 4); status = dc_serial_read (device->port, answer + 4, sizeof (answer) - 4, NULL);
if (rc != sizeof (answer) - 4) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Unexpected EOF in answer."); ERROR (abstract->context, "Unexpected EOF in answer.");
return EXITCODE (rc); return status;
} }
// Update and emit a progress event. // Update and emit a progress event.

View File

@ -33,11 +33,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &uwatec_memomouse_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &uwatec_memomouse_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define PACKETSIZE 126 #define PACKETSIZE 126
#define ACK 0x60 #define ACK 0x60
@ -45,7 +40,7 @@
typedef struct uwatec_memomouse_device_t { typedef struct uwatec_memomouse_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
unsigned int timestamp; unsigned int timestamp;
unsigned int devtime; unsigned int devtime;
dc_ticks_t systime; dc_ticks_t systime;
@ -91,45 +86,49 @@ uwatec_memomouse_device_open (dc_device_t **out, dc_context_t *context, const ch
device->devtime = 0; device->devtime = 0;
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (9600 8N1). // Set the serial communication protocol (9600 8N1).
rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (1000 ms). // Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->port, 1000) == -1) { status = dc_serial_set_timeout (device->port, 1000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Clear the RTS and DTR lines. // Clear the DTR line.
if (serial_set_rts (device->port, 0) == -1 || status = dc_serial_set_dtr (device->port, 0);
serial_set_dtr (device->port, 0) == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the DTR/RTS line."); ERROR (context, "Failed to clear the DTR line.");
status = DC_STATUS_IO; goto error_close;
}
// Clear the RTS line.
status = dc_serial_set_rts (device->port, 0);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to clear the RTS line.");
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
*out = (dc_device_t*) device; *out = (dc_device_t*) device;
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -141,10 +140,12 @@ uwatec_memomouse_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
uwatec_memomouse_device_t *device = (uwatec_memomouse_device_t*) abstract; uwatec_memomouse_device_t *device = (uwatec_memomouse_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -171,15 +172,16 @@ uwatec_memomouse_device_set_fingerprint (dc_device_t *abstract, const unsigned c
static dc_status_t static dc_status_t
uwatec_memomouse_read_packet (uwatec_memomouse_device_t *device, unsigned char data[], unsigned int size, unsigned int *result) uwatec_memomouse_read_packet (uwatec_memomouse_device_t *device, unsigned char data[], unsigned int size, unsigned int *result)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
assert (result != NULL); assert (result != NULL);
// Receive the header of the package. // Receive the header of the package.
int rc = serial_read (device->port, data, 1); status = dc_serial_read (device->port, data, 1, NULL);
if (rc != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (rc); return status;
} }
// Reverse the bits. // Reverse the bits.
@ -193,10 +195,10 @@ uwatec_memomouse_read_packet (uwatec_memomouse_device_t *device, unsigned char d
} }
// Receive the remaining part of the package. // Receive the remaining part of the package.
rc = serial_read (device->port, data + 1, len + 1); status = dc_serial_read (device->port, data + 1, len + 1, NULL);
if (rc != len + 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (rc); return status;
} }
// Reverse the bits. // Reverse the bits.
@ -219,6 +221,7 @@ uwatec_memomouse_read_packet (uwatec_memomouse_device_t *device, unsigned char d
static dc_status_t static dc_status_t
uwatec_memomouse_read_packet_outer (uwatec_memomouse_device_t *device, unsigned char data[], unsigned int size, unsigned int *result) uwatec_memomouse_read_packet_outer (uwatec_memomouse_device_t *device, unsigned char data[], unsigned int size, unsigned int *result)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
dc_status_t rc = DC_STATUS_SUCCESS; dc_status_t rc = DC_STATUS_SUCCESS;
@ -229,14 +232,14 @@ uwatec_memomouse_read_packet_outer (uwatec_memomouse_device_t *device, unsigned
return rc; return rc;
// Flush the input buffer. // Flush the input buffer.
serial_flush (device->port, SERIAL_QUEUE_INPUT); dc_serial_purge (device->port, DC_DIRECTION_INPUT);
// Reject the packet. // Reject the packet.
unsigned char value = NAK; unsigned char value = NAK;
int n = serial_write (device->port, &value, 1); status = dc_serial_write (device->port, &value, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to reject the packet."); ERROR (abstract->context, "Failed to reject the packet.");
return EXITCODE (n); return status;
} }
} }
@ -247,6 +250,7 @@ uwatec_memomouse_read_packet_outer (uwatec_memomouse_device_t *device, unsigned
static dc_status_t static dc_status_t
uwatec_memomouse_read_packet_inner (uwatec_memomouse_device_t *device, dc_buffer_t *buffer, dc_event_progress_t *progress) uwatec_memomouse_read_packet_inner (uwatec_memomouse_device_t *device, dc_buffer_t *buffer, dc_event_progress_t *progress)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
// Erase the current contents of the buffer. // Erase the current contents of the buffer.
@ -271,10 +275,10 @@ uwatec_memomouse_read_packet_inner (uwatec_memomouse_device_t *device, dc_buffer
// Accept the packet. // Accept the packet.
unsigned char value = ACK; unsigned char value = ACK;
int n = serial_write (device->port, &value, 1); status = dc_serial_write (device->port, &value, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to accept the packet."); ERROR (abstract->context, "Failed to accept the packet.");
return EXITCODE (n); return status;
} }
if (nbytes == 0) { if (nbytes == 0) {
@ -329,29 +333,31 @@ uwatec_memomouse_read_packet_inner (uwatec_memomouse_device_t *device, dc_buffer
static dc_status_t static dc_status_t
uwatec_memomouse_dump_internal (uwatec_memomouse_device_t *device, dc_buffer_t *buffer) uwatec_memomouse_dump_internal (uwatec_memomouse_device_t *device, dc_buffer_t *buffer)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
size_t available = 0;
// Enable progress notifications. // Enable progress notifications.
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
device_event_emit (&device->base, DC_EVENT_PROGRESS, &progress); device_event_emit (&device->base, DC_EVENT_PROGRESS, &progress);
// Waiting for greeting message. // Waiting for greeting message.
while (serial_get_received (device->port) == 0) { while (dc_serial_get_available (device->port, &available) == DC_STATUS_SUCCESS && available == 0) {
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
// Flush the input buffer. // Flush the input buffer.
serial_flush (device->port, SERIAL_QUEUE_INPUT); dc_serial_purge (device->port, DC_DIRECTION_INPUT);
// Reject the packet. // Reject the packet.
unsigned char value = NAK; unsigned char value = NAK;
int n = serial_write (device->port, &value, 1); status = dc_serial_write (device->port, &value, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to reject the packet."); ERROR (abstract->context, "Failed to reject the packet.");
return EXITCODE (n); return status;
} }
serial_sleep (device->port, 300); dc_serial_sleep (device->port, 300);
} }
// Read the ID string. // Read the ID string.
@ -374,27 +380,27 @@ uwatec_memomouse_dump_internal (uwatec_memomouse_device_t *device, dc_buffer_t *
// Wait a small amount of time before sending the command. // Wait a small amount of time before sending the command.
// Without this delay, the transfer will fail most of the time. // Without this delay, the transfer will fail most of the time.
serial_sleep (device->port, 50); dc_serial_sleep (device->port, 50);
// Keep send the command to the device, // Keep send the command to the device,
// until the ACK answer is received. // until the ACK answer is received.
unsigned char answer = NAK; unsigned char answer = NAK;
while (answer == NAK) { while (answer == NAK) {
// Flush the input buffer. // Flush the input buffer.
serial_flush (device->port, SERIAL_QUEUE_INPUT); dc_serial_purge (device->port, DC_DIRECTION_INPUT);
// Send the command to the device. // Send the command to the device.
int n = serial_write (device->port, command, sizeof (command)); status = dc_serial_write (device->port, command, sizeof (command), NULL);
if (n != sizeof (command)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Wait for the answer (ACK). // Wait for the answer (ACK).
n = serial_read (device->port, &answer, 1); status = dc_serial_read (device->port, &answer, 1, NULL);
if (n != 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
} }
@ -405,12 +411,12 @@ uwatec_memomouse_dump_internal (uwatec_memomouse_device_t *device, dc_buffer_t *
} }
// Wait for the data packet. // Wait for the data packet.
while (serial_get_received (device->port) == 0) { while (dc_serial_get_available (device->port, &available) == DC_STATUS_SUCCESS && available == 0) {
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
device_event_emit (&device->base, DC_EVENT_WAITING, NULL); device_event_emit (&device->base, DC_EVENT_WAITING, NULL);
serial_sleep (device->port, 100); dc_serial_sleep (device->port, 100);
} }
// Fetch the current system time. // Fetch the current system time.
@ -438,7 +444,9 @@ uwatec_memomouse_dump_internal (uwatec_memomouse_device_t *device, dc_buffer_t *
static dc_status_t static dc_status_t
uwatec_memomouse_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) uwatec_memomouse_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
uwatec_memomouse_device_t *device = (uwatec_memomouse_device_t*) abstract; uwatec_memomouse_device_t *device = (uwatec_memomouse_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Erase the current contents of the buffer. // Erase the current contents of the buffer.
if (!dc_buffer_clear (buffer)) { if (!dc_buffer_clear (buffer)) {
@ -448,24 +456,26 @@ uwatec_memomouse_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
// Give the interface some time to notice the DTR // Give the interface some time to notice the DTR
// line change from a previous transfer (if any). // line change from a previous transfer (if any).
serial_sleep (device->port, 500); dc_serial_sleep (device->port, 500);
// Set the DTR line. // Set the DTR line.
if (serial_set_dtr (device->port, 1) == -1) { rc = dc_serial_set_dtr (device->port, 1);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to set the RTS line."); ERROR (abstract->context, "Failed to set the RTS line.");
return DC_STATUS_IO; return rc;
} }
// Start the transfer. // Start the transfer.
dc_status_t rc = uwatec_memomouse_dump_internal (device, buffer); status = uwatec_memomouse_dump_internal (device, buffer);
// Clear the DTR line again. // Clear the DTR line again.
if (serial_set_dtr (device->port, 0) == -1) { rc = dc_serial_set_dtr (device->port, 0);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to set the RTS line."); ERROR (abstract->context, "Failed to set the RTS line.");
return DC_STATUS_IO; return rc;
} }
return rc; return status;
} }

View File

@ -33,17 +33,12 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &uwatec_meridian_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &uwatec_meridian_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define ACK 0x11 #define ACK 0x11
#define NAK 0x66 #define NAK 0x66
typedef struct uwatec_meridian_device_t { typedef struct uwatec_meridian_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
unsigned int timestamp; unsigned int timestamp;
unsigned int devtime; unsigned int devtime;
dc_ticks_t systime; dc_ticks_t systime;
@ -69,6 +64,7 @@ static const dc_device_vtable_t uwatec_meridian_device_vtable = {
static dc_status_t static dc_status_t
uwatec_meridian_transfer (uwatec_meridian_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) uwatec_meridian_transfer (uwatec_meridian_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
assert (csize > 0 && csize <= 255); assert (csize > 0 && csize <= 255);
@ -85,18 +81,18 @@ uwatec_meridian_transfer (uwatec_meridian_device_t *device, const unsigned char
packet[11 + csize] = checksum_xor_uint8 (packet + 7, csize + 4, 0x00); packet[11 + csize] = checksum_xor_uint8 (packet + 7, csize + 4, 0x00);
// Send the packet. // Send the packet.
int n = serial_write (device->port, packet, csize + 12); status = dc_serial_write (device->port, packet, csize + 12, NULL);
if (n != csize + 12) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Read the echo. // Read the echo.
unsigned char echo[sizeof(packet)]; unsigned char echo[sizeof(packet)];
n = serial_read (device->port, echo, csize + 12); status = dc_serial_read (device->port, echo, csize + 12, NULL);
if (n != csize + 12) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the echo."); ERROR (abstract->context, "Failed to receive the echo.");
return EXITCODE (n); return status;
} }
// Verify the echo. // Verify the echo.
@ -107,10 +103,10 @@ uwatec_meridian_transfer (uwatec_meridian_device_t *device, const unsigned char
// Read the header. // Read the header.
unsigned char header[6]; unsigned char header[6];
n = serial_read (device->port, header, sizeof (header)); status = dc_serial_read (device->port, header, sizeof (header), NULL);
if (n != sizeof (header)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the header."); ERROR (abstract->context, "Failed to receive the header.");
return EXITCODE (n); return status;
} }
// Verify the header. // Verify the header.
@ -120,18 +116,18 @@ uwatec_meridian_transfer (uwatec_meridian_device_t *device, const unsigned char
} }
// Read the packet. // Read the packet.
n = serial_read (device->port, answer, asize); status = dc_serial_read (device->port, answer, asize, NULL);
if (n != asize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the packet."); ERROR (abstract->context, "Failed to receive the packet.");
return EXITCODE (n); return status;
} }
// Read the checksum. // Read the checksum.
unsigned char csum = 0x00; unsigned char csum = 0x00;
n = serial_read (device->port, &csum, sizeof (csum)); status = dc_serial_read (device->port, &csum, sizeof (csum), NULL);
if (n != sizeof (csum)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the checksum."); ERROR (abstract->context, "Failed to receive the checksum.");
return EXITCODE (n); return status;
} }
// Verify the checksum. // Verify the checksum.
@ -207,30 +203,28 @@ uwatec_meridian_device_open (dc_device_t **out, dc_context_t *context, const cha
device->devtime = 0; device->devtime = 0;
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (57600 8N1). // Set the serial communication protocol (57600 8N1).
rc = serial_configure (device->port, 57600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 57600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (3000ms). // Set the timeout for receiving data (3000ms).
if (serial_set_timeout (device->port, 3000) == -1) { status = dc_serial_set_timeout (device->port, 3000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
// Perform the handshaking. // Perform the handshaking.
uwatec_meridian_handshake (device); uwatec_meridian_handshake (device);
@ -240,7 +234,7 @@ uwatec_meridian_device_open (dc_device_t **out, dc_context_t *context, const cha
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -252,10 +246,12 @@ uwatec_meridian_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
uwatec_meridian_device_t *device = (uwatec_meridian_device_t*) abstract; uwatec_meridian_device_t *device = (uwatec_meridian_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -282,6 +278,7 @@ uwatec_meridian_device_set_fingerprint (dc_device_t *abstract, const unsigned ch
static dc_status_t static dc_status_t
uwatec_meridian_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) uwatec_meridian_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
uwatec_meridian_device_t *device = (uwatec_meridian_device_t*) abstract; uwatec_meridian_device_t *device = (uwatec_meridian_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS; dc_status_t rc = DC_STATUS_SUCCESS;
@ -395,10 +392,10 @@ uwatec_meridian_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
// Read the header. // Read the header.
unsigned char header[5]; unsigned char header[5];
int n = serial_read (device->port, header, sizeof (header)); status = dc_serial_read (device->port, header, sizeof (header), NULL);
if (n != sizeof (header)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the header."); ERROR (abstract->context, "Failed to receive the header.");
return EXITCODE (n); return status;
} }
// Get the packet size. // Get the packet size.
@ -409,18 +406,18 @@ uwatec_meridian_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
} }
// Read the packet data. // Read the packet data.
n = serial_read (device->port, data + nbytes, packetsize - 1); status = dc_serial_read (device->port, data + nbytes, packetsize - 1, NULL);
if (n != packetsize - 1) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the packet."); ERROR (abstract->context, "Failed to receive the packet.");
return EXITCODE (n); return status;
} }
// Read the checksum. // Read the checksum.
unsigned char csum = 0x00; unsigned char csum = 0x00;
n = serial_read (device->port, &csum, sizeof (csum)); status = dc_serial_read (device->port, &csum, sizeof (csum), NULL);
if (n != sizeof (csum)) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the checksum."); ERROR (abstract->context, "Failed to receive the checksum.");
return EXITCODE (n); return status;
} }
// Verify the checksum. // Verify the checksum.

View File

@ -31,14 +31,9 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &uwatec_smart_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &uwatec_smart_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
typedef struct uwatec_smart_device_t { typedef struct uwatec_smart_device_t {
dc_device_t base; dc_device_t base;
irda_t *socket; dc_irda_t *socket;
unsigned int address; unsigned int address;
unsigned int timestamp; unsigned int timestamp;
unsigned int devtime; unsigned int devtime;
@ -88,18 +83,19 @@ uwatec_smart_discovery (unsigned int address, const char *name, unsigned int cha
static dc_status_t static dc_status_t
uwatec_smart_transfer (uwatec_smart_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) uwatec_smart_transfer (uwatec_smart_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
int n = irda_socket_write (device->socket, command, csize); status = dc_irda_write (device->socket, command, csize, NULL);
if (n != csize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
n = irda_socket_read (device->socket, answer, asize); status = dc_irda_read (device->socket, answer, asize, NULL);
if (n != asize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
@ -167,18 +163,16 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context)
device->devtime = 0; device->devtime = 0;
// Open the irda socket. // Open the irda socket.
int rc = irda_socket_open (&device->socket, context); status = dc_irda_open (&device->socket, context);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the irda socket."); ERROR (context, "Failed to open the irda socket.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Discover the device. // Discover the device.
rc = irda_socket_discover (device->socket, uwatec_smart_discovery, device); status = dc_irda_discover (device->socket, uwatec_smart_discovery, device);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to discover the device."); ERROR (context, "Failed to discover the device.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
@ -189,10 +183,9 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context)
} }
// Connect the device. // Connect the device.
rc = irda_socket_connect_lsap (device->socket, device->address, 1); status = dc_irda_connect_lsap (device->socket, device->address, 1);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to connect the device."); ERROR (context, "Failed to connect the device.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
@ -204,7 +197,7 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context)
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
irda_socket_close (device->socket); dc_irda_close (device->socket);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -216,10 +209,12 @@ uwatec_smart_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
uwatec_smart_device_t *device = (uwatec_smart_device_t*) abstract; uwatec_smart_device_t *device = (uwatec_smart_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (irda_socket_close (device->socket) == -1) { rc = dc_irda_close (device->socket);
dc_status_set_error(&status, DC_STATUS_IO); if (status != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;
@ -360,25 +355,26 @@ uwatec_smart_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
unsigned int len = 32; unsigned int len = 32;
// Increase the packet size if more data is immediately available. // Increase the packet size if more data is immediately available.
int available = irda_socket_available (device->socket); size_t available = 0;
if (available > len) rc = dc_irda_get_available (device->socket, &available);
if (rc == DC_STATUS_SUCCESS && available > len)
len = available; len = available;
// Limit the packet size to the total size. // Limit the packet size to the total size.
if (nbytes + len > length) if (nbytes + len > length)
len = length - nbytes; len = length - nbytes;
int n = irda_socket_read (device->socket, data + nbytes, len); rc = dc_irda_read (device->socket, data + nbytes, len, NULL);
if (n != len) { if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return rc;
} }
// Update and emit a progress event. // Update and emit a progress event.
progress.current += n; progress.current += len;
device_event_emit (&device->base, DC_EVENT_PROGRESS, &progress); device_event_emit (&device->base, DC_EVENT_PROGRESS, &progress);
nbytes += n; nbytes += len;
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;

View File

@ -34,11 +34,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &zeagle_n2ition3_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &zeagle_n2ition3_device_vtable)
#define EXITCODE(rc) \
( \
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define SZ_MEMORY 0x8000 #define SZ_MEMORY 0x8000
#define SZ_PACKET 64 #define SZ_PACKET 64
@ -51,7 +46,7 @@
typedef struct zeagle_n2ition3_device_t { typedef struct zeagle_n2ition3_device_t {
dc_device_t base; dc_device_t base;
serial_t *port; dc_serial_t *port;
unsigned char fingerprint[16]; unsigned char fingerprint[16];
} zeagle_n2ition3_device_t; } zeagle_n2ition3_device_t;
@ -76,6 +71,7 @@ static const dc_device_vtable_t zeagle_n2ition3_device_vtable = {
static dc_status_t static dc_status_t
zeagle_n2ition3_packet (zeagle_n2ition3_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) zeagle_n2ition3_packet (zeagle_n2ition3_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
assert (asize >= csize + 5); assert (asize >= csize + 5);
@ -84,17 +80,17 @@ zeagle_n2ition3_packet (zeagle_n2ition3_device_t *device, const unsigned char co
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
// Send the command to the device. // Send the command to the device.
int n = serial_write (device->port, command, csize); status = dc_serial_write (device->port, command, csize, NULL);
if (n != csize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command."); ERROR (abstract->context, "Failed to send the command.");
return EXITCODE (n); return status;
} }
// Receive the answer of the device. // Receive the answer of the device.
n = serial_read (device->port, answer, asize); status = dc_serial_read (device->port, answer, asize, NULL);
if (n != asize) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the answer."); ERROR (abstract->context, "Failed to receive the answer.");
return EXITCODE (n); return status;
} }
// Verify the echo. // Verify the echo.
@ -156,30 +152,28 @@ zeagle_n2ition3_device_open (dc_device_t **out, dc_context_t *context, const cha
memset (device->fingerprint, 0, sizeof (device->fingerprint)); memset (device->fingerprint, 0, sizeof (device->fingerprint));
// Open the device. // Open the device.
int rc = serial_open (&device->port, context, name); status = dc_serial_open (&device->port, context, name);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port."); ERROR (context, "Failed to open the serial port.");
status = DC_STATUS_IO;
goto error_free; goto error_free;
} }
// Set the serial communication protocol (4800 8N1). // Set the serial communication protocol (4800 8N1).
rc = serial_configure (device->port, 4800, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); status = dc_serial_configure (device->port, 4800, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (rc == -1) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Set the timeout for receiving data (1000 ms). // Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->port, 1000) == -1) { status = dc_serial_set_timeout (device->port, 1000);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
status = DC_STATUS_IO;
goto error_close; goto error_close;
} }
// Make sure everything is in a sane state. // Make sure everything is in a sane state.
serial_flush (device->port, SERIAL_QUEUE_BOTH); dc_serial_purge (device->port, DC_DIRECTION_ALL);
// Send the init commands. // Send the init commands.
zeagle_n2ition3_init (device); zeagle_n2ition3_init (device);
@ -189,7 +183,7 @@ zeagle_n2ition3_device_open (dc_device_t **out, dc_context_t *context, const cha
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_close: error_close:
serial_close (device->port); dc_serial_close (device->port);
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; return status;
@ -201,10 +195,12 @@ zeagle_n2ition3_device_close (dc_device_t *abstract)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
zeagle_n2ition3_device_t *device = (zeagle_n2ition3_device_t*) abstract; zeagle_n2ition3_device_t *device = (zeagle_n2ition3_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Close the device. // Close the device.
if (serial_close (device->port) == -1) { rc = dc_serial_close (device->port);
dc_status_set_error(&status, DC_STATUS_IO); if (rc != DC_STATUS_SUCCESS) {
dc_status_set_error(&status, rc);
} }
return status; return status;