Merge branch 'refactor'

This commit is contained in:
Jef Driesen 2016-05-10 20:22:07 +02:00
commit d1aa9478a4
39 changed files with 2203 additions and 1773 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,18 +39,31 @@
#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;
typedef DWORD s_errcode_t;
#define S_ERRNO WSAGetLastError () #define S_ERRNO WSAGetLastError ()
#define S_EAGAIN WSAEWOULDBLOCK #define S_EAGAIN WSAEWOULDBLOCK
#define S_ENOMEM WSA_NOT_ENOUGH_MEMORY
#define S_EINVAL WSAEINVAL
#define S_EACCES WSAEACCES
#define S_EAFNOSUPPORT WSAEAFNOSUPPORT
#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;
typedef int s_errcode_t;
#define S_ERRNO errno #define S_ERRNO errno
#define S_EAGAIN EAGAIN #define S_EAGAIN EAGAIN
#define S_ENOMEM ENOMEM
#define S_EINVAL EINVAL
#define S_EACCES EACCES
#define S_EAFNOSUPPORT EAFNOSUPPORT
#define S_INVALID -1 #define S_INVALID -1
#define S_IOCTL ioctl #define S_IOCTL ioctl
#define S_CLOSE close #define S_CLOSE close
@ -60,32 +73,47 @@
#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;
}; };
static dc_status_t
int syserror(s_errcode_t errcode)
irda_socket_open (irda_t **out, dc_context_t *context)
{ {
switch (errcode) {
case S_EINVAL:
return DC_STATUS_INVALIDARGS;
case S_ENOMEM:
return DC_STATUS_NOMEMORY;
case S_EACCES:
return DC_STATUS_NOACCESS;
case S_EAFNOSUPPORT:
return DC_STATUS_UNSUPPORTED;
default:
return DC_STATUS_IO;
}
}
dc_status_t
dc_irda_open (dc_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 SYSERROR (context, S_ENOMEM);
SYSERROR (context, ERROR_OUTOFMEMORY); return DC_STATUS_NOMEMORY;
#else
SYSERROR (context, ENOMEM);
#endif
return -1; // ENOMEM (Not enough space)
} }
// Library context. // Library context.
@ -101,6 +129,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 +139,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
@ -117,13 +147,15 @@ irda_socket_open (irda_t **out, dc_context_t *context)
// Open the socket. // Open the socket.
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); s_errcode_t errcode = S_ERRNO;
SYSERROR (context, errcode);
status = syserror(errcode);
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,53 +163,53 @@ 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);
// Close the socket. // Close the socket.
if (S_CLOSE (device->fd) != 0) { if (S_CLOSE (device->fd) != 0) {
SYSERROR (device->context, S_ERRNO); s_errcode_t errcode = S_ERRNO;
errcode = -1; SYSERROR (device->context, errcode);
dc_status_set_error(&status, syserror(errcode));
} }
#ifdef _WIN32 #ifdef _WIN32
// Terminate the winsock dll. // Terminate the winsock dll.
if (WSACleanup () != 0) { if (WSACleanup () != 0) {
SYSERROR (device->context, S_ERRNO); s_errcode_t errcode = S_ERRNO;
errcode = -1; SYSERROR (device->context, errcode);
dc_status_set_error(&status, syserror(errcode));
} }
#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 +224,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
@ -221,15 +253,16 @@ irda_socket_discover (irda_t *device, irda_callback_t callback, void *userdata)
// discovered, while on Windows it succeeds and sets the number // discovered, while on Windows it succeeds and sets the number
// of devices to zero. Both situations are handled the same here. // of devices to zero. Both situations are handled the same here.
if (rc != 0) { if (rc != 0) {
if (S_ERRNO != S_EAGAIN) { s_errcode_t errcode = S_ERRNO;
SYSERROR (device->context, S_ERRNO); if (errcode != S_EAGAIN) {
return -1; // Error during getsockopt call. SYSERROR (device->context, errcode);
return syserror(errcode);
} }
} }
// 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 +299,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 : "");
@ -300,18 +332,19 @@ irda_socket_connect_name (irda_t *device, unsigned int address, const char *name
#endif #endif
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); s_errcode_t errcode = S_ERRNO;
return -1; SYSERROR (device->context, errcode);
return syserror(errcode);
} }
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);
@ -332,19 +365,19 @@ irda_socket_connect_lsap (irda_t *device, unsigned int address, unsigned int lsa
#endif #endif
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); s_errcode_t errcode = S_ERRNO;
return -1; SYSERROR (device->context, errcode);
return syserror(errcode);
} }
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;
@ -353,19 +386,27 @@ irda_socket_available (irda_t *device)
#endif #endif
if (S_IOCTL (device->fd, FIONREAD, &bytes) != 0) { if (S_IOCTL (device->fd, FIONREAD, &bytes) != 0) {
SYSERROR (device->context, S_ERRNO); s_errcode_t errcode = S_ERRNO;
return -1; SYSERROR (device->context, errcode);
return syserror(errcode);
} }
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 +418,23 @@ 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); s_errcode_t errcode = S_ERRNO;
return -1; // Error during select call. SYSERROR (device->context, errcode);
status = syserror(errcode);
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); s_errcode_t errcode = S_ERRNO;
return -1; // Error during recv call. SYSERROR (device->context, errcode);
status = syserror(errcode);
goto out;
} else if (n == 0) { } else if (n == 0) {
break; // EOF reached. break; // EOF reached.
} }
@ -398,30 +442,51 @@ 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); s_errcode_t errcode = S_ERRNO;
return -1; // Error during send call. SYSERROR (device->context, errcode);
status = syserror(errcode);
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
@ -76,9 +77,26 @@ struct serial_t {
unsigned int nbits; unsigned int nbits;
}; };
static dc_status_t
syserror(int errcode)
{
switch (errcode) {
case EINVAL:
return DC_STATUS_INVALIDARGS;
case ENOMEM:
return DC_STATUS_NOMEMORY;
case ENOENT:
return DC_STATUS_NODEVICE;
case EACCES:
case EBUSY:
return DC_STATUS_NOACCESS;
default:
return DC_STATUS_IO;
}
}
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 +115,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 +125,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 +136,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.
@ -156,14 +171,18 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
// without waiting for the modem connection to complete. // without waiting for the modem connection to complete.
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); int errcode = errno;
SYSERROR (context, errcode);
status = syserror (errcode);
goto error_free; goto error_free;
} }
#ifndef ENABLE_PTY #ifndef ENABLE_PTY
// 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); int errcode = errno;
SYSERROR (context, errcode);
status = syserror (errcode);
goto error_close; goto error_close;
} }
#endif #endif
@ -173,37 +192,36 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
// It is also used to check if the obtained // It is also used to check if the obtained
// 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); int errcode = errno;
SYSERROR (context, errcode);
status = syserror (errcode);
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); int errcode = errno;
errcode = -1; SYSERROR (device->context, errcode);
dc_status_set_error(&status, syserror (errcode));
} }
#ifndef ENABLE_PTY #ifndef ENABLE_PTY
@ -213,25 +231,22 @@ 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); int errcode = errno;
errcode = -1; SYSERROR (device->context, errcode);
dc_status_set_error(&status, syserror (errcode));
} }
// 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);
@ -240,8 +255,9 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int
struct termios tty; struct termios tty;
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); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
// Setup raw input/output mode without echo. // Setup raw input/output mode without echo.
@ -336,8 +352,9 @@ 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); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
// Set the character size. // Set the character size.
@ -356,70 +373,85 @@ 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.
#ifdef CMSPAR
tty.c_cflag &= ~(PARENB | PARODD | CMSPAR);
#else
tty.c_cflag &= ~(PARENB | PARODD); tty.c_cflag &= ~(PARENB | PARODD);
#endif
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;
#ifdef CMSPAR
case DC_PARITY_MARK:
tty.c_cflag |= (PARENB | PARODD | CMSPAR);
tty.c_iflag |= INPCK;
break;
case DC_PARITY_SPACE:
tty.c_cflag |= (PARENB | CMSPAR);
tty.c_iflag |= INPCK;
break;
#endif
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); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
// Configure a custom baudrate if necessary. // Configure a custom baudrate if necessary.
@ -428,8 +460,9 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int
// 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); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
// Set the custom divisor. // Set the custom divisor.
@ -439,82 +472,66 @@ 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); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
#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); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
#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); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
// Set or clear the low latency flag. // Set or clear the low latency flag.
@ -526,8 +543,9 @@ 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); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
#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
@ -535,28 +553,33 @@ serial_set_latency (serial_t *device, unsigned int milliseconds)
// the hardware. A value of zero restores the default value. // the hardware. A value of zero restores the default value.
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); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
#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);
@ -566,8 +589,10 @@ serial_read (serial_t *device, void *data, unsigned int size)
if (timeout > 0) { if (timeout > 0) {
struct timeval now; struct timeval now;
if (gettimeofday (&now, NULL) != 0) { if (gettimeofday (&now, NULL) != 0) {
SYSERROR (device->context, errno); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
status = syserror (errcode);
goto out;
} }
if (init) { if (init) {
@ -590,20 +615,24 @@ serial_read (serial_t *device, void *data, unsigned int size)
int rc = select (device->fd + 1, &fds, NULL, NULL, timeout >= 0 ? &tvt : NULL); int rc = select (device->fd + 1, &fds, NULL, NULL, timeout >= 0 ? &tvt : NULL);
if (rc < 0) { if (rc < 0) {
if (errno == EINTR) int errcode = errno;
if (errcode == EINTR)
continue; // Retry. continue; // Retry.
SYSERROR (device->context, errno); SYSERROR (device->context, errcode);
return -1; // Error during select call. status = syserror (errcode);
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) int errcode = errno;
if (errcode == EINTR || errcode == EAGAIN)
continue; // Retry. continue; // Retry.
SYSERROR (device->context, errno); SYSERROR (device->context, errcode);
return -1; // Error during read call. status = syserror (errcode);
goto out;
} else if (n == 0) { } else if (n == 0) {
break; // EOF. break; // EOF.
} }
@ -611,28 +640,41 @@ 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); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
status = syserror (errcode);
goto out;
} }
} }
unsigned int nbytes = 0;
while (nbytes < size) { while (nbytes < size) {
fd_set fds; fd_set fds;
FD_ZERO (&fds); FD_ZERO (&fds);
@ -640,20 +682,24 @@ serial_write (serial_t *device, const void *data, unsigned int size)
int rc = select (device->fd + 1, NULL, &fds, NULL, NULL); int rc = select (device->fd + 1, NULL, &fds, NULL, NULL);
if (rc < 0) { if (rc < 0) {
if (errno == EINTR) int errcode = errno;
if (errcode == EINTR)
continue; // Retry. continue; // Retry.
SYSERROR (device->context, errno); SYSERROR (device->context, errcode);
return -1; // Error during select call. status = syserror (errcode);
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) int errcode = errno;
if (errcode == EINTR || errcode == EAGAIN)
continue; // Retry. continue; // Retry.
SYSERROR (device->context, errno); SYSERROR (device->context, errcode);
return -1; // Error during write call. status = syserror (errcode);
goto out;
} else if (n == 0) { } else if (n == 0) {
break; // EOF. break; // EOF.
} }
@ -668,17 +714,21 @@ serial_write (serial_t *device, const void *data, unsigned int size)
#else #else
while (tcdrain (device->fd) != 0) { while (tcdrain (device->fd) != 0) {
#endif #endif
if (errno != EINTR ) { int errcode = errno;
SYSERROR (device->context, errno); if (errcode != EINTR ) {
return -1; SYSERROR (device->context, errcode);
status = syserror (errcode);
goto out;
} }
} }
if (device->halfduplex) { if (device->halfduplex) {
// Get the current time. // Get the current time.
if (gettimeofday (&tve, NULL) != 0) { if (gettimeofday (&tve, NULL) != 0) {
SYSERROR (device->context, errno); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
status = syserror (errcode);
goto out;
} }
// Calculate the elapsed time (microseconds). // Calculate the elapsed time (microseconds).
@ -697,88 +747,87 @@ 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); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
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);
unsigned long action = (level ? TIOCSBRK : TIOCCBRK); unsigned long action = (level ? TIOCSBRK : TIOCCBRK);
if (ioctl (device->fd, action, NULL) != 0 && NOPTY) { if (ioctl (device->fd, action, NULL) != 0 && NOPTY) {
SYSERROR (device->context, errno); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
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);
@ -786,19 +835,19 @@ 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); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
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);
@ -806,93 +855,82 @@ 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); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
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); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
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); int errcode = errno;
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
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);
ts.tv_nsec = (timeout % 1000) * 1000000; ts.tv_nsec = (timeout % 1000) * 1000000;
while (nanosleep (&ts, &ts) != 0) { while (nanosleep (&ts, &ts) != 0) {
if (errno != EINTR ) { int errcode = errno;
SYSERROR (device->context, errno); if (errcode != EINTR ) {
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
} }
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,34 @@ struct serial_t {
unsigned int nbits; unsigned int nbits;
}; };
int static dc_status_t
serial_enumerate (serial_callback_t callback, void *userdata) syserror(DWORD errcode)
{
switch (errcode) {
case ERROR_INVALID_PARAMETER:
return DC_STATUS_INVALIDARGS;
case ERROR_OUTOFMEMORY:
return DC_STATUS_NOMEMORY;
case ERROR_FILE_NOT_FOUND:
return DC_STATUS_NODEVICE;
case ERROR_ACCESS_DENIED:
return DC_STATUS_NOACCESS;
default:
return DC_STATUS_IO;
}
}
dc_status_t
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 +83,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 +95,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 +105,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 +116,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 +135,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 +143,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.
@ -149,7 +165,9 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
0, // Non-overlapped I/O. 0, // Non-overlapped I/O.
NULL); NULL);
if (device->hFile == INVALID_HANDLE_VALUE) { if (device->hFile == INVALID_HANDLE_VALUE) {
SYSERROR (context, GetLastError ()); DWORD errcode = GetLastError ();
SYSERROR (context, errcode);
status = syserror (errcode);
goto error_free; goto error_free;
} }
@ -159,61 +177,57 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
// represents a serial device. // represents a serial device.
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 ()); DWORD errcode = GetLastError ();
SYSERROR (context, errcode);
status = syserror (errcode);
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 ()); DWORD errcode = GetLastError ();
errcode = -1; SYSERROR (device->context, errcode);
dc_status_set_error(&status, syserror (errcode));
} }
// Close the device. // Close the device.
if (!CloseHandle (device->hFile)) { if (!CloseHandle (device->hFile)) {
SYSERROR (device->context, GetLastError ()); DWORD errcode = GetLastError ();
errcode = -1; SYSERROR (device->context, errcode);
dc_status_set_error(&status, syserror (errcode));
} }
// 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);
@ -221,8 +235,9 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int
// Retrieve the current settings. // Retrieve the current settings.
DCB dcb; DCB dcb;
if (!GetCommState (device->hFile, &dcb)) { if (!GetCommState (device->hFile, &dcb)) {
SYSERROR (device->context, GetLastError ()); DWORD errcode = GetLastError ();
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
dcb.fBinary = TRUE; // Enable Binary Transmission dcb.fBinary = TRUE; // Enable Binary Transmission
@ -235,40 +250,52 @@ 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;
case DC_PARITY_MARK:
dcb.Parity = MARKPARITY;
dcb.fParity = TRUE;
break;
case DC_PARITY_SPACE:
dcb.Parity = SPACEPARITY;
dcb.fParity = TRUE;
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_ONEPOINTFIVE:
dcb.StopBits = ONE5STOPBITS;
break;
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 +303,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 +311,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 +320,36 @@ 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 ()); DWORD errcode = GetLastError ();
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
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 ()); DWORD errcode = GetLastError ();
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
// Update the settings. // Update the settings.
@ -353,98 +378,102 @@ 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 ()); DWORD errcode = GetLastError ();
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
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)) {
DWORD errcode = GetLastError ();
SYSERROR (device->context, errcode);
status = syserror (errcode);
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) {
// Get the current time. // Get the current time.
if (!QueryPerformanceFrequency(&freq) || if (!QueryPerformanceFrequency(&freq) ||
!QueryPerformanceCounter(&begin)) { !QueryPerformanceCounter(&begin)) {
SYSERROR (device->context, GetLastError ()); DWORD errcode = GetLastError ();
return -1; SYSERROR (device->context, errcode);
status = syserror (errcode);
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 ()); DWORD errcode = GetLastError ();
return -1; SYSERROR (device->context, errcode);
status = syserror (errcode);
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 ()); DWORD errcode = GetLastError ();
return -1; SYSERROR (device->context, errcode);
status = syserror (errcode);
goto out;
} }
// Calculate the elapsed time (microseconds). // Calculate the elapsed time (microseconds).
@ -461,204 +490,195 @@ 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 ()); DWORD errcode = GetLastError ();
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
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");
SYSERROR (device->context, GetLastError ());
return -1; if (!FlushFileBuffers (device->hFile)) {
DWORD errcode = GetLastError ();
SYSERROR (device->context, errcode);
return syserror (errcode);
} }
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 ()); DWORD errcode = GetLastError ();
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
} else { } else {
if (!ClearCommBreak (device->hFile)) { if (!ClearCommBreak (device->hFile)) {
SYSERROR (device->context, GetLastError ()); DWORD errcode = GetLastError ();
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
} }
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);
int status = (level ? SETDTR : CLRDTR); int status = (level ? SETDTR : CLRDTR);
if (!EscapeCommFunction (device->hFile, status)) { if (!EscapeCommFunction (device->hFile, status)) {
SYSERROR (device->context, GetLastError ()); DWORD errcode = GetLastError ();
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
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);
int status = (level ? SETRTS : CLRRTS); int status = (level ? SETRTS : CLRRTS);
if (!EscapeCommFunction (device->hFile, status)) { if (!EscapeCommFunction (device->hFile, status)) {
SYSERROR (device->context, GetLastError ()); DWORD errcode = GetLastError ();
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
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 ()); DWORD errcode = GetLastError ();
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
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 ()); DWORD errcode = GetLastError ();
return -1; SYSERROR (device->context, errcode);
return syserror (errcode);
} }
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;