mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
Move all core-functionality to subsurface-core
And adapt a new CMakeLists.txt file for it. On the way I've also found out that we where double-compilling a few files. I've also set the subsurface-core as a include_path but that was just to reduce the noise on this commit, since I plan to remove it from the include path to make it obligatory to specify something like include "subsurface-core/dive.h" for the header files. Since the app is growing quite a bit we ended up having a few different files with almost same name that did similar things, I want to kill that (for instance Dive.h, dive.h, PrintDive.h and such). Signed-off-by: Tomaz Canabrava <tomaz.canabrava@intel.com> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
parent
a079821423
commit
4c0156e3d5
105 changed files with 102 additions and 78 deletions
415
subsurface-core/qtserialbluetooth.cpp
Normal file
415
subsurface-core/qtserialbluetooth.cpp
Normal file
|
@ -0,0 +1,415 @@
|
|||
#include <errno.h>
|
||||
|
||||
#include <QtBluetooth/QBluetoothAddress>
|
||||
#include <QtBluetooth/QBluetoothSocket>
|
||||
#include <QEventLoop>
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
|
||||
#include <libdivecomputer/version.h>
|
||||
|
||||
#if defined(SSRF_CUSTOM_SERIAL)
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <ws2bth.h>
|
||||
#endif
|
||||
|
||||
#include <libdivecomputer/custom_serial.h>
|
||||
|
||||
extern "C" {
|
||||
typedef struct serial_t {
|
||||
/* Library context. */
|
||||
dc_context_t *context;
|
||||
/*
|
||||
* RFCOMM socket used for Bluetooth Serial communication.
|
||||
*/
|
||||
#if defined(Q_OS_WIN)
|
||||
SOCKET socket;
|
||||
#else
|
||||
QBluetoothSocket *socket;
|
||||
#endif
|
||||
long timeout;
|
||||
} serial_t;
|
||||
|
||||
static int qt_serial_open(serial_t **out, dc_context_t *context, const char* devaddr)
|
||||
{
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
serial_t *serial_port = (serial_t *) malloc (sizeof (serial_t));
|
||||
if (serial_port == NULL) {
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Library context.
|
||||
serial_port->context = context;
|
||||
|
||||
// Default to blocking reads.
|
||||
serial_port->timeout = -1;
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
// Create a RFCOMM socket
|
||||
serial_port->socket = ::socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
|
||||
|
||||
if (serial_port->socket == INVALID_SOCKET) {
|
||||
free(serial_port);
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
|
||||
SOCKADDR_BTH socketBthAddress;
|
||||
int socketBthAddressBth = sizeof (socketBthAddress);
|
||||
char *address = strdup(devaddr);
|
||||
|
||||
ZeroMemory(&socketBthAddress, socketBthAddressBth);
|
||||
qDebug() << "Trying to connect to address " << devaddr;
|
||||
|
||||
if (WSAStringToAddressA(address,
|
||||
AF_BTH,
|
||||
NULL,
|
||||
(LPSOCKADDR) &socketBthAddress,
|
||||
&socketBthAddressBth
|
||||
) != 0) {
|
||||
qDebug() << "FAiled to convert the address " << address;
|
||||
free(address);
|
||||
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
|
||||
free(address);
|
||||
|
||||
socketBthAddress.addressFamily = AF_BTH;
|
||||
socketBthAddress.port = BT_PORT_ANY;
|
||||
memset(&socketBthAddress.serviceClassId, 0, sizeof(socketBthAddress.serviceClassId));
|
||||
socketBthAddress.serviceClassId = SerialPortServiceClass_UUID;
|
||||
|
||||
// Try to connect to the device
|
||||
if (::connect(serial_port->socket,
|
||||
(struct sockaddr *) &socketBthAddress,
|
||||
socketBthAddressBth
|
||||
) != 0) {
|
||||
qDebug() << "Failed to connect to device";
|
||||
|
||||
return DC_STATUS_NODEVICE;
|
||||
}
|
||||
|
||||
qDebug() << "Succesfully connected to device";
|
||||
#else
|
||||
// Create a RFCOMM socket
|
||||
serial_port->socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
|
||||
|
||||
// Wait until the connection succeeds or until an error occurs
|
||||
QEventLoop loop;
|
||||
loop.connect(serial_port->socket, SIGNAL(connected()), SLOT(quit()));
|
||||
loop.connect(serial_port->socket, SIGNAL(error(QBluetoothSocket::SocketError)), SLOT(quit()));
|
||||
|
||||
// Create a timer. If the connection doesn't succeed after five seconds or no error occurs then stop the opening step
|
||||
QTimer timer;
|
||||
int msec = 5000;
|
||||
timer.setSingleShot(true);
|
||||
loop.connect(&timer, SIGNAL(timeout()), SLOT(quit()));
|
||||
|
||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||
// First try to connect on RFCOMM channel 1. This is the default channel for most devices
|
||||
QBluetoothAddress remoteDeviceAddress(devaddr);
|
||||
serial_port->socket->connectToService(remoteDeviceAddress, 1, QIODevice::ReadWrite | QIODevice::Unbuffered);
|
||||
timer.start(msec);
|
||||
loop.exec();
|
||||
|
||||
if (serial_port->socket->state() == QBluetoothSocket::ConnectingState) {
|
||||
// It seems that the connection on channel 1 took more than expected. Wait another 15 seconds
|
||||
qDebug() << "The connection on RFCOMM channel number 1 took more than expected. Wait another 15 seconds.";
|
||||
timer.start(3 * msec);
|
||||
loop.exec();
|
||||
} else if (serial_port->socket->state() == QBluetoothSocket::UnconnectedState) {
|
||||
// Try to connect on channel number 5. Maybe this is a Shearwater Petrel2 device.
|
||||
qDebug() << "Connection on channel 1 failed. Trying on channel number 5.";
|
||||
serial_port->socket->connectToService(remoteDeviceAddress, 5, QIODevice::ReadWrite | QIODevice::Unbuffered);
|
||||
timer.start(msec);
|
||||
loop.exec();
|
||||
|
||||
if (serial_port->socket->state() == QBluetoothSocket::ConnectingState) {
|
||||
// It seems that the connection on channel 5 took more than expected. Wait another 15 seconds
|
||||
qDebug() << "The connection on RFCOMM channel number 5 took more than expected. Wait another 15 seconds.";
|
||||
timer.start(3 * msec);
|
||||
loop.exec();
|
||||
}
|
||||
}
|
||||
#elif defined(Q_OS_ANDROID) || (QT_VERSION >= 0x050500 && defined(Q_OS_MAC))
|
||||
// Try to connect to the device using the uuid of the Serial Port Profile service
|
||||
QBluetoothAddress remoteDeviceAddress(devaddr);
|
||||
serial_port->socket->connectToService(remoteDeviceAddress, QBluetoothUuid(QBluetoothUuid::SerialPort));
|
||||
timer.start(msec);
|
||||
loop.exec();
|
||||
|
||||
if (serial_port->socket->state() == QBluetoothSocket::ConnectingState ||
|
||||
serial_port->socket->state() == QBluetoothSocket::ServiceLookupState) {
|
||||
// It seems that the connection step took more than expected. Wait another 20 seconds.
|
||||
qDebug() << "The connection step took more than expected. Wait another 20 seconds";
|
||||
timer.start(4 * msec);
|
||||
loop.exec();
|
||||
}
|
||||
#endif
|
||||
if (serial_port->socket->state() != QBluetoothSocket::ConnectedState) {
|
||||
|
||||
// Get the latest error and try to match it with one from libdivecomputer
|
||||
QBluetoothSocket::SocketError err = serial_port->socket->error();
|
||||
qDebug() << "Failed to connect to device " << devaddr << ". Device state " << serial_port->socket->state() << ". Error: " << err;
|
||||
|
||||
free (serial_port);
|
||||
switch(err) {
|
||||
case QBluetoothSocket::HostNotFoundError:
|
||||
case QBluetoothSocket::ServiceNotFoundError:
|
||||
return DC_STATUS_NODEVICE;
|
||||
case QBluetoothSocket::UnsupportedProtocolError:
|
||||
return DC_STATUS_PROTOCOL;
|
||||
#if QT_VERSION >= 0x050400
|
||||
case QBluetoothSocket::OperationError:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
#endif
|
||||
case QBluetoothSocket::NetworkError:
|
||||
return DC_STATUS_IO;
|
||||
default:
|
||||
return QBluetoothSocket::UnknownSocketError;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*out = serial_port;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int qt_serial_close(serial_t *device)
|
||||
{
|
||||
if (device == NULL)
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
// Cleanup
|
||||
closesocket(device->socket);
|
||||
free(device);
|
||||
#else
|
||||
if (device->socket == NULL) {
|
||||
free(device);
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
device->socket->close();
|
||||
|
||||
delete device->socket;
|
||||
free(device);
|
||||
#endif
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int qt_serial_read(serial_t *device, void* data, unsigned int size)
|
||||
{
|
||||
#if defined(Q_OS_WIN)
|
||||
if (device == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
unsigned int nbytes = 0;
|
||||
int rc;
|
||||
|
||||
while (nbytes < size) {
|
||||
rc = recv (device->socket, (char *) data + nbytes, size - nbytes, 0);
|
||||
|
||||
if (rc < 0) {
|
||||
return -1; // Error during recv call.
|
||||
} else if (rc == 0) {
|
||||
break; // EOF reached.
|
||||
}
|
||||
|
||||
nbytes += rc;
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
#else
|
||||
if (device == NULL || device->socket == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
unsigned int nbytes = 0;
|
||||
int rc;
|
||||
|
||||
while(nbytes < size && device->socket->state() == QBluetoothSocket::ConnectedState)
|
||||
{
|
||||
rc = device->socket->read((char *) data + nbytes, size - nbytes);
|
||||
|
||||
if (rc < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue; // Retry.
|
||||
|
||||
return -1; // Something really bad happened :-(
|
||||
} else if (rc == 0) {
|
||||
// Wait until the device is available for read operations
|
||||
QEventLoop loop;
|
||||
QTimer timer;
|
||||
timer.setSingleShot(true);
|
||||
loop.connect(&timer, SIGNAL(timeout()), SLOT(quit()));
|
||||
loop.connect(device->socket, SIGNAL(readyRead()), SLOT(quit()));
|
||||
timer.start(device->timeout);
|
||||
loop.exec();
|
||||
|
||||
if (!timer.isActive())
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
nbytes += rc;
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int qt_serial_write(serial_t *device, const void* data, unsigned int size)
|
||||
{
|
||||
#if defined(Q_OS_WIN)
|
||||
if (device == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
unsigned int nbytes = 0;
|
||||
int rc;
|
||||
|
||||
while (nbytes < size) {
|
||||
rc = send(device->socket, (char *) data + nbytes, size - nbytes, 0);
|
||||
|
||||
if (rc < 0) {
|
||||
return -1; // Error during send call.
|
||||
}
|
||||
|
||||
nbytes += rc;
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
#else
|
||||
if (device == NULL || device->socket == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
unsigned int nbytes = 0;
|
||||
int rc;
|
||||
|
||||
while(nbytes < size && device->socket->state() == QBluetoothSocket::ConnectedState)
|
||||
{
|
||||
rc = device->socket->write((char *) data + nbytes, size - nbytes);
|
||||
|
||||
if (rc < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue; // Retry.
|
||||
|
||||
return -1; // Something really bad happened :-(
|
||||
} else if (rc == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
nbytes += rc;
|
||||
}
|
||||
|
||||
return nbytes;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int qt_serial_flush(serial_t *device, int queue)
|
||||
{
|
||||
if (device == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
#if !defined(Q_OS_WIN)
|
||||
if (device->socket == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
#endif
|
||||
// TODO: add implementation
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int qt_serial_get_received(serial_t *device)
|
||||
{
|
||||
#if defined(Q_OS_WIN)
|
||||
if (device == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// TODO use WSAIoctl to get the information
|
||||
|
||||
return 0;
|
||||
#else
|
||||
if (device == NULL || device->socket == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
return device->socket->bytesAvailable();
|
||||
#endif
|
||||
}
|
||||
|
||||
static int qt_serial_get_transmitted(serial_t *device)
|
||||
{
|
||||
#if defined(Q_OS_WIN)
|
||||
if (device == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// TODO add implementation
|
||||
|
||||
return 0;
|
||||
#else
|
||||
if (device == NULL || device->socket == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
return device->socket->bytesToWrite();
|
||||
#endif
|
||||
}
|
||||
|
||||
static int qt_serial_set_timeout(serial_t *device, long timeout)
|
||||
{
|
||||
if (device == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
device->timeout = timeout;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
const dc_serial_operations_t qt_serial_ops = {
|
||||
.open = qt_serial_open,
|
||||
.close = qt_serial_close,
|
||||
.read = qt_serial_read,
|
||||
.write = qt_serial_write,
|
||||
.flush = qt_serial_flush,
|
||||
.get_received = qt_serial_get_received,
|
||||
.get_transmitted = qt_serial_get_transmitted,
|
||||
.set_timeout = qt_serial_set_timeout
|
||||
};
|
||||
|
||||
extern void dc_serial_init (dc_serial_t *serial, void *data, const dc_serial_operations_t *ops);
|
||||
|
||||
dc_status_t dc_serial_qt_open(dc_serial_t **out, dc_context_t *context, const char *devaddr)
|
||||
{
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
dc_serial_t *serial_device = (dc_serial_t *) malloc (sizeof (dc_serial_t));
|
||||
|
||||
if (serial_device == NULL) {
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Initialize data and function pointers
|
||||
dc_serial_init(serial_device, NULL, &qt_serial_ops);
|
||||
|
||||
// Open the serial device.
|
||||
dc_status_t rc = (dc_status_t)qt_serial_open (&serial_device->port, context, devaddr);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
free (serial_device);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Set the type of the device
|
||||
serial_device->type = DC_TRANSPORT_BLUETOOTH;
|
||||
|
||||
*out = serial_device;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue