Add support for native bluetooth communication

For the time being, the bluetooth communication code is of very limited
use. It's not used anywhere in the library, and as an internal api it's
also not available to applications. It serves mainly as a reference
implementation for future use.

The implementation supports Windows and Linux.
This commit is contained in:
Jef Driesen 2013-09-22 07:21:46 +02:00
parent 404cea7417
commit 3c7bd525bb
5 changed files with 811 additions and 4 deletions

View File

@ -111,8 +111,28 @@ AS_IF([test "x$with_hidapi" != "xno"], [
])
])
# Checks for BlueZ (bluetooth) support.
AC_ARG_WITH([bluez],
[AS_HELP_STRING([--without-bluez],
[Build without the BlueZ library])],
[], [with_bluez=auto])
AS_IF([test "x$with_bluez" != "xno"], [
PKG_CHECK_MODULES([BLUEZ], [bluez], [have_bluez=yes], [have_bluez=no])
AS_IF([test "x$have_bluez" = "xyes"], [
AC_DEFINE([HAVE_BLUEZ], [1], [BlueZ library])
DEPENDENCIES="$DEPENDENCIES bluez"
])
])
AC_SUBST([DEPENDENCIES])
# Checks for Windows bluetooth support.
AC_CHECK_HEADERS([winsock2.h ws2bth.h], , , [
#if HAVE_WINSOCK2_H
# include <winsock2.h>
# endif
])
# Checks for IrDA support.
AC_CHECK_HEADERS([winsock2.h af_irda.h], , , [
#if HAVE_WINSOCK2_H

View File

@ -42,7 +42,7 @@
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\include"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBDIVECOMPUTER_EXPORTS;ENABLE_LOGGING;HAVE_AF_IRDA_H"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBDIVECOMPUTER_EXPORTS;ENABLE_LOGGING;HAVE_AF_IRDA_H;HAVE_WS2BTH_H"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
@ -119,7 +119,7 @@
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="..\include"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBDIVECOMPUTER_EXPORTS;ENABLE_LOGGING;HAVE_AF_IRDA_H"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBDIVECOMPUTER_EXPORTS;ENABLE_LOGGING;HAVE_AF_IRDA_H;HAVE_WS2BTH_H"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
@ -194,6 +194,10 @@
RelativePath="..\src\atomics_cobalt_parser.c"
>
</File>
<File
RelativePath="..\src\bluetooth.c"
>
</File>
<File
RelativePath="..\src\buffer.c"
>
@ -524,6 +528,10 @@
RelativePath="..\include\libdivecomputer\atomics_cobalt.h"
>
</File>
<File
RelativePath="..\src\bluetooth.h"
>
</File>
<File
RelativePath="..\include\libdivecomputer\buffer.h"
>

View File

@ -1,9 +1,9 @@
AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
AM_CFLAGS = $(LIBUSB_CFLAGS) $(HIDAPI_CFLAGS)
AM_CFLAGS = $(LIBUSB_CFLAGS) $(HIDAPI_CFLAGS) $(BLUEZ_CFLAGS)
lib_LTLIBRARIES = libdivecomputer.la
libdivecomputer_la_LIBADD = $(LIBUSB_LIBS) $(HIDAPI_LIBS) -lm
libdivecomputer_la_LIBADD = $(LIBUSB_LIBS) $(HIDAPI_LIBS) $(BLUEZ_LIBS) -lm
libdivecomputer_la_LDFLAGS = \
-version-info $(DC_VERSION_LIBTOOL) \
-no-undefined \
@ -77,6 +77,7 @@ endif
libdivecomputer_la_SOURCES += irda.h irda.c
libdivecomputer_la_SOURCES += usbhid.h usbhid.c
libdivecomputer_la_SOURCES += bluetooth.h bluetooth.c
if OS_WIN32
libdivecomputer_la_SOURCES += libdivecomputer.rc

604
src/bluetooth.c Normal file
View File

@ -0,0 +1,604 @@
/*
* libdivecomputer
*
* Copyright (C) 2013 Jef Driesen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h> // malloc, free
#ifdef _WIN32
#define NOGDI
#include <winsock2.h>
#include <windows.h>
#ifdef HAVE_WS2BTH_H
#define BLUETOOTH
#include <ws2bth.h>
#endif
#else
#include <errno.h> // errno
#include <unistd.h> // close
#include <sys/types.h> // socket, getsockopt
#include <sys/socket.h> // socket, getsockopt
#include <sys/select.h> // select
#include <sys/ioctl.h> // ioctl
#include <sys/time.h>
#ifdef HAVE_BLUEZ
#define BLUETOOTH
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#endif
#endif
#include "bluetooth.h"
#include "common-private.h"
#include "context-private.h"
#ifdef _WIN32
typedef int s_ssize_t;
typedef DWORD s_errcode_t;
#define S_ERRNO WSAGetLastError ()
#define S_EINTR WSAEINTR
#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_IOCTL ioctlsocket
#define S_CLOSE closesocket
#else
typedef ssize_t s_ssize_t;
typedef int s_errcode_t;
#define S_ERRNO errno
#define S_EINTR EINTR
#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_IOCTL ioctl
#define S_CLOSE close
#endif
#ifdef _WIN32
#define DC_ADDRESS_FORMAT "%012I64X"
#else
#define DC_ADDRESS_FORMAT "%012llX"
#endif
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
#define MAX_DEVICES 255
#define MAX_PERIODS 8
struct dc_bluetooth_t {
dc_context_t *context;
#ifdef _WIN32
SOCKET fd;
#else
int fd;
#endif
int timeout;
};
#ifdef BLUETOOTH
static dc_status_t
syserror(s_errcode_t errcode)
{
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;
}
}
#endif
#ifdef HAVE_BLUEZ
static dc_bluetooth_address_t
dc_address_get (const bdaddr_t *ba)
{
dc_bluetooth_address_t address = 0;
size_t shift = 0;
for (size_t i = 0; i < C_ARRAY_SIZE(ba->b); ++i) {
address |= (dc_bluetooth_address_t) ba->b[i] << shift;
shift += 8;
}
return address;
}
static void
dc_address_set (bdaddr_t *ba, dc_bluetooth_address_t address)
{
size_t shift = 0;
for (size_t i = 0; i < C_ARRAY_SIZE(ba->b); ++i) {
ba->b[i] = (address >> shift) & 0xFF;
shift += 8;
}
}
#endif
dc_status_t
dc_bluetooth_open (dc_bluetooth_t **out, dc_context_t *context)
{
#ifdef BLUETOOTH
dc_status_t status = DC_STATUS_SUCCESS;
dc_bluetooth_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
device = (dc_bluetooth_t *) malloc (sizeof (dc_bluetooth_t));
if (device == NULL) {
SYSERROR (context, S_ENOMEM);
return DC_STATUS_NOMEMORY;
}
// Library context.
device->context = context;
// Default to blocking reads.
device->timeout = -1;
#ifdef _WIN32
// Initialize the winsock dll.
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD (2, 2);
int rc = WSAStartup (wVersionRequested, &wsaData);
if (rc != 0) {
SYSERROR (context, rc);
status = DC_STATUS_UNSUPPORTED;
goto error_free;
}
// Confirm that the winsock dll supports version 2.2.
// Note that if the dll supports versions greater than 2.2 in addition to
// 2.2, it will still return 2.2 since that is the version we requested.
if (LOBYTE (wsaData.wVersion) != 2 ||
HIBYTE (wsaData.wVersion) != 2) {
ERROR (context, "Incorrect winsock version.");
status = DC_STATUS_UNSUPPORTED;
goto error_wsacleanup;
}
#endif
// Open the socket.
#ifdef _WIN32
device->fd = socket (AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
#else
device->fd = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
#endif
if (device->fd == S_INVALID) {
s_errcode_t errcode = S_ERRNO;
SYSERROR (context, errcode);
status = syserror(errcode);
goto error_wsacleanup;
}
*out = device;
return DC_STATUS_SUCCESS;
error_wsacleanup:
#ifdef _WIN32
WSACleanup ();
error_free:
#endif
free (device);
return status;
#else
return DC_STATUS_UNSUPPORTED;
#endif
}
dc_status_t
dc_bluetooth_close (dc_bluetooth_t *device)
{
#ifdef BLUETOOTH
dc_status_t status = DC_STATUS_SUCCESS;
if (device == NULL)
return DC_STATUS_SUCCESS;
// Terminate all send and receive operations.
shutdown (device->fd, 0);
// Close the socket.
if (S_CLOSE (device->fd) != 0) {
s_errcode_t errcode = S_ERRNO;
SYSERROR (device->context, errcode);
dc_status_set_error(&status, syserror(errcode));
}
#ifdef _WIN32
// Terminate the winsock dll.
if (WSACleanup () != 0) {
s_errcode_t errcode = S_ERRNO;
SYSERROR (device->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)
{
#ifdef BLUETOOTH
if (device == NULL)
return DC_STATUS_INVALIDARGS;
INFO (device->context, "Timeout: value=%i", timeout);
device->timeout = timeout;
return DC_STATUS_SUCCESS;
#else
return DC_STATUS_UNSUPPORTED;
#endif
}
dc_status_t
dc_bluetooth_discover (dc_bluetooth_t *device, dc_bluetooth_callback_t callback, void *userdata)
{
#ifdef BLUETOOTH
dc_status_t status = DC_STATUS_SUCCESS;
if (device == NULL)
return DC_STATUS_INVALIDARGS;
#ifdef _WIN32
WSAQUERYSET wsaq;
memset(&wsaq, 0, sizeof (wsaq));
wsaq.dwSize = sizeof (wsaq);
wsaq.dwNameSpace = NS_BTH;
wsaq.lpcsaBuffer = NULL;
HANDLE hLookup;
if (WSALookupServiceBegin(&wsaq, LUP_CONTAINERS | LUP_FLUSHCACHE, &hLookup) != 0) {
s_errcode_t errcode = S_ERRNO;
if (errcode == WSASERVICE_NOT_FOUND) {
// No remote bluetooth devices found.
status = DC_STATUS_SUCCESS;
} else {
SYSERROR (device->context, errcode);
status = syserror(errcode);
}
goto error_exit;
}
unsigned char buf[4096];
LPWSAQUERYSET pwsaResults = (LPWSAQUERYSET) buf;
memset(pwsaResults, 0, sizeof(WSAQUERYSET));
pwsaResults->dwSize = sizeof(WSAQUERYSET);
pwsaResults->dwNameSpace = NS_BTH;
pwsaResults->lpBlob = NULL;
while (1) {
DWORD dwSize = sizeof(buf);
if (WSALookupServiceNext (hLookup, LUP_RETURN_NAME | LUP_RETURN_ADDR, &dwSize, pwsaResults) != 0) {
s_errcode_t errcode = S_ERRNO;
if (errcode == WSA_E_NO_MORE || errcode == WSAENOMORE) {
break; // No more results.
}
SYSERROR (device->context, errcode);
status = syserror(errcode);
goto error_close;
}
if (pwsaResults->dwNumberOfCsAddrs == 0 ||
pwsaResults->lpcsaBuffer == NULL ||
pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr == NULL) {
ERROR (device->context, "Invalid results returned");
status = DC_STATUS_IO;
goto error_close;
}
SOCKADDR_BTH *sa = (SOCKADDR_BTH *) pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr;
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);
if (callback) callback (address, name, userdata);
}
error_close:
WSALookupServiceEnd (hLookup);
#else
// Get the resource number for the first available bluetooth adapter.
int dev = hci_get_route (NULL);
if (dev < 0) {
s_errcode_t errcode = S_ERRNO;
SYSERROR (device->context, errcode);
status = syserror(errcode);
goto error_exit;
}
// Open a socket to the bluetooth adapter.
int fd = hci_open_dev (dev);
if (fd < 0) {
s_errcode_t errcode = S_ERRNO;
SYSERROR (device->context, errcode);
status = syserror(errcode);
goto error_exit;
}
// Allocate a buffer to store the results of the discovery.
inquiry_info *devices = (inquiry_info *) malloc (MAX_DEVICES * sizeof(inquiry_info));
if (devices == NULL) {
s_errcode_t errcode = S_ERRNO;
SYSERROR (device->context, errcode);
status = syserror(errcode);
goto error_close;
}
// Perform the bluetooth device discovery. The inquiry lasts for at
// most MAX_PERIODS * 1.28 seconds, and at most MAX_DEVICES devices
// will be returned.
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);
status = syserror(errcode);
goto error_free;
}
for (unsigned int i = 0; i < ndevices; ++i) {
dc_bluetooth_address_t address = dc_address_get (&devices[i].bdaddr);
// Get the user friendly name.
char buf[HCI_MAX_NAME_LENGTH], *name = buf;
int rc = hci_read_remote_name (fd, &devices[i].bdaddr, sizeof(buf), buf, 0);
if (rc < 0) {
name = NULL;
}
INFO (device->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s", address, name);
if (callback) callback (address, name, userdata);
}
error_free:
free(devices);
error_close:
hci_close_dev(fd);
#endif
error_exit:
return status;
#else
return DC_STATUS_UNSUPPORTED;
#endif
}
dc_status_t
dc_bluetooth_connect (dc_bluetooth_t *device, dc_bluetooth_address_t address, unsigned int port)
{
#ifdef BLUETOOTH
if (device == NULL)
return DC_STATUS_INVALIDARGS;
INFO (device->context, "Connect: address=" DC_ADDRESS_FORMAT ", port=%d", address, port);
#ifdef _WIN32
SOCKADDR_BTH sa;
sa.addressFamily = AF_BTH;
sa.btAddr = address;
sa.port = port;
memset(&sa.serviceClassId, 0, sizeof(sa.serviceClassId));
#else
struct sockaddr_rc sa;
sa.rc_family = AF_BLUETOOTH;
sa.rc_channel = port;
dc_address_set (&sa.rc_bdaddr, address);
#endif
if (connect (device->fd, (struct sockaddr *) &sa, sizeof (sa)) != 0) {
s_errcode_t errcode = S_ERRNO;
SYSERROR (device->context, errcode);
return syserror(errcode);
}
return DC_STATUS_SUCCESS;
#else
return DC_STATUS_UNSUPPORTED;
#endif
}
dc_status_t
dc_bluetooth_get_available (dc_bluetooth_t *device, size_t *value)
{
#ifdef BLUETOOTH
if (device == NULL)
return DC_STATUS_INVALIDARGS;
#ifdef _WIN32
unsigned long bytes = 0;
#else
int bytes = 0;
#endif
if (S_IOCTL (device->fd, FIONREAD, &bytes) != 0) {
s_errcode_t errcode = S_ERRNO;
SYSERROR (device->context, errcode);
return syserror(errcode);
}
if (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)
{
#ifdef BLUETOOTH
dc_status_t status = DC_STATUS_SUCCESS;
size_t nbytes = 0;
if (device == NULL) {
status = DC_STATUS_INVALIDARGS;
goto out_invalidargs;
}
while (nbytes < size) {
fd_set fds;
FD_ZERO (&fds);
FD_SET (device->fd, &fds);
struct timeval tvt;
if (device->timeout > 0) {
tvt.tv_sec = (device->timeout / 1000);
tvt.tv_usec = (device->timeout % 1000) * 1000;
} else if (device->timeout == 0) {
timerclear (&tvt);
}
int rc = select (device->fd + 1, &fds, NULL, NULL, device->timeout >= 0 ? &tvt : NULL);
if (rc < 0) {
s_errcode_t errcode = S_ERRNO;
if (errcode == S_EINTR)
continue; // Retry.
SYSERROR (device->context, errcode);
status = syserror(errcode);
goto out;
} else if (rc == 0) {
break; // Timeout.
}
s_ssize_t n = recv (device->fd, (char*) data + nbytes, size - nbytes, 0);
if (n < 0) {
s_errcode_t errcode = S_ERRNO;
if (errcode == S_EINTR || errcode == S_EAGAIN)
continue; // Retry.
SYSERROR (device->context, errcode);
status = syserror(errcode);
goto out;
} else if (n == 0) {
break; // EOF reached.
}
nbytes += n;
}
if (nbytes != size) {
status = DC_STATUS_TIMEOUT;
}
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)
{
#ifdef BLUETOOTH
dc_status_t status = DC_STATUS_SUCCESS;
size_t nbytes = 0;
if (device == NULL) {
status = DC_STATUS_INVALIDARGS;
goto out_invalidargs;
}
while (nbytes < size) {
fd_set fds;
FD_ZERO (&fds);
FD_SET (device->fd, &fds);
int rc = select (device->fd + 1, NULL, &fds, NULL, NULL);
if (rc < 0) {
s_errcode_t errcode = S_ERRNO;
if (errcode == S_EINTR)
continue; // Retry.
SYSERROR (device->context, errcode);
status = syserror(errcode);
goto out;
} else if (rc == 0) {
break; // Timeout.
}
s_ssize_t n = send (device->fd, (char*) data + nbytes, size - nbytes, 0);
if (n < 0) {
s_errcode_t errcode = S_ERRNO;
if (errcode == S_EINTR || errcode == S_EAGAIN)
continue; // Retry.
SYSERROR (device->context, errcode);
status = syserror(errcode);
goto out;
} else if (n == 0) {
break; // EOF.
}
nbytes += n;
}
if (nbytes != size) {
status = DC_STATUS_TIMEOUT;
}
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes);
out_invalidargs:
if (actual)
*actual = nbytes;
return status;
#else
return DC_STATUS_UNSUPPORTED;
#endif
}

174
src/bluetooth.h Normal file
View File

@ -0,0 +1,174 @@
/*
* libdivecomputer
*
* Copyright (C) 2013 Jef Driesen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef DC_BLUETOOTH_H
#define DC_BLUETOOTH_H
#include <libdivecomputer/common.h>
#include <libdivecomputer/context.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).
*/
#if defined (_WIN32) && !defined (__GNUC__)
typedef unsigned __int64 dc_bluetooth_address_t;
#else
typedef unsigned long long dc_bluetooth_address_t;
#endif
/**
* Bluetooth enumeration callback.
*
* @param[in] address The bluetooth device address.
* @param[in] name The bluetooth device name.
* @param[in] userdata The user data pointer.
*/
typedef void (*dc_bluetooth_callback_t) (dc_bluetooth_address_t address, const char *name, void *userdata);
/**
* Open an bluetooth connection.
*
* @param[out] bluetooth 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);
/**
* Enumerate the bluetooth devices.
*
* @param[in] bluetooth 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);
/**
* Connect to an bluetooth device.
*
* @param[in] bluetooth 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);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* DC_BLUETOOTH_H */