Port the bluetooth code to the new I/O interface

This commit is contained in:
Jef Driesen 2017-05-03 23:12:06 +02:00
parent 8f17055ec4
commit 300ef5257b
2 changed files with 87 additions and 183 deletions

View File

@ -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

View File

@ -24,16 +24,12 @@
#include <libdivecomputer/common.h>
#include <libdivecomputer/context.h>
#include <libdivecomputer/iostream.h>
#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
}