summaryrefslogtreecommitdiff
path: root/bluetoothgpsserver.cpp
blob: efbddf08b0088e662ce9cdce3a062dceea1fe51e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <QtCore/QDebug>

#include "nmeasource.h"
#include "bluetoothgpsserver.h"

BluetoothGpsServer::BluetoothGpsServer(uint port, QObject *parent) :
	QObject(parent), m_port(port), m_source(new NmeaSource(this)), m_server(0)
{
	connect(m_source, SIGNAL(dataReady(QString)), this, SLOT(sendData(QString)));
}

BluetoothGpsServer::~BluetoothGpsServer()
{
	stop();
}

void BluetoothGpsServer::start()
{
	if (m_server) {
		return;
	}

	m_server = new QRfcommServer(this);
	connect(m_server, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
	if (!m_server->listen(QBluetoothAddress(), m_port)) {
		qWarning() << "Failed to start Bluetooth listener socket";
		stop();
		return;
	}

	quint8 serverPort = m_server->serverPort();

	const QBluetoothUuid service_uuid(QLatin1String("2af0b21d-2d9d-43bd-9693-5d9235fa2033"));
	const QBluetoothUuid gnss_profile_uuid(quint16(0x1135));
	const QBluetoothUuid gnss_server_uuid(quint16(0x1136));

	m_service.setServiceName("GPS");
	m_service.setServiceDescription("GPS/NMEA emulator over Serial Port");
	m_service.setServiceProvider("btgpsd");
	m_service.setServiceUuid(service_uuid);

	QBluetoothServiceInfo::Sequence classIds;
	classIds.append(QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::SerialPort)));
	classIds.append(QVariant::fromValue(gnss_server_uuid));
	m_service.setAttribute(QBluetoothServiceInfo::ServiceClassIds, classIds);

	QBluetoothServiceInfo::Sequence browseGroupList;
	browseGroupList.append(QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::PublicBrowseGroup)));
	m_service.setAttribute(QBluetoothServiceInfo::BrowseGroupList, browseGroupList);

	QBluetoothServiceInfo::Sequence protocolDescriptorList;
	QBluetoothServiceInfo::Sequence protocol;

	protocol.append(QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::L2cap)));
	protocolDescriptorList.append(QVariant::fromValue(protocol));
	protocol.clear();

	protocol.append(QVariant::fromValue(QBluetoothUuid(QBluetoothUuid::Rfcomm)));
	protocol.append(QVariant::fromValue(serverPort));
	protocolDescriptorList.append(QVariant::fromValue(protocol));
	protocol.clear();

	m_service.setAttribute(QBluetoothServiceInfo::ProtocolDescriptorList,
						   protocolDescriptorList);

	QBluetoothServiceInfo::Sequence profileDescriptorList;
	protocol.append(QVariant::fromValue(gnss_profile_uuid));
	protocol.append(QVariant::fromValue<quint16>(0x100));
	profileDescriptorList.append(QVariant::fromValue(protocol));
	protocol.clear();

	// Profile Descriptor list
	m_service.setAttribute(0x0009, QVariant::fromValue(profileDescriptorList));

	if (!m_service.registerService()) {
		qWarning() << "Failed to register the Serial Port service";
	}
}

void BluetoothGpsServer::stop()
{
	if (!m_server) {
		return;
	}

	if (!m_service.unregisterService()) {
		qWarning() << "Failed to unregister Serial Port service";
	}

	qDeleteAll(m_clients);
	m_clients.clear();
	m_source->stop();

	delete m_server;
	m_server = 0;
}

void BluetoothGpsServer::sendData(const QString &data)
{
	QByteArray text = data.toLatin1();
	foreach (QBluetoothSocket *socket, m_clients) {
		socket->write(text);
	}
}

void BluetoothGpsServer::acceptConnection()
{
	qDebug() << "Incoming BT connection";
	QBluetoothSocket *socket = m_server->nextPendingConnection();
	if (!socket) {
		qWarning() << "Actually, no incoming connection";
		return;
	}

	connect(socket, SIGNAL(disconnected()), this, SLOT(handleDisconnection()));

	m_clients.append(socket);
	if (m_clients.size() == 1) {
		// This was the first client; start listening to GPS
		qDebug() << "Starting GPS for BT";
		m_source->start();
	}
}

void BluetoothGpsServer::handleDisconnection()
{
	QBluetoothSocket *socket = qobject_cast<QBluetoothSocket*>(sender());
	Q_ASSERT(socket);

	m_clients.removeOne(socket);
	socket->deleteLater();

	if (m_clients.isEmpty()) {
		qDebug() << "Stopping GPS for BT";
		m_source->stop();
	}
}