diff --git a/src/irda.c b/src/irda.c index 1a2c38c..980fab5 100644 --- a/src/irda.c +++ b/src/irda.c @@ -50,8 +50,10 @@ #endif #include "irda.h" + #include "common-private.h" #include "context-private.h" +#include "iostream-private.h" #include "array.h" #include "platform.h" @@ -83,17 +85,44 @@ typedef int s_errcode_t; #define S_CLOSE close #endif -struct dc_irda_t { - dc_context_t *context; +#define ISINSTANCE(device) dc_iostream_isinstance((device), &dc_irda_vtable) + +#ifdef IRDA +static dc_status_t dc_irda_set_timeout (dc_iostream_t *iostream, int timeout); +static dc_status_t dc_irda_get_available (dc_iostream_t *iostream, size_t *value); +static dc_status_t dc_irda_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual); +static dc_status_t dc_irda_write (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual); +static dc_status_t dc_irda_close (dc_iostream_t *iostream); + +typedef struct dc_irda_t { + dc_iostream_t base; #ifdef _WIN32 SOCKET fd; #else int fd; #endif int timeout; +} dc_irda_t; + +static const dc_iostream_vtable_t dc_irda_vtable = { + sizeof(dc_irda_t), + dc_irda_set_timeout, /* set_timeout */ + NULL, /* set_latency */ + NULL, /* set_halfduplex */ + NULL, /* set_break */ + NULL, /* set_dtr */ + NULL, /* set_rts */ + NULL, /* get_lines */ + dc_irda_get_available, /* get_received */ + NULL, /* configure */ + dc_irda_read, /* read */ + dc_irda_write, /* write */ + NULL, /* flush */ + NULL, /* purge */ + NULL, /* sleep */ + dc_irda_close, /* close */ }; -#ifdef IRDA static dc_status_t syserror(s_errcode_t errcode) { @@ -113,7 +142,7 @@ syserror(s_errcode_t errcode) #endif dc_status_t -dc_irda_open (dc_irda_t **out, dc_context_t *context) +dc_irda_open (dc_iostream_t **out, dc_context_t *context) { #ifdef IRDA dc_status_t status = DC_STATUS_SUCCESS; @@ -123,15 +152,12 @@ dc_irda_open (dc_irda_t **out, dc_context_t *context) return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (dc_irda_t *) malloc (sizeof (dc_irda_t)); + device = (dc_irda_t *) dc_iostream_allocate (context, &dc_irda_vtable); if (device == NULL) { SYSERROR (context, S_ENOMEM); return DC_STATUS_NOMEMORY; } - // Library context. - device->context = context; - // Default to blocking reads. device->timeout = -1; @@ -166,7 +192,7 @@ dc_irda_open (dc_irda_t **out, dc_context_t *context) goto error_wsacleanup; } - *out = device; + *out = (dc_iostream_t *) device; return DC_STATUS_SUCCESS; @@ -175,21 +201,19 @@ error_wsacleanup: WSACleanup (); error_free: #endif - free (device); + dc_iostream_deallocate ((dc_iostream_t *) device); return status; #else return DC_STATUS_UNSUPPORTED; #endif } -dc_status_t -dc_irda_close (dc_irda_t *device) -{ #ifdef IRDA +static dc_status_t +dc_irda_close (dc_iostream_t *abstract) +{ dc_status_t status = DC_STATUS_SUCCESS; - - if (device == NULL) - return DC_STATUS_SUCCESS; + dc_irda_t *device = (dc_irda_t *) abstract; // Terminate all send and receive operations. shutdown (device->fd, 0); @@ -197,7 +221,7 @@ dc_irda_close (dc_irda_t *device) // Close the socket. if (S_CLOSE (device->fd) != 0) { s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); dc_status_set_error(&status, syserror(errcode)); } @@ -205,37 +229,24 @@ dc_irda_close (dc_irda_t *device) // Terminate the winsock dll. if (WSACleanup () != 0) { s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); dc_status_set_error(&status, syserror(errcode)); } #endif - // Free memory. - free (device); - return status; -#else - return DC_STATUS_UNSUPPORTED; -#endif } -dc_status_t -dc_irda_set_timeout (dc_irda_t *device, int timeout) +static dc_status_t +dc_irda_set_timeout (dc_iostream_t *abstract, int timeout) { -#ifdef IRDA - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "Timeout: value=%i", timeout); + dc_irda_t *device = (dc_irda_t *) abstract; device->timeout = timeout; return DC_STATUS_SUCCESS; -#else - return DC_STATUS_UNSUPPORTED; -#endif } - +#endif #define DISCOVER_MAX_DEVICES 16 // Maximum number of devices. #define DISCOVER_MAX_RETRIES 4 // Maximum number of retries. @@ -249,10 +260,12 @@ dc_irda_set_timeout (dc_irda_t *device, int timeout) #endif dc_status_t -dc_irda_discover (dc_irda_t *device, dc_irda_callback_t callback, void *userdata) +dc_irda_discover (dc_iostream_t *abstract, dc_irda_callback_t callback, void *userdata) { #ifdef IRDA - if (device == NULL) + dc_irda_t *device = (dc_irda_t *) abstract; + + if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; unsigned char data[DISCOVER_BUFSIZE] = {0}; @@ -280,7 +293,7 @@ dc_irda_discover (dc_irda_t *device, dc_irda_callback_t callback, void *userdata if (rc != 0) { s_errcode_t errcode = S_ERRNO; if (errcode != S_EAGAIN) { - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror(errcode); } } @@ -316,7 +329,7 @@ dc_irda_discover (dc_irda_t *device, dc_irda_callback_t callback, void *userdata unsigned int hints = array_uint16_be (list->dev[i].hints); #endif - INFO (device->context, + INFO (abstract->context, "Discover: address=%08x, name=%s, charset=%02x, hints=%04x", address, name, charset, hints); @@ -331,13 +344,15 @@ dc_irda_discover (dc_irda_t *device, dc_irda_callback_t callback, void *userdata } dc_status_t -dc_irda_connect_name (dc_irda_t *device, unsigned int address, const char *name) +dc_irda_connect_name (dc_iostream_t *abstract, unsigned int address, const char *name) { #ifdef IRDA - if (device == NULL) + dc_irda_t *device = (dc_irda_t *) abstract; + + if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; - INFO (device->context, "Connect: address=%08x, name=%s", address, name ? name : ""); + INFO (abstract->context, "Connect: address=%08x, name=%s", address, name ? name : ""); #ifdef _WIN32 SOCKADDR_IRDA peer; @@ -362,7 +377,7 @@ dc_irda_connect_name (dc_irda_t *device, unsigned int address, const char *name) if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) { s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror(errcode); } @@ -373,13 +388,15 @@ dc_irda_connect_name (dc_irda_t *device, unsigned int address, const char *name) } dc_status_t -dc_irda_connect_lsap (dc_irda_t *device, unsigned int address, unsigned int lsap) +dc_irda_connect_lsap (dc_iostream_t *abstract, unsigned int address, unsigned int lsap) { #ifdef IRDA - if (device == NULL) + dc_irda_t *device = (dc_irda_t *) abstract; + + if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; - INFO (device->context, "Connect: address=%08x, lsap=%u", address, lsap); + INFO (abstract->context, "Connect: address=%08x, lsap=%u", address, lsap); #ifdef _WIN32 SOCKADDR_IRDA peer; @@ -399,7 +416,7 @@ dc_irda_connect_lsap (dc_irda_t *device, unsigned int address, unsigned int lsap if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) { s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror(errcode); } @@ -409,12 +426,11 @@ dc_irda_connect_lsap (dc_irda_t *device, unsigned int address, unsigned int lsap #endif } -dc_status_t -dc_irda_get_available (dc_irda_t *device, size_t *value) -{ #ifdef IRDA - if (device == NULL) - return DC_STATUS_INVALIDARGS; +static dc_status_t +dc_irda_get_available (dc_iostream_t *abstract, size_t *value) +{ + dc_irda_t *device = (dc_irda_t *) abstract; #ifdef _WIN32 unsigned long bytes = 0; @@ -424,7 +440,7 @@ dc_irda_get_available (dc_irda_t *device, size_t *value) if (S_IOCTL (device->fd, FIONREAD, &bytes) != 0) { s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror(errcode); } @@ -432,23 +448,15 @@ dc_irda_get_available (dc_irda_t *device, size_t *value) *value = bytes; return DC_STATUS_SUCCESS; -#else - return DC_STATUS_UNSUPPORTED; -#endif } -dc_status_t -dc_irda_read (dc_irda_t *device, void *data, size_t size, size_t *actual) +static dc_status_t +dc_irda_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual) { -#ifdef IRDA dc_status_t status = DC_STATUS_SUCCESS; + dc_irda_t *device = (dc_irda_t *) abstract; size_t nbytes = 0; - if (device == NULL) { - status = DC_STATUS_INVALIDARGS; - goto out_invalidargs; - } - while (nbytes < size) { fd_set fds; FD_ZERO (&fds); @@ -467,7 +475,7 @@ dc_irda_read (dc_irda_t *device, void *data, size_t size, size_t *actual) s_errcode_t errcode = S_ERRNO; if (errcode == S_EINTR) continue; // Retry. - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror(errcode); goto out; } else if (rc == 0) { @@ -479,7 +487,7 @@ dc_irda_read (dc_irda_t *device, void *data, size_t size, size_t *actual) s_errcode_t errcode = S_ERRNO; if (errcode == S_EINTR || errcode == S_EAGAIN) continue; // Retry. - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror(errcode); goto out; } else if (n == 0) { @@ -494,30 +502,19 @@ dc_irda_read (dc_irda_t *device, void *data, size_t size, size_t *actual) } out: - HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes); - -out_invalidargs: if (actual) *actual = nbytes; return status; -#else - return DC_STATUS_UNSUPPORTED; -#endif } -dc_status_t -dc_irda_write (dc_irda_t *device, const void *data, size_t size, size_t *actual) +static dc_status_t +dc_irda_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual) { -#ifdef IRDA dc_status_t status = DC_STATUS_SUCCESS; + dc_irda_t *device = (dc_irda_t *) abstract; size_t nbytes = 0; - if (device == NULL) { - status = DC_STATUS_INVALIDARGS; - goto out_invalidargs; - } - while (nbytes < size) { fd_set fds; FD_ZERO (&fds); @@ -528,7 +525,7 @@ dc_irda_write (dc_irda_t *device, const void *data, size_t size, size_t *actual) s_errcode_t errcode = S_ERRNO; if (errcode == S_EINTR) continue; // Retry. - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror(errcode); goto out; } else if (rc == 0) { @@ -540,7 +537,7 @@ dc_irda_write (dc_irda_t *device, const void *data, size_t size, size_t *actual) s_errcode_t errcode = S_ERRNO; if (errcode == S_EINTR || errcode == S_EAGAIN) continue; // Retry. - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror(errcode); goto out; } else if (n == 0) { @@ -555,14 +552,9 @@ dc_irda_write (dc_irda_t *device, const void *data, size_t size, size_t *actual) } out: - HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (const unsigned char *) data, nbytes); - -out_invalidargs: if (actual) *actual = nbytes; return status; -#else - return DC_STATUS_UNSUPPORTED; -#endif } +#endif diff --git a/src/irda.h b/src/irda.h index 84d2f4d..c413963 100644 --- a/src/irda.h +++ b/src/irda.h @@ -24,16 +24,12 @@ #include #include +#include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -/** - * Opaque object representing an IrDA connection. - */ -typedef struct dc_irda_t dc_irda_t; - /** * IrDA enumeration callback. * @@ -48,130 +44,49 @@ typedef void (*dc_irda_callback_t) (unsigned int address, const char *name, unsi /** * Open an IrDA connection. * - * @param[out] irda A location to store the IrDA connection. + * @param[out] iostream 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); - -/** - * 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); - -/** - * 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); +dc_irda_open (dc_iostream_t **iostream, dc_context_t *context); /** * Enumerate the IrDA devices. * - * @param[in] irda A valid IrDA connection. + * @param[in] iostream 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); +dc_irda_discover (dc_iostream_t *iostream, dc_irda_callback_t callback, void *userdata); /** * Connect to an IrDA device. * - * @param[in] irda A valid IrDA connection. + * @param[in] iostream 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); +dc_irda_connect_name (dc_iostream_t *iostream, unsigned int address, const char *name); /** * Connect to an IrDA device. * - * @param[in] irda A valid IrDA connection. + * @param[in] iostream 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); - -/** - * 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); - -/** - * 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); +dc_irda_connect_lsap (dc_iostream_t *iostream, unsigned int address, unsigned int lsap); #ifdef __cplusplus } diff --git a/src/uwatec_smart.c b/src/uwatec_smart.c index 4fd2e2d..bb67131 100644 --- a/src/uwatec_smart.c +++ b/src/uwatec_smart.c @@ -32,7 +32,7 @@ typedef struct uwatec_smart_device_t { dc_device_t base; - dc_irda_t *socket; + dc_iostream_t *iostream; unsigned int address; unsigned int timestamp; unsigned int devtime; @@ -88,13 +88,13 @@ uwatec_smart_transfer (uwatec_smart_device_t *device, const unsigned char comman dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; - status = dc_irda_write (device->socket, command, csize, NULL); + status = dc_iostream_write (device->iostream, command, csize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; } - status = dc_irda_read (device->socket, answer, asize, NULL); + status = dc_iostream_read (device->iostream, answer, asize, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; @@ -158,21 +158,21 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context) } // Set the default values. - device->socket = NULL; + device->iostream = NULL; device->address = 0; device->timestamp = 0; device->systime = (dc_ticks_t) -1; device->devtime = 0; // Open the irda socket. - status = dc_irda_open (&device->socket, context); + status = dc_irda_open (&device->iostream, context); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the irda socket."); goto error_free; } // Discover the device. - status = dc_irda_discover (device->socket, uwatec_smart_discovery, device); + status = dc_irda_discover (device->iostream, uwatec_smart_discovery, device); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to discover the device."); goto error_close; @@ -185,7 +185,7 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context) } // Connect the device. - status = dc_irda_connect_lsap (device->socket, device->address, 1); + status = dc_irda_connect_lsap (device->iostream, device->address, 1); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to connect the device."); goto error_close; @@ -203,7 +203,7 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context) return DC_STATUS_SUCCESS; error_close: - dc_irda_close (device->socket); + dc_iostream_close (device->iostream); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -218,7 +218,7 @@ uwatec_smart_device_close (dc_device_t *abstract) dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - rc = dc_irda_close (device->socket); + rc = dc_iostream_close (device->iostream); if (status != DC_STATUS_SUCCESS) { dc_status_set_error(&status, rc); } @@ -362,7 +362,7 @@ uwatec_smart_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Increase the packet size if more data is immediately available. size_t available = 0; - rc = dc_irda_get_available (device->socket, &available); + rc = dc_iostream_get_available (device->iostream, &available); if (rc == DC_STATUS_SUCCESS && available > len) len = available; @@ -370,7 +370,7 @@ uwatec_smart_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) if (nbytes + len > length) len = length - nbytes; - rc = dc_irda_read (device->socket, data + nbytes, len, NULL); + rc = dc_iostream_read (device->iostream, data + nbytes, len, NULL); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return rc;