diff --git a/src/bluetooth.c b/src/bluetooth.c index 01a3e96..40fa7a6 100644 --- a/src/bluetooth.c +++ b/src/bluetooth.c @@ -51,8 +51,10 @@ #endif #include "bluetooth.h" + #include "common-private.h" #include "context-private.h" +#include "iostream-private.h" #ifdef _WIN32 typedef int s_ssize_t; @@ -93,17 +95,44 @@ typedef int s_errcode_t; #define MAX_DEVICES 255 #define MAX_PERIODS 8 -struct dc_bluetooth_t { - dc_context_t *context; +#define ISINSTANCE(device) dc_iostream_isinstance((device), &dc_bluetooth_vtable) + +#ifdef BLUETOOTH +static dc_status_t dc_bluetooth_set_timeout (dc_iostream_t *iostream, int timeout); +static dc_status_t dc_bluetooth_get_available (dc_iostream_t *iostream, size_t *value); +static dc_status_t dc_bluetooth_read (dc_iostream_t *iostream, void *data, size_t size, size_t *actual); +static dc_status_t dc_bluetooth_write (dc_iostream_t *iostream, const void *data, size_t size, size_t *actual); +static dc_status_t dc_bluetooth_close (dc_iostream_t *iostream); + +typedef struct dc_bluetooth_t { + dc_iostream_t base; #ifdef _WIN32 SOCKET fd; #else int fd; #endif int timeout; +} dc_bluetooth_t; + +static const dc_iostream_vtable_t dc_bluetooth_vtable = { + sizeof(dc_bluetooth_t), + dc_bluetooth_set_timeout, /* set_timeout */ + NULL, /* set_latency */ + NULL, /* set_halfduplex */ + NULL, /* set_break */ + NULL, /* set_dtr */ + NULL, /* set_rts */ + NULL, /* get_lines */ + dc_bluetooth_get_available, /* get_received */ + NULL, /* configure */ + dc_bluetooth_read, /* read */ + dc_bluetooth_write, /* write */ + NULL, /* flush */ + NULL, /* purge */ + NULL, /* sleep */ + dc_bluetooth_close, /* close */ }; -#ifdef BLUETOOTH static dc_status_t syserror(s_errcode_t errcode) { @@ -120,7 +149,6 @@ syserror(s_errcode_t errcode) return DC_STATUS_IO; } } -#endif #ifdef HAVE_BLUEZ static dc_bluetooth_address_t @@ -147,9 +175,10 @@ dc_address_set (bdaddr_t *ba, dc_bluetooth_address_t address) } } #endif +#endif dc_status_t -dc_bluetooth_open (dc_bluetooth_t **out, dc_context_t *context) +dc_bluetooth_open (dc_iostream_t **out, dc_context_t *context) { #ifdef BLUETOOTH dc_status_t status = DC_STATUS_SUCCESS; @@ -159,15 +188,12 @@ dc_bluetooth_open (dc_bluetooth_t **out, dc_context_t *context) return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (dc_bluetooth_t *) malloc (sizeof (dc_bluetooth_t)); + device = (dc_bluetooth_t *) dc_iostream_allocate (context, &dc_bluetooth_vtable); if (device == NULL) { SYSERROR (context, S_ENOMEM); return DC_STATUS_NOMEMORY; } - // Library context. - device->context = context; - // Default to blocking reads. device->timeout = -1; @@ -206,7 +232,7 @@ dc_bluetooth_open (dc_bluetooth_t **out, dc_context_t *context) goto error_wsacleanup; } - *out = device; + *out = (dc_iostream_t *) device; return DC_STATUS_SUCCESS; @@ -215,21 +241,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_bluetooth_close (dc_bluetooth_t *device) -{ #ifdef BLUETOOTH +static dc_status_t +dc_bluetooth_close (dc_iostream_t *abstract) +{ dc_status_t status = DC_STATUS_SUCCESS; - - if (device == NULL) - return DC_STATUS_SUCCESS; + dc_bluetooth_t *device = (dc_bluetooth_t *) abstract; // Terminate all send and receive operations. shutdown (device->fd, 0); @@ -237,7 +261,7 @@ dc_bluetooth_close (dc_bluetooth_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)); } @@ -245,44 +269,32 @@ dc_bluetooth_close (dc_bluetooth_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_bluetooth_set_timeout (dc_bluetooth_t *device, int timeout) +static dc_status_t +dc_bluetooth_set_timeout (dc_iostream_t *abstract, int timeout) { -#ifdef BLUETOOTH - if (device == NULL) - return DC_STATUS_INVALIDARGS; - - INFO (device->context, "Timeout: value=%i", timeout); + dc_bluetooth_t *device = (dc_bluetooth_t *) abstract; device->timeout = timeout; return DC_STATUS_SUCCESS; -#else - return DC_STATUS_UNSUPPORTED; -#endif } +#endif dc_status_t -dc_bluetooth_discover (dc_bluetooth_t *device, dc_bluetooth_callback_t callback, void *userdata) +dc_bluetooth_discover (dc_iostream_t *abstract, dc_bluetooth_callback_t callback, void *userdata) { #ifdef BLUETOOTH dc_status_t status = DC_STATUS_SUCCESS; - if (device == NULL) + if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; #ifdef _WIN32 @@ -299,7 +311,7 @@ dc_bluetooth_discover (dc_bluetooth_t *device, dc_bluetooth_callback_t callback, // No remote bluetooth devices found. status = DC_STATUS_SUCCESS; } else { - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror(errcode); } goto error_exit; @@ -319,7 +331,7 @@ dc_bluetooth_discover (dc_bluetooth_t *device, dc_bluetooth_callback_t callback, if (errcode == WSA_E_NO_MORE || errcode == WSAENOMORE) { break; // No more results. } - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror(errcode); goto error_close; } @@ -327,7 +339,7 @@ dc_bluetooth_discover (dc_bluetooth_t *device, dc_bluetooth_callback_t callback, if (pwsaResults->dwNumberOfCsAddrs == 0 || pwsaResults->lpcsaBuffer == NULL || pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr == NULL) { - ERROR (device->context, "Invalid results returned"); + ERROR (abstract->context, "Invalid results returned"); status = DC_STATUS_IO; goto error_close; } @@ -336,7 +348,7 @@ dc_bluetooth_discover (dc_bluetooth_t *device, dc_bluetooth_callback_t callback, dc_bluetooth_address_t address = sa->btAddr; const char *name = (char *) pwsaResults->lpszServiceInstanceName; - INFO (device->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s", address, name); + INFO (abstract->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s", address, name); if (callback) callback (address, name, userdata); @@ -349,7 +361,7 @@ error_close: int dev = hci_get_route (NULL); if (dev < 0) { s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror(errcode); goto error_exit; } @@ -358,7 +370,7 @@ error_close: int fd = hci_open_dev (dev); if (fd < 0) { s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror(errcode); goto error_exit; } @@ -367,7 +379,7 @@ error_close: inquiry_info *devices = (inquiry_info *) malloc (MAX_DEVICES * sizeof(inquiry_info)); if (devices == NULL) { s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror(errcode); goto error_close; } @@ -378,7 +390,7 @@ error_close: int ndevices = hci_inquiry (dev, MAX_PERIODS, MAX_DEVICES, NULL, &devices, IREQ_CACHE_FLUSH); if (ndevices < 0) { s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); status = syserror(errcode); goto error_free; } @@ -393,7 +405,7 @@ error_close: name = NULL; } - INFO (device->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s", address, name); + INFO (abstract->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s", address, name); if (callback) callback (address, name, userdata); } @@ -412,13 +424,15 @@ error_exit: } dc_status_t -dc_bluetooth_connect (dc_bluetooth_t *device, dc_bluetooth_address_t address, unsigned int port) +dc_bluetooth_connect (dc_iostream_t *abstract, dc_bluetooth_address_t address, unsigned int port) { #ifdef BLUETOOTH - if (device == NULL) + dc_bluetooth_t *device = (dc_bluetooth_t *) abstract; + + if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; - INFO (device->context, "Connect: address=" DC_ADDRESS_FORMAT ", port=%d", address, port); + INFO (abstract->context, "Connect: address=" DC_ADDRESS_FORMAT ", port=%d", address, port); #ifdef _WIN32 SOCKADDR_BTH sa; @@ -435,7 +449,7 @@ dc_bluetooth_connect (dc_bluetooth_t *device, dc_bluetooth_address_t address, un if (connect (device->fd, (struct sockaddr *) &sa, sizeof (sa)) != 0) { s_errcode_t errcode = S_ERRNO; - SYSERROR (device->context, errcode); + SYSERROR (abstract->context, errcode); return syserror(errcode); } @@ -445,12 +459,11 @@ dc_bluetooth_connect (dc_bluetooth_t *device, dc_bluetooth_address_t address, un #endif } -dc_status_t -dc_bluetooth_get_available (dc_bluetooth_t *device, size_t *value) -{ #ifdef BLUETOOTH - if (device == NULL) - return DC_STATUS_INVALIDARGS; +static dc_status_t +dc_bluetooth_get_available (dc_iostream_t *abstract, size_t *value) +{ + dc_bluetooth_t *device = (dc_bluetooth_t *) abstract; #ifdef _WIN32 unsigned long bytes = 0; @@ -460,7 +473,7 @@ dc_bluetooth_get_available (dc_bluetooth_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); } @@ -468,23 +481,15 @@ dc_bluetooth_get_available (dc_bluetooth_t *device, size_t *value) *value = bytes; return DC_STATUS_SUCCESS; -#else - return DC_STATUS_UNSUPPORTED; -#endif } -dc_status_t -dc_bluetooth_read (dc_bluetooth_t *device, void *data, size_t size, size_t *actual) +static dc_status_t +dc_bluetooth_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual) { -#ifdef BLUETOOTH dc_status_t status = DC_STATUS_SUCCESS; + dc_bluetooth_t *device = (dc_bluetooth_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); @@ -503,7 +508,7 @@ dc_bluetooth_read (dc_bluetooth_t *device, void *data, size_t size, size_t *actu 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) { @@ -515,7 +520,7 @@ dc_bluetooth_read (dc_bluetooth_t *device, void *data, size_t size, size_t *actu 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) { @@ -530,30 +535,19 @@ dc_bluetooth_read (dc_bluetooth_t *device, void *data, size_t size, size_t *actu } 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_bluetooth_write (dc_bluetooth_t *device, const void *data, size_t size, size_t *actual) +static dc_status_t +dc_bluetooth_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual) { -#ifdef BLUETOOTH dc_status_t status = DC_STATUS_SUCCESS; + dc_bluetooth_t *device = (dc_bluetooth_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); @@ -564,7 +558,7 @@ dc_bluetooth_write (dc_bluetooth_t *device, const void *data, size_t size, size_ 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) { @@ -576,7 +570,7 @@ dc_bluetooth_write (dc_bluetooth_t *device, const void *data, size_t size, size_ 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) { @@ -591,14 +585,9 @@ dc_bluetooth_write (dc_bluetooth_t *device, const void *data, size_t size, size_ } 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/bluetooth.h b/src/bluetooth.h index d2e3868..1a8e947 100644 --- a/src/bluetooth.h +++ b/src/bluetooth.h @@ -24,16 +24,12 @@ #include #include +#include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -/** - * Opaque object representing a bluetooth connection. - */ -typedef struct dc_bluetooth_t dc_bluetooth_t; - /** * Bluetooth address (48 bits). */ @@ -55,118 +51,37 @@ typedef void (*dc_bluetooth_callback_t) (dc_bluetooth_address_t address, const c /** * Open an bluetooth connection. * - * @param[out] bluetooth A location to store the bluetooth connection. + * @param[out] iostream A location to store the bluetooth 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_bluetooth_open (dc_bluetooth_t **bluetooth, dc_context_t *context); - -/** - * Close the bluetooth connection and free all resources. - * - * @param[in] bluetooth A valid bluetooth connection. - * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code - * on failure. - */ -dc_status_t -dc_bluetooth_close (dc_bluetooth_t *bluetooth); - -/** - * 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] bluetooth A valid bluetooth 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_bluetooth_set_timeout (dc_bluetooth_t *bluetooth, int timeout); +dc_bluetooth_open (dc_iostream_t **iostream, dc_context_t *context); /** * Enumerate the bluetooth devices. * - * @param[in] bluetooth A valid bluetooth connection. + * @param[in] iostream A valid bluetooth 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_bluetooth_discover (dc_bluetooth_t *bluetooth, dc_bluetooth_callback_t callback, void *userdata); +dc_bluetooth_discover (dc_iostream_t *iostream, dc_bluetooth_callback_t callback, void *userdata); /** * Connect to an bluetooth device. * - * @param[in] bluetooth A valid bluetooth connection. + * @param[in] iostream A valid bluetooth connection. * @param[in] address The bluetooth device address. * @param[in] port The bluetooth port number. * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code * on failure. */ dc_status_t -dc_bluetooth_connect (dc_bluetooth_t *bluetooth, dc_bluetooth_address_t address, unsigned int port); - -/** - * Query the number of available bytes in the input buffer. - * - * @param[in] bluetooth A valid bluetooth 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_bluetooth_get_available (dc_bluetooth_t *bluetooth, size_t *value); - -/** - * Read data from the bluetooth connection. - * - * @param[in] bluetooth A valid bluetooth 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_bluetooth_read (dc_bluetooth_t *bluetooth, void *data, size_t size, size_t *actual); - -/** - * Write data to the bluetooth connection. - * - * @param[in] bluetooth A valid bluetooth 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_bluetooth_write (dc_bluetooth_t *bluetooth, const void *data, size_t size, size_t *actual); +dc_bluetooth_connect (dc_iostream_t *iostream, dc_bluetooth_address_t address, unsigned int port); #ifdef __cplusplus }