summaryrefslogtreecommitdiffstats
path: root/tradeshow/iot-sensortag/bluetoothdevice.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tradeshow/iot-sensortag/bluetoothdevice.cpp')
-rw-r--r--tradeshow/iot-sensortag/bluetoothdevice.cpp212
1 files changed, 53 insertions, 159 deletions
diff --git a/tradeshow/iot-sensortag/bluetoothdevice.cpp b/tradeshow/iot-sensortag/bluetoothdevice.cpp
index 66faf5a..a7b8bc4 100644
--- a/tradeshow/iot-sensortag/bluetoothdevice.cpp
+++ b/tradeshow/iot-sensortag/bluetoothdevice.cpp
@@ -58,18 +58,14 @@
#include <QTimer>
#include <QDebug>
#include <QtMath>
+#include <QDateTime>
Q_DECLARE_LOGGING_CATEGORY(boot2QtDemos)
-// The average time from read request to read response is 150ms in optimal conditions.
-// With other sensors being read we have to limit it to even longer periods.
-#define RAPID_TIMER_MS 350
-#define MEDIUM_TIMER_MS (1.5*RAPID_TIMER_MS)
-#define SLOW_TIMER_MS 2000
-
#define START_MEASUREMENT_STR "01" /* 01 start, 00 stop */
#define DISABLE_NOTIF_STR "0000" /* 0100 enable, 0000 disable */
-#define SLOW_TIMER_TIMEOUT_STR "FA" /* 250 -> 2500ms */
+#define ENABLE_NOTIF_STR "0100" /* 0100 enable, 0000 disable */
+#define SLOW_TIMER_TIMEOUT_STR "64" /* 100 -> 1000ms */
#define MEDIUM_TIMER_TIMEOUT_STR "32" /* 50 -> 500ms */
#define RAPID_TIMER_TIMEOUT_STR "0A" /* 10 -> 100ms */
#define MOVEMENT_ENABLE_SENSORS_BITMASK_VALUE "7F02" /* see below */
@@ -85,6 +81,13 @@ Q_DECLARE_LOGGING_CATEGORY(boot2QtDemos)
//MPU9250_ACCELEROMETER_RANGE_2 =0b0000_0010 = 8 G (default)
//MPU9250_ACCELEROMETER_RANGE_3 =0b0000_0011 = 16 G
+// These modifiers come from the Texas Intruments SensorTag Bluetooth LE API specification
+#define GYROSCOPE_API_READING_MULTIPLIER (500.0 / 65536.0)
+#define ACCELOMETER_API_READING_MULTIPLIER (8.0 / 32.768)
+#define HUMIDITY_API_READING_MULTIPLIER (100.0 / 65536.0)
+#define IR_TEMPERATURE_API_READING_DIVIDER 128.0
+#define BAROMETER_API_READING_DIVIDER 100
+
typedef struct {
qint16 gyrox;
qint16 gyroy;
@@ -107,10 +110,8 @@ BluetoothDevice::BluetoothDevice()
, motionService(0)
, m_deviceState(DeviceState::Disconnected)
, randomAddress(false)
- , slowTimer(0)
- , mediumTimer(0)
- , rapidTimer(0)
{
+ lastMilliseconds = QDateTime::currentMSecsSinceEpoch();
statusUpdated("Device created");
}
@@ -122,18 +123,6 @@ BluetoothDevice::BluetoothDevice(const QBluetoothDeviceInfo &d)
BluetoothDevice::~BluetoothDevice()
{
- if (slowTimer) {
- slowTimer->stop();
- delete slowTimer;
- }
- if (mediumTimer) {
- mediumTimer->stop();
- delete mediumTimer;
- }
- if (rapidTimer) {
- rapidTimer->stop();
- delete rapidTimer;
- }
delete discoveryAgent;
delete controller;
qDeleteAll(m_services);
@@ -240,7 +229,7 @@ void BluetoothDevice::serviceScanDone()
irTemperatureService = controller->createServiceObject(uuid);
connect(irTemperatureService, &QLowEnergyService::stateChanged, this, &BluetoothDevice::temperatureDetailsDiscovered);
- connect(irTemperatureService, &QLowEnergyService::characteristicRead, this, &BluetoothDevice::characteristicsRead);
+ connect(irTemperatureService, &QLowEnergyService::characteristicChanged, this, &BluetoothDevice::characteristicsRead);
irTemperatureService->discoverDetails();
}
if (!baroService)
@@ -256,7 +245,7 @@ void BluetoothDevice::serviceScanDone()
baroService = controller->createServiceObject(uuid);
connect(baroService, &QLowEnergyService::stateChanged, this, &BluetoothDevice::barometerDetailsDiscovered);
- connect(baroService, &QLowEnergyService::characteristicRead, this, &BluetoothDevice::characteristicsRead);
+ connect(baroService, &QLowEnergyService::characteristicChanged, this, &BluetoothDevice::characteristicsRead);
baroService->discoverDetails();
}
if (!humidityService)
@@ -273,7 +262,7 @@ void BluetoothDevice::serviceScanDone()
humidityService = controller->createServiceObject(uuid);
connect(humidityService, &QLowEnergyService::stateChanged, this, &BluetoothDevice::humidityDetailsDiscovered);
- connect(humidityService, &QLowEnergyService::characteristicRead, this, &BluetoothDevice::characteristicsRead);
+ connect(humidityService, &QLowEnergyService::characteristicChanged, this, &BluetoothDevice::characteristicsRead);
humidityService->discoverDetails();
}
@@ -291,7 +280,7 @@ void BluetoothDevice::serviceScanDone()
lightService = controller->createServiceObject(uuid);
connect(lightService, &QLowEnergyService::stateChanged, this, &BluetoothDevice::lightIntensityDetailsDiscovered);
- connect(lightService, &QLowEnergyService::characteristicRead, this, &BluetoothDevice::characteristicsRead);
+ connect(lightService, &QLowEnergyService::characteristicChanged, this, &BluetoothDevice::characteristicsRead);
lightService->discoverDetails();
}
if (!motionService)
@@ -306,7 +295,7 @@ void BluetoothDevice::serviceScanDone()
}
motionService = controller->createServiceObject(uuid);
connect(motionService, &QLowEnergyService::stateChanged, this, &BluetoothDevice::motionDetailsDiscovered);
- connect(motionService, &QLowEnergyService::characteristicRead, this, &BluetoothDevice::characteristicsRead);
+ connect(motionService, &QLowEnergyService::characteristicChanged, this, &BluetoothDevice::characteristicsRead);
motionService->discoverDetails();
}
attitudeChangeInterval.restart();
@@ -331,7 +320,7 @@ void BluetoothDevice::temperatureDetailsDiscovered(QLowEnergyService::ServiceSta
if (id.toString().contains("f000aa01-0451-4000-b000-000000000000")) {
//RN
- irTemperatureService->writeDescriptor(characteristic.descriptors().at(0), QByteArray::fromHex(DISABLE_NOTIF_STR));
+ irTemperatureService->writeDescriptor(characteristic.descriptors().at(0), QByteArray::fromHex(ENABLE_NOTIF_STR));
}
if (id.toString().contains("f000aa02-0451-4000-b000-000000000000")) {
//RW
@@ -363,13 +352,13 @@ void BluetoothDevice::barometerDetailsDiscovered(QLowEnergyService::ServiceState
qCDebug(boot2QtDemos)<<"characteristic:"<<id.toString();
if (id.toString().contains("f000aa41-0451-4000-b000-000000000000")) {
- baroService->writeDescriptor(characteristic.descriptors().at(0), QByteArray::fromHex(DISABLE_NOTIF_STR));
+ baroService->writeDescriptor(characteristic.descriptors().at(0), QByteArray::fromHex(ENABLE_NOTIF_STR));
}
if (id.toString().contains("f000aa42-0451-4000-b000-000000000000")) {
baroService->writeCharacteristic(characteristic, QByteArray::fromHex(START_MEASUREMENT_STR), QLowEnergyService::WriteWithResponse); // Start
}
if (id.toString().contains("f000aa44-0451-4000-b000-000000000000")) {
- baroService->writeCharacteristic(characteristic, QByteArray::fromHex(SLOW_TIMER_TIMEOUT_STR), QLowEnergyService::WriteWithResponse); // Period 1 second
+ baroService->writeCharacteristic(characteristic, QByteArray::fromHex(MEDIUM_TIMER_TIMEOUT_STR), QLowEnergyService::WriteWithResponse); // Period 1 second
}
}
m_barometerMeasurementStarted = true;
@@ -394,7 +383,7 @@ void BluetoothDevice::humidityDetailsDiscovered(QLowEnergyService::ServiceState
qCDebug(boot2QtDemos)<<"characteristic:"<<id.toString();
if (id.toString().contains("f000aa21-0451-4000-b000-000000000000")) {
- humidityService->writeDescriptor(characteristic.descriptors().at(0), QByteArray::fromHex(DISABLE_NOTIF_STR));
+ humidityService->writeDescriptor(characteristic.descriptors().at(0), QByteArray::fromHex(ENABLE_NOTIF_STR));
}
if (id.toString().contains("f000aa22-0451-4000-b000-000000000000")) {
humidityService->writeCharacteristic(characteristic, QByteArray::fromHex(START_MEASUREMENT_STR), QLowEnergyService::WriteWithResponse); // Start
@@ -425,7 +414,7 @@ void BluetoothDevice::lightIntensityDetailsDiscovered(QLowEnergyService::Service
qCDebug(boot2QtDemos)<<"characteristic:"<<id.toString();
if (id.toString().contains("f000aa71-0451-4000-b000-000000000000")) {
- lightService->writeDescriptor(characteristic.descriptors().at(0), QByteArray::fromHex(DISABLE_NOTIF_STR));
+ lightService->writeDescriptor(characteristic.descriptors().at(0), QByteArray::fromHex(ENABLE_NOTIF_STR));
}
if (id.toString().contains("f000aa72-0451-4000-b000-000000000000")) {
lightService->writeCharacteristic(characteristic, QByteArray::fromHex(START_MEASUREMENT_STR), QLowEnergyService::WriteWithResponse); // Start
@@ -440,8 +429,13 @@ void BluetoothDevice::lightIntensityDetailsDiscovered(QLowEnergyService::Service
void BluetoothDevice::motionDetailsDiscovered(QLowEnergyService::ServiceState newstate)
{
+ // reset the time once more before we start to receive measurements.
+ lastMilliseconds = QDateTime::currentMSecsSinceEpoch();
+
if (newstate == QLowEnergyService::ServiceDiscovered) {
- connect(motionService, &QLowEnergyService::characteristicWritten, this, &BluetoothDevice::startTimers);
+ connect(motionService, &QLowEnergyService::characteristicWritten, [=]() {
+ qCDebug(boot2QtDemos) << "Wrote Characteristic - gyro";
+ });
connect(motionService, static_cast<void(QLowEnergyService::*)(QLowEnergyService::ServiceError)>(&QLowEnergyService::error),
[=](QLowEnergyService::ServiceError newError) {
@@ -454,65 +448,19 @@ void BluetoothDevice::motionDetailsDiscovered(QLowEnergyService::ServiceState ne
qCDebug(boot2QtDemos)<<"characteristic:"<<id.toString();
if (id.toString().contains("f000aa81-0451-4000-b000-000000000000")) {
- motionService->writeDescriptor(characteristic.descriptors().at(0), QByteArray::fromHex(DISABLE_NOTIF_STR));
+ motionService->writeDescriptor(characteristic.descriptors().at(0), QByteArray::fromHex(ENABLE_NOTIF_STR));
}
if (id.toString().contains("f000aa82-0451-4000-b000-000000000000")) {
motionService->writeCharacteristic(characteristic, QByteArray::fromHex(MOVEMENT_ENABLE_SENSORS_BITMASK_VALUE), QLowEnergyService::WriteWithResponse);
}
if (id.toString().contains("f000aa83-0451-4000-b000-000000000000")) {
- motionService->writeCharacteristic(characteristic, QByteArray::fromHex("0a"), QLowEnergyService::WriteWithResponse);
+ motionService->writeCharacteristic(characteristic, QByteArray::fromHex(RAPID_TIMER_TIMEOUT_STR), QLowEnergyService::WriteWithResponse);
}
}
m_motionMeasurementStarted = true;
}
}
-void BluetoothDevice::startTimers() {
- qCDebug(boot2QtDemos) << "Wrote Characteristic - gyro, starting timers.";
- if (!slowTimer) {
- slowTimer = new QTimer(this);
- connect(slowTimer, SIGNAL(timeout()), this, SLOT(slowTimerExpired()));
- slowTimer->start(SLOW_TIMER_MS);
- }
- if (!mediumTimer) {
- mediumTimer = new QTimer(this);
- connect(mediumTimer, SIGNAL(timeout()), this, SLOT(mediumTimerExpired()));
- mediumTimer->start(MEDIUM_TIMER_MS);
- }
- if (!rapidTimer) {
- rapidTimer = new QTimer(this);
- connect(rapidTimer, SIGNAL(timeout()), this, SLOT(rapidTimerExpired()));
- rapidTimer->start(RAPID_TIMER_MS);
- }
-}
-
-void BluetoothDevice::slowTimerExpired()
-{
- if (irTemperatureService && m_temperatureMeasurementStarted) {
- queueReadRequest(temperatureCharacteristic);
- }
- if (baroService && m_barometerMeasurementStarted) {
- queueReadRequest(barometerCharacteristic);
- }
- if (humidityService && m_humidityMeasurementStarted){
- queueReadRequest(humidityCharacteristic);
- }
-}
-
-void BluetoothDevice::mediumTimerExpired()
-{
- if (lightService && m_lightIntensityMeasurementStarted){
- queueReadRequest(lightCharacteristic);
- }
-}
-
-void BluetoothDevice::rapidTimerExpired()
-{
- if (motionService && m_motionMeasurementStarted) {
- queueReadRequest(motionCharacteristic);
- }
-}
-
void BluetoothDevice::characteristicsRead(const QLowEnergyCharacteristic &info, const QByteArray &value)
{
switch (info.handle())
@@ -536,9 +484,6 @@ void BluetoothDevice::characteristicsRead(const QLowEnergyCharacteristic &info,
qWarning() << "Invalid handle" << info.handle() << "in characteristicsRead!";
break;
}
- delete readRequestQueue.takeFirst();
- // Response got, now we can send new request.
- sendFirstFromQueue();
}
void BluetoothDevice::setState(BluetoothDevice::DeviceState state)
@@ -549,76 +494,22 @@ void BluetoothDevice::setState(BluetoothDevice::DeviceState state)
}
}
-bool BluetoothDevice::isNotInQueue(CharacteristicType characteristic)
-{
- bool characteristicFound = false;
- QVector<QueueData*>::const_iterator i;
- for (i = readRequestQueue.constBegin(); i != readRequestQueue.constEnd(); ++i) {
- if (characteristic == (*i)->typeToSend) {
- characteristicFound = true;
- break;
- }
- }
- return !characteristicFound;
-}
-
-void BluetoothDevice::queueReadRequest(CharacteristicType characteristicToRead)
-{
- if (isNotInQueue(characteristicToRead)) {
- readRequestQueue.append(new QueueData(characteristicToRead));
- // Try to send. If there is a request ongoing, this does nothing.
- sendFirstFromQueue();
- } else {
- qWarning() << "tried to add request of type " << characteristicToRead << " to queue before previous response was received!";
- }
-}
-
-void BluetoothDevice::sendFirstFromQueue()
+double BluetoothDevice::convertIrTemperatureAPIReadingToCelsius(quint16 rawReading)
{
- while (readRequestQueue.length() &&
- (false == readRequestQueue.first()->alreadySent)) {
- readRequestQueue.first()->alreadySent = true;
- switch (readRequestQueue.first()->typeToSend)
- {
- case temperatureCharacteristic:
- if (irTemperatureService)
- irTemperatureService->readCharacteristic(irTemperatureService->characteristic(QUuid(QString("f000aa01-0451-4000-b000-000000000000"))));
- break;
- case humidityCharacteristic:
- if (humidityService)
- humidityService->readCharacteristic(humidityService->characteristic(QUuid(QString("f000aa21-0451-4000-b000-000000000000"))));
- break;
- case barometerCharacteristic:
- if (baroService)
- baroService->readCharacteristic(baroService->characteristic(QUuid(QString("f000aa41-0451-4000-b000-000000000000"))));
- break;
- case motionCharacteristic:
- if (motionService)
- motionService->readCharacteristic(motionService->characteristic(QUuid(QString("f000aa81-0451-4000-b000-000000000000"))));
- break;
- case lightCharacteristic:
- if (lightService)
- lightService->readCharacteristic(lightService->characteristic(QUuid(QString("f000aa71-0451-4000-b000-000000000000"))));
- break;
- default:
- delete readRequestQueue.takeFirst();
- break;
- }
- }
+ // Compute and filter final value according to TI Bluetooth LE API
+ const float SCALE_LSB = 0.03125;
+ int it = (int)((rawReading) >> 2);
+ float t = (float)it;
+ return t * SCALE_LSB;
}
void BluetoothDevice::irTemperatureReceived(const QByteArray &value)
{
- //Merge bytes
- unsigned int temperature_raw = (((quint8)value.at(3)) << 8) + ((quint8)value.at(2));
- double temperature = static_cast<double>(temperature_raw);
-
- //Compute and filter final value
- if (temperature < 32768)
- temperature = temperature/128.0; //Positive temperature values
- else if (temperature > 32768)
- temperature = (temperature - 65536) / 128.0; //Negative temperature values
- emit temperatureChanged(temperature);
+ const unsigned int rawObjectTemperature = (((quint8)value.at(3)) << 8) + ((quint8)value.at(2));
+ const double objectTemperature = convertIrTemperatureAPIReadingToCelsius(rawObjectTemperature);
+ const unsigned int rawAmbientTemperature = (((quint8)value.at(1)) << 8) + ((quint8)value.at(0));
+ const double ambientTemperature = convertIrTemperatureAPIReadingToCelsius(rawAmbientTemperature);
+ emit temperatureChanged(ambientTemperature, objectTemperature);
}
void BluetoothDevice::barometerReceived(const QByteArray &value)
@@ -635,10 +526,10 @@ void BluetoothDevice::barometerReceived(const QByteArray &value)
}
double temperature = static_cast<double>(temperature_raw);
- temperature /= 100;
+ temperature /= BAROMETER_API_READING_DIVIDER;
double barometer = static_cast<double>(barometer_raw);
- barometer /= 100;
+ barometer /= BAROMETER_API_READING_DIVIDER;
emit barometerChanged(temperature, barometer);
}
@@ -647,7 +538,7 @@ void BluetoothDevice::humidityReceived(const QByteArray &value)
//Merge bytes
unsigned int humidity_raw = (((quint8)value.at(3)) << 8) + ((quint8)value.at(2));
double humidity = static_cast<double>(humidity_raw);
- humidity = (humidity / 65536)*100;
+ humidity = humidity * HUMIDITY_API_READING_MULTIPLIER;
emit humidityChanged(humidity);
}
@@ -660,6 +551,7 @@ void BluetoothDevice::lightIntensityReceived(const QByteArray &value)
m = lightIntensity_raw & 0x0FFF;
e = (lightIntensity_raw & 0xF000) >> 12;
+ // Compute and final value according to TI Bluetooth LE API
double lightIntensity = ((double)m) * (0.01 * (double)qPow(2.0,(qreal)e));
emit lightIntensityChanged(lightIntensity);
}
@@ -667,7 +559,9 @@ void BluetoothDevice::lightIntensityReceived(const QByteArray &value)
void BluetoothDevice::motionReceived(const QByteArray &value)
{
static MotionSensorData data;
- data.msSincePreviousData = attitudeChangeInterval.restart();
+ data.msSincePreviousData = lastMilliseconds;
+ lastMilliseconds = QDateTime::currentMSecsSinceEpoch();
+ data.msSincePreviousData = lastMilliseconds - data.msSincePreviousData;
movement_data_t values;
quint8* writePtr = (quint8*)(&values);
@@ -679,13 +573,13 @@ void BluetoothDevice::motionReceived(const QByteArray &value)
// Data is in little endian. Fix here if needed.
//Convert gyroscope and accelometer readings to proper units
- data.gyroScope_x = (double(values.gyrox) * 500) / 65536;
- data.gyroScope_y = (double(values.gyroy) * 500) / 65536;
- data.gyroScope_z = (double(values.gyroz) * 500) / 65536;
+ data.gyroScope_x = double(values.gyrox) * GYROSCOPE_API_READING_MULTIPLIER;
+ data.gyroScope_y = double(values.gyroy) * GYROSCOPE_API_READING_MULTIPLIER;
+ data.gyroScope_z = double(values.gyroz) * GYROSCOPE_API_READING_MULTIPLIER;
// Accelometer at 8G
- data.accelometer_x = (double(values.accelx)*8) / 32.768;
- data.accelometer_y = (double(values.accely)*8) / 32.768;
- data.accelometer_z = (double(values.accelz)*8) / 32.768;
+ data.accelometer_x = double(values.accelx) * ACCELOMETER_API_READING_MULTIPLIER;
+ data.accelometer_y = double(values.accely) * ACCELOMETER_API_READING_MULTIPLIER;
+ data.accelometer_z = double(values.accelz) * ACCELOMETER_API_READING_MULTIPLIER;
data.magnetometer_x = double(values.magnetomx);
data.magnetometer_y = double(values.magnetomy);
data.magnetometer_z = double(values.magnetomz);