summaryrefslogtreecommitdiffstats
path: root/tradeshow/iot-sensortag/bluetoothdevice.cpp
diff options
context:
space:
mode:
authorOtto Ryynänen <otto.ryynanen@qt.io>2017-01-30 16:30:13 +0200
committerKari Hautamäki <kari.hautamaki@qt.io>2017-01-31 11:15:58 +0000
commit4a7c0e5841b2bb69ddaef2c9620c443934d194ee (patch)
tree0997ae3fdb9de74ace3d140724b96fe1fdde386d /tradeshow/iot-sensortag/bluetoothdevice.cpp
parent632e35db6d6ef6bf15891e486da983aabfb740b3 (diff)
SensorTag changed to broadcasting mode form read-resp mode
Sensortag now sends data according to set intervals and app only listens to signals. Timers removed as they are no longer needed. Both ambient and object temperature read and converted properly. Cloud data updated with dedicated abient and object temperatures. Version is now 1.1 (backwards compatible). Mock data reflects to reality better. Change-Id: I6a0325a513c1a054322f18e68d2b15c474db3ee5 Reviewed-by: Kari Hautamäki <kari.hautamaki@qt.io>
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);