Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Current Time Service #37

Merged
merged 3 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ set(SRC
advertisement.cpp
bluezmanager.cpp
ancs.cpp
ancs_notification.cpp)
ancs_notification.cpp
cts.cpp)
set(HEADERS
notificationservice.h
weatherservice.h
Expand All @@ -30,7 +31,8 @@ set(HEADERS
bluezmanager.h
ancs_protocol_constants.h
ancs.h
ancs_notification.h)
ancs_notification.h
cts.h)

add_executable(asteroid-btsyncd ${SRC} ${HEADERS})

Expand All @@ -40,7 +42,7 @@ target_link_libraries(asteroid-btsyncd PRIVATE
QtMpris::QtMpris
SystemSettings::SystemSettings
PkgConfig::GIOMM)


install(TARGETS asteroid-btsyncd
DESTINATION ${CMAKE_INSTALL_BINDIR})
Expand Down
5 changes: 4 additions & 1 deletion src/bluezmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ void BlueZManager::onConnectedChanged()
appIcon = "ios-bluetooth-outline";
} else {
mAncs.disconnect();
mCts.disconnect();
//% "Disconnected"
summary = qtTrId("id-disconnected");
body = "";
Expand Down Expand Up @@ -208,6 +209,8 @@ void BlueZManager::onConnectedChanged()
}

void BlueZManager::onServicesResolvedChanged() {
if (mServicesResolved)
if (mServicesResolved) {
mAncs.searchForAncsCharacteristics();
mCts.searchForTimeCharacteristics();
}
}
2 changes: 2 additions & 0 deletions src/bluezmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <QDBusConnection>

#include "ancs.h"
#include "cts.h"

typedef QMap<QString, QMap<QString, QVariant>> InterfaceList;

Expand All @@ -41,6 +42,7 @@ class BlueZManager : public QObject
QDBusServiceWatcher *mWatcher;
QDBusConnection mBus;
ANCS mAncs;
CTS mCts;

void updateAdapter();
void setAdapter(QString adatper);
Expand Down
108 changes: 108 additions & 0 deletions src/cts.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Implements the Current Time Service as per: https://www.bluetooth.com/specifications/specs/cts-1-1/
#include "cts.h"

#include <QDebug>
#include <QDBusInterface>
#include <QDBusArgument>
#include <QDateTime>
#include <QTimeZone>

#include <timed-qt5/wallclock>
#include <timed-qt5/interface>

#include "common.h"

CTS::CTS() {

}

void CTS::searchForTimeCharacteristics() {
QDBusConnection bus = QDBusConnection::systemBus();
QDBusInterface remoteOm(BLUEZ_SERVICE_NAME, "/", DBUS_OM_IFACE, bus);
QDBusMessage result = remoteOm.call("GetManagedObjects");
QString timeChar;
qDebug() << "CTS searching for characteristic";
const QDBusArgument argument = result.arguments().at(0).value<QDBusArgument>();
if (argument.currentType() == QDBusArgument::MapType) {
argument.beginMap();
while (!argument.atEnd()) {
QString key;
QMap<QString, QVariantMap> value;

argument.beginMapEntry();
argument >> key >> value;
argument.endMapEntry();
if (isMatchingCharacteristic(CTS_CHARACTERISTIC_UUID, value)) {
qDebug() << "Found Current Time Characteristic:" << key;
timeChar = key;
}

}
argument.endMap();
}

if (!timeChar.isEmpty()) {
qDebug() << "Current Time Characteristic found";
bus.connect(BLUEZ_SERVICE_NAME, timeChar, DBUS_PROPERTIES_IFACE, "PropertiesChanged", this,
SLOT(TimeCharacteristicPropertiesChanged(QString, QMap<QString, QVariant>, QStringList)));
QDBusInterface timeCharacteristicIface("org.bluez", timeChar, GATT_CHRC_IFACE,
QDBusConnection::systemBus());
timeCharacteristicIface.call("StartNotify");

QMap<QString, QVariant> empty;
QDBusMessage response = timeCharacteristicIface.call("ReadValue", empty);
QList<QVariant> arguments = response.arguments();

if(!arguments.isEmpty() && arguments.first().type() == QVariant::ByteArray) {
QByteArray bytes = arguments.first().toByteArray();
parseCurrentTime(bytes);
}
}
}

void CTS::parseCurrentTime(QByteArray& bytes)
{
if(bytes.size() != 10) {
qWarning() << "Current time value is not 10 bytes long";
return;
}
ushort year = (bytes[1] << 8) + bytes[0];
uint8_t month = bytes[2];
uint8_t day = bytes[3];
uint8_t hour = bytes[4];
uint8_t minute = bytes[5];
uint8_t second = bytes[6];
uint8_t day_of_week = bytes[7];
uint8_t exact_time_256 = bytes[8];
uint8_t adjust_reason = bytes[9];

Maemo::Timed::WallClock::Settings s;
QDateTime newTime(QDate(year, month, day), QTime(hour, minute, second));
newTime.setTimeZone(QTimeZone::systemTimeZone());
s.setTimeManual(newTime.toTime_t());

Maemo::Timed::Interface timed;
timed.wall_clock_settings_async(s);
}

void CTS::TimeCharacteristicPropertiesChanged(QString /* interfaceName */,
QMap<QString, QVariant> changedProperties, QStringList /* invalidatedProperties */)
{
if (changedProperties.contains("Value")) {
QVariant value = changedProperties["Value"];
if (value.type() == QVariant::ByteArray) {

QByteArray bytes = value.toByteArray();
parseCurrentTime(bytes);
}
}
}

bool CTS::isMatchingCharacteristic(QString uuid, QMap<QString, QVariantMap> dbusObject)
{
if (!dbusObject.contains(GATT_CHRC_IFACE)) {
return false;
}
QString charUuid = dbusObject.value(GATT_CHRC_IFACE).value("UUID").toString();
return charUuid.toLower() == uuid.toLower();
}
28 changes: 28 additions & 0 deletions src/cts.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef CTS_H
#define CTS_H
#include <QObject>
#include <QString>
#include <QMap>
#include <QVariant>
#include <QCache>
#include <QTimer>
#include <QDateTime>

#define CTS_CHARACTERISTIC_UUID "00002a2b-0000-1000-8000-00805f9b34fb"

class CTS: public QObject
{
Q_OBJECT
public:
CTS();
void searchForTimeCharacteristics();
void disconnect() {};
private slots:
void TimeCharacteristicPropertiesChanged( QString interfaceName,
QMap<QString, QVariant> changedProperties, QStringList invalidatedProperties);
private:
bool isMatchingCharacteristic(QString uuid, QMap<QString, QVariantMap> dbusObject);
void parseCurrentTime(QByteArray& bytes);

};
#endif // CTS_H