diff --git a/Manager.cpp b/Manager.cpp index 775c1c8..fc7a372 100644 --- a/Manager.cpp +++ b/Manager.cpp @@ -9,7 +9,8 @@ #include #include #include -#include > +#include +#include #include #include @@ -23,6 +24,7 @@ const std::string NUC1 = "38:de:ad:6d:77:25"; const std::string NUC2 = "38:de:ad:6d:60:ff"; const std::string NUC3 = "1c:1b:b5:ef:a2:9a"; const std::string NUC4 = "1c:1b:b5:ec:d1:82"; +const std::string NUC5 = "d0:c6:37:bc:5c:41"; static long long startTime = 0; @@ -49,178 +51,81 @@ Manager::Manager() { } +void Manager::test() { -void Manager::trigger() { +} - QString folder = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + "/ftm/"; - - QString prefix = GetCurrentTimeForFileName(); - - dataLogger = std::make_shared(folder+"/"+prefix+"_ftm.txt"); - uwbLogger = std::make_shared(folder+"/"+prefix+"_uwb.txt"); - gtLogger = std::make_shared(folder+"/"+prefix+"_gt.txt"); - - if (!dataLogger->exists()) { - // create the folder, if necessary - QDir dir(folder); - if (!dir.exists()) { - qWarning("creating new folder"); - if (!dir.mkpath(".")) { - qWarning() << "Failed to create new folder"; - } - } - } - - if (!dataLogger->open(QIODevice::ReadWrite)) { - qWarning() << "Failed to create data logger file" << dataLogger->fileName(); - dataLogger = nullptr; - } - - if (!uwbLogger->open(QIODevice::ReadWrite)) { - qWarning() << "Failed to create uwb data logger file" << uwbLogger->fileName(); - uwbLogger = nullptr; +bool Manager::trigger() { + if (isRunning) { + stop(); + } else { + start(); } - if (!gtLogger->open(QIODevice::ReadWrite)) { - qWarning() << "Failed to create gt data logger file" << gtLogger->fileName(); - gtLogger = nullptr; - } + return isRunning; +} +void Manager::start() { startTime = nowInMsec(); #ifdef ANDROID + //QAndroidJniObject::callStaticMethod("android/net/wifi/UWB", "start", "()I"); + QAndroidJniObject::callStaticMethod("android/net/wifi/RTT", "start", "()I"); - QAndroidJniObject::callStaticMethod("android/net/wifi/UWB", "start", "()I"); - QAndroidJniObject::callStaticMethod("android/net/wifi/RTT", "start", "()I"); - - + isRunning = true; #else + std::random_device rd; + std::mt19937 gen{rd()}; + std::normal_distribution d{5000,1000}; + //std::uniform_real d{0, 500}; - //onData("38:de:ad:6d:77:25;FAILED"); - onData("1337;"+NUC1+";6230;1231"); - onData("1337;"+NUC2+";3430;3423"); - onData("1337;"+NUC3+";5630;2341"); - onData("1337;"+NUC4+";8830;2241"); + WifiRttResult res; + res.success = 1; + res.mac = NUC1; + res.numAttemptedMeas = 8; + res.numSuccessfullMeas = 8; + for(int n=0; n<1000; ++n) { + res.timeMS = nowInMsec(); + res.distMM = static_cast(std::round(d(gen))); + + onWifiData(res); + } #endif } + void Manager::stop() { #ifdef ANDROID QAndroidJniObject::callStaticMethod("android/net/wifi/RTT", "stop", "()I"); - QAndroidJniObject::callStaticMethod("android/net/wifi/UWB", "stop", "()I"); + //QAndroidJniObject::callStaticMethod("android/net/wifi/UWB", "stop", "()I"); #endif - dataLogger->flush(); - dataLogger->close(); - - uwbLogger->flush(); - uwbLogger->close(); - - gtLogger->flush(); - gtLogger->close(); + isRunning = false; } +int Manager::runTimeInMs() const { + return static_cast(nowInMsec() - startTime); +} void Manager::manualCheckpoint() { qDebug() << "Manual checkpoint"; - - long long timestamp = nowInMsec(); - timestamp -= startTime; - - QTextStream out(gtLogger.get()); - - out << timestamp << endl; } -void Manager::onData(std::string str) { +void Manager::onWifiData(WifiRttResult result) { + qDebug() << result; - qDebug() << QString(str.c_str()); + if (result.success == 1 && result.numSuccessfullMeas > 3) { + int nucIdx = 0; - long long timestamp = nowInMsec(); - timestamp -= startTime; + if(NUC1 == result.mac) {nucIdx = 0;} + if(NUC2 == result.mac) {nucIdx = 1;} + if(NUC3 == result.mac) {nucIdx = 2;} + if(NUC4 == result.mac) {nucIdx = 3;} + if(NUC5 == result.mac) {nucIdx = 4;} - bool successfullMeas = true; - std::stringstream lineStream(str); - std::string cell; - - std::string mac; - - int distIndex = 0; - int i = 0; - const float alpha = 0.7f; - - QTextStream out(dataLogger.get()); - - out << timestamp << ";"; - - while (std::getline(lineStream, cell, ';')) { - - switch(i) { - - case 0: { - // success flag - successfullMeas = (cell == "1"); - - out << (successfullMeas ? 1 : 0) << ";"; - break; - } - case 1: { - // timestamp; ignore; - break; - } - case 2: { - if(NUC1 == cell) {distIndex = 0;} - if(NUC2 == cell) {distIndex = 1;} - if(NUC3 == cell) {distIndex = 2;} - if(NUC4 == cell) {distIndex = 3;} - - out << QString(cell.c_str()) << ";"; - break; - } - - case 3: { - if (successfullMeas) { - _dist[distIndex] = std::stoi(cell) + _offset; - //_dist[distIndex] = _dist[distIndex] * alpha + atoi(cell.c_str()) * (1-alpha); - } else { - _dist[distIndex] = 0; - } - - out << _dist[distIndex] << ";"; - break; - } - - case 4: { - if (successfullMeas) { - _stdDev[distIndex] = atoi(cell.c_str()); - } else { - _stdDev[distIndex] = 0; - } - - out << _stdDev[distIndex] << ";"; - break; - } - - case 5: { - // RSSI - - out << cell.c_str() << ";"; - break; - } - } - ++i; - } - - out << endl; - - -// if (dataLogger && successfullMeas) { -// dataLogger->write(str.c_str()); -// dataLogger->write("\n"); -// } - - emit distChanged(); + emit newDistMeas(nucIdx, result.distMM); + } } void Manager::onUWBData(std::vector data) { @@ -245,16 +150,9 @@ void Manager::onUWBData(std::vector data) { case 0x863B: _uwbDist[2] = static_cast(dist.distance); break; case 0x58B4: _uwbDist[3] = static_cast(dist.distance); break; } - - if (uwbLogger) { - - QTextStream out(uwbLogger.get()); - - out << timestamp << ";" << "1;" << "DW" << hex << dist.nodeID << dec << ";" << dist.distance << endl; - } } - emit distChanged(); + emit uwbDistChanged(); } Manager mgmt; @@ -262,19 +160,34 @@ Manager mgmt; #ifdef ANDROID extern "C" { - JNIEXPORT void JNICALL Java_android_net_wifi_RTT_onRTTComplete(JNIEnv* env, jobject jobj, jbyteArray arrayID) { - (void) env; (void) jobj; - jsize length = env->GetArrayLength(arrayID); - jbyte* data = env->GetByteArrayElements(arrayID, 0); - std::string str((char*)data, length); - env->ReleaseByteArrayElements(arrayID, data, JNI_ABORT); - mgmt.onData(str); - } + JNIEXPORT void JNICALL Java_android_net_wifi_RTT_onRttData(JNIEnv* env, jobject jobj, jint success, jbyteArray macString, jlong timeMS, jint distMM, jint distStdDevMM, jint numMeas, jint numSuccessfullMeas, jint rssi) { + (void) env; + (void) jobj; + + jsize length = env->GetArrayLength(macString); + jbyte* data = env->GetByteArrayElements(macString, nullptr); + std::string str(reinterpret_cast(data), static_cast(length)); + env->ReleaseByteArrayElements(macString, data, JNI_ABORT); + + WifiRttResult result; + result.success = success; + result.mac = str; + result.timeMS = timeMS; + result.distMM = distMM; + result.distStdDevMM = distStdDevMM; + result.numAttemptedMeas = numMeas; + result.numSuccessfullMeas = numSuccessfullMeas; + result.rssi = rssi; + + mgmt.onWifiData(result); + } JNIEXPORT void JNICALL Java_android_net_wifi_UWB_onUWBComplete(JNIEnv* env, jobject jobj, jbyteArray arrayID) { - (void) env; (void) jobj; + (void) env; + (void) jobj; + jsize length = env->GetArrayLength(arrayID); - jbyte* data = env->GetByteArrayElements(arrayID, 0); + jbyte* data = env->GetByteArrayElements(arrayID, nullptr); std::vector c_data; c_data.assign(reinterpret_cast(data), reinterpret_cast(data)+length); env->ReleaseByteArrayElements(arrayID, data, JNI_ABORT); diff --git a/Manager.h b/Manager.h index 6f29d03..9a11ffc 100644 --- a/Manager.h +++ b/Manager.h @@ -1,69 +1,68 @@ #ifndef MANAGER_H #define MANAGER_H +#include #include #include +#include +#include +#include + +struct WifiRttResult { + int success; + std::string mac; + int64_t timeMS; + int distMM; + int distStdDevMM; + int numAttemptedMeas; + int numSuccessfullMeas; + int rssi; +}; + +static QDebug operator<<(QDebug dbg, const WifiRttResult& v) +{ + dbg << v.success << ";" + << QString::fromStdString(v.mac) << ";" + << v.timeMS << ";" + << v.distMM << ";" + << v.distStdDevMM << ";" + << v.numSuccessfullMeas << "/" << v.numAttemptedMeas << ";" + << v.rssi; + return dbg; +} + class Manager : public QObject { Q_OBJECT private: - float _dist[4]; - float _stdDev[4]; - float _offset = 500; - float _uwbDist[4]; - std::shared_ptr dataLogger; - std::shared_ptr uwbLogger; - std::shared_ptr gtLogger; + bool isRunning = false; public: + Q_PROPERTY(float uwbDist1 READ getUwbDist1() NOTIFY uwbDistChanged) + Q_PROPERTY(float uwbDist2 READ getUwbDist2() NOTIFY uwbDistChanged) + Q_PROPERTY(float uwbDist3 READ getUwbDist3() NOTIFY uwbDistChanged) + Q_PROPERTY(float uwbDist4 READ getUwbDist4() NOTIFY uwbDistChanged) - Q_PROPERTY(float dist1 READ getDist1() NOTIFY distChanged) - Q_PROPERTY(float dist2 READ getDist2() NOTIFY distChanged) - Q_PROPERTY(float dist3 READ getDist3() NOTIFY distChanged) - Q_PROPERTY(float dist4 READ getDist4() NOTIFY distChanged) - - Q_PROPERTY(float stdDev1 READ getStdDev1() NOTIFY distChanged) - Q_PROPERTY(float stdDev2 READ getStdDev2() NOTIFY distChanged) - Q_PROPERTY(float stdDev3 READ getStdDev3() NOTIFY distChanged) - Q_PROPERTY(float stdDev4 READ getStdDev4() NOTIFY distChanged) - - // FTM offset - Q_PROPERTY(float offset READ getOffset() WRITE setOffset() NOTIFY offsetChanged) - - Q_PROPERTY(float uwbDist1 READ getUwbDist1() NOTIFY distChanged) - Q_PROPERTY(float uwbDist2 READ getUwbDist2() NOTIFY distChanged) - Q_PROPERTY(float uwbDist3 READ getUwbDist3() NOTIFY distChanged) - Q_PROPERTY(float uwbDist4 READ getUwbDist4() NOTIFY distChanged) - - - Q_INVOKABLE void trigger(); + Q_INVOKABLE bool trigger(); + Q_INVOKABLE void start(); Q_INVOKABLE void stop(); + Q_INVOKABLE int runTimeInMs() const; + + Q_INVOKABLE void test(); + Q_INVOKABLE void manualCheckpoint(); - void onData(std::string str); + void onWifiData(WifiRttResult result); void onUWBData(std::vector data); public: - float getDist1() {return _dist[0];} - float getDist2() {return _dist[1];} - float getDist3() {return _dist[2];} - float getDist4() {return _dist[3];} - - float getStdDev1() {return _stdDev[0];} - float getStdDev2() {return _stdDev[1];} - float getStdDev3() {return _stdDev[2];} - float getStdDev4() {return _stdDev[3];} - - float getOffset() {return _offset;} - void setOffset(float value) { _offset = value; emit offsetChanged(); } - float getUwbDist1() {return _uwbDist[0];} float getUwbDist2() {return _uwbDist[1];} float getUwbDist3() {return _uwbDist[2];} @@ -71,8 +70,8 @@ public: signals: - void distChanged(); - void offsetChanged(); + void uwbDistChanged(); + void newDistMeas(int idx, int value); public: diff --git a/RTT.pro b/RTT.pro index ec0684a..0ed2d08 100644 --- a/RTT.pro +++ b/RTT.pro @@ -3,7 +3,8 @@ QT += quick android { QT += androidextras } -CONFIG += c++11 + +CONFIG += c++17 # The following define makes your compiler emit warnings if you use # any feature of Qt which as been marked deprecated (the exact warnings @@ -17,6 +18,7 @@ DEFINES += QT_DEPRECATED_WARNINGS #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ + histogramchart.cpp \ main.cpp \ Manager.cpp @@ -47,6 +49,7 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin HEADERS += \ Manager.h \ + histogramchart.h \ uwb.h DISTFILES += \ diff --git a/_android/src/RTT.java b/_android/src/RTT.java index 4d645ed..6fccf46 100644 --- a/_android/src/RTT.java +++ b/_android/src/RTT.java @@ -35,8 +35,7 @@ public class RTT { private static Thread ftmThread; private static boolean ftmRunning; - // called when a RTT is completed successfully - public static native void onRTTComplete(final byte[] result); + public static native void onRttData(int success, final byte[] mac, long timeMS, int distMM, int distStdDevMM, int numAttemptedMeas, int numSuccessfullMeas, int rssi); // result callback private static final RangingResultCallback callback = new RangingResultCallback() { @@ -52,57 +51,34 @@ public class RTT { Log.d("RTT", "onRangingResults: " + list.size()); for (final RangingResult res : list) { + int success = 0; + long timeStampInMS = 0; + MacAddress mac = res.getMacAddress(); + int dist = 0; + int stdDevDist = 0; + int rssi = 0; + int numAttemptedMeas = 0; + int numSuccessfulMeas = 0; - final MacAddress mac = res.getMacAddress(); - if (res.getStatus() == RangingResult.STATUS_SUCCESS) { - final int dist = res.getDistanceMm(); - final int stdDevDist = res.getDistanceStdDevMm(); - Log.d("RTT", mac.toString() + " " + dist + " " + stdDevDist); - } else { - Log.d("RTT", mac.toString() + " FAILED"); - } + if (res.getStatus() == RangingResult.STATUS_SUCCESS) { + success = 1; + timeStampInMS = res.getRangingTimestampMillis(); + dist = res.getDistanceMm(); + stdDevDist = res.getDistanceStdDevMm(); + rssi = res.getRssi(); + numAttemptedMeas = res.getNumAttemptedMeasurements(); + numSuccessfulMeas = res.getNumSuccessfulMeasurements(); - RTT.onRTTComplete(serialize(res)); + //Log.d("RTT", mac.toString() + " " + dist + " " + stdDevDist + " " + rssi); + } else { + //Log.d("RTT", mac.toString() + " FAILED"); + } + + onRttData(success, mac.toString().getBytes(), timeStampInMS, dist, stdDevDist, numAttemptedMeas, numSuccessfulMeas, rssi); } } }; - private static byte[] serialize(final RangingResult res) { - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try { - char delim = ';'; - boolean success = res.getStatus() == RangingResult.STATUS_SUCCESS; - - baos.write(success ? '1' : '0'); - baos.write(delim); - - baos.write(("" + System.currentTimeMillis()).getBytes()); - baos.write(delim); - - baos.write(res.getMacAddress().toString().getBytes()); - baos.write(delim); - - int distValue = 0; - int distStdDev = 0; - int rssi = 0; - - if (success) { - distValue = res.getDistanceMm(); - distStdDev = res.getDistanceStdDevMm(); - rssi = res.getRssi(); - } - - baos.write( ("" + distValue).getBytes() ); - baos.write(delim); - baos.write( ("" + distStdDev).getBytes() ); - baos.write(delim); - baos.write( ("" + rssi).getBytes() ); - - } catch (final Exception e) {;} - return baos.toByteArray(); - } - - public static int start() { if (ftmRunning) @@ -116,10 +92,11 @@ public class RTT { mainExecutor = act.getMainExecutor(); final ArrayList macs = new ArrayList<>(); - macs.add(MacAddress.fromString("38:de:ad:6d:77:25")); // NUC 1 + macs.add(MacAddress.fromString("38:de:ad:6d:77:25")); // NUC 1 macs.add(MacAddress.fromString("38:de:ad:6d:60:ff")); // NUC 2 macs.add(MacAddress.fromString("1c:1b:b5:ef:a2:9a")); // NUC 3 macs.add(MacAddress.fromString("1c:1b:b5:ec:d1:82")); // NUC 4 + macs.add(MacAddress.fromString("d0:c6:37:bc:5c:41")); // NUC 5 ftmRunning = true; diff --git a/histogramchart.cpp b/histogramchart.cpp new file mode 100644 index 0000000..7c73a25 --- /dev/null +++ b/histogramchart.cpp @@ -0,0 +1,137 @@ +#include "histogramchart.h" + +#include + +#include +#include + + + +HistogramChart::HistogramChart(QQuickItem *parent) + : QQuickPaintedItem(parent) +{ + +} + +void HistogramChart::paint(QPainter* painter) +{ + const int leftPadding = 32; + const int bottomPadding = 32; + + const int height = static_cast(this->height()); + const int width = static_cast(this->width()); + + painter->fillRect(0, 0, width, height, Qt::white); + + if (_histogram.empty()) { + return; + } + + const qreal barHeight = height - bottomPadding; + const qreal barWidth = (width - leftPadding) / static_cast(_histogram.size()); + + for (size_t i = 0; i < _histogram.size(); i++) { + int count = _histogram[i]; + + qreal h = (count / static_cast(maxBinCount)) * barHeight; + + qreal x = i * barWidth; + qreal y = barHeight - h; + + const QColor darkBlue = QColor::fromRgb(32, 74, 135); + const QColor lightBlue = QColor::fromRgb(52, 101, 164); + const QColor lighterBlue = QColor::fromRgb(114, 159, 207); + + QColor c = (lastUpdatedBinIndex == i) ? lighterBlue : lightBlue; + + QRectF barRect(x + leftPadding, y, barWidth, h); + painter->fillRect(barRect, c); + + if (i % 10 == 0) { + QRectF txtRect(x + leftPadding, barHeight, barWidth, 32); + + std::string str(16, '\0'); + std::snprintf(&str[0], str.size(), "%g", minValue + i*_binWidth); + + painter->drawText(txtRect, Qt::AlignCenter | Qt::TextDontClip, QString::fromStdString(str)); + } + } +} + +void HistogramChart::pushData(qreal value) +{ + if(_histogram.empty()) { + minValue = value; + maxValue = value; + + _histogram.resize(1); + } + else if (value > maxValue) { + + int newMaxIndex = binIndex(value); + Q_ASSERT(newMaxIndex > 0); + _histogram.resize(static_cast(newMaxIndex + 1)); + + maxValue = value; + } + else if (value < minValue) { + int oldMinIndex = binIndex(minValue); + int newMinIndex = binIndex(value); + + int diff = oldMinIndex - newMinIndex; + Q_ASSERT(diff > 0); + + _histogram.insert(_histogram.begin(), static_cast(diff), 0); + + minValue = value; + } + + int idx = binIndex(value); + + int& count = _histogram.at(static_cast(idx)); + count++; + + if (count >= maxBinCount) { + maxBinCount = count; + maxBinIndex = idx; + } + lastUpdatedBinIndex = static_cast(idx); + + stats.add(value); + + update(); +} + +int HistogramChart::binIndex(qreal value) const +{ + Q_ASSERT(!std::isnan(minValue)); + return static_cast( std::floor( (value-minValue) / _binWidth)); +} + +int HistogramChart::numberOfBins() const +{ + Q_ASSERT(!std::isnan(minValue)); + Q_ASSERT(!std::isnan(maxValue)); + return static_cast( std::ceil((maxValue - minValue)/_binWidth) ); +} + + +void HistogramChart::clear() +{ + std::fill(_histogram.begin(), _histogram.end(), 0); + + maxBinCount = 0; + stats.clear(); +} + +void HistogramChart::reset() +{ + _histogram.resize(0); + + minValue = std::numeric_limits::quiet_NaN(); + maxValue = std::numeric_limits::quiet_NaN(); + + maxBinCount = 0; + + stats.clear(); +} diff --git a/histogramchart.h b/histogramchart.h new file mode 100644 index 0000000..e097bbe --- /dev/null +++ b/histogramchart.h @@ -0,0 +1,100 @@ +#ifndef HISTOGRAMCHART_H +#define HISTOGRAMCHART_H + +#include + +#include +#include +#include + + +struct Statistics { + qreal sum = 0; + qreal sumSquares = 0; + int count = 0; + + void add(qreal v) { + sum += v; + sumSquares += v*v; + count++; + } + + void clear() { + sum = 0; + sumSquares = 0; + count = 0; + } + + int getCount() const { + return count; + } + + qreal getMean() const { + return sum / static_cast(count); + } + + qreal getStdDev() const { + const qreal x = sumSquares / static_cast(count); + const qreal e = getMean(); + return std::sqrt(x - (e*e)); + } +}; + +class HistogramChart : public QQuickPaintedItem +{ + Q_OBJECT + Q_PROPERTY(QString name READ name WRITE setName) + Q_PROPERTY(QColor color READ color WRITE setColor) + Q_PROPERTY(qreal binWidth READ binWidth WRITE setBinWidth) + Q_PROPERTY(qreal mean READ mean) + Q_PROPERTY(qreal stdDev READ stdDev) + Q_PROPERTY(int totalCount READ totalCount) + Q_PROPERTY(qreal maxBinValue READ maxBinValue) + +public: + HistogramChart(QQuickItem* parent = nullptr); + + QString name() const { return m_name; } + void setName(const QString &name) { m_name = name; } + + QColor color() const { return m_color; } + void setColor(const QColor& color) { m_color = color; } + + qreal binWidth() const { return _binWidth; } + void setBinWidth(qreal newBinWidth) { _binWidth = newBinWidth; reset(); } + + qreal mean() const { return stats.getMean(); } + qreal stdDev() const { return stats.getStdDev(); } + int totalCount() const { return stats.getCount(); } + qreal maxBinValue() const { return maxBinIndex * binWidth(); } + + void paint(QPainter *painter); + + Q_INVOKABLE void pushData(qreal value); + + Q_INVOKABLE void clear(); // soft reset + Q_INVOKABLE void reset(); // hard reset + +public: + int numberOfBins() const; + int binIndex(qreal value) const; + + +private: + QString m_name; + QColor m_color; + + std::vector _histogram; + qreal _binWidth = 100; + qreal minValue = std::numeric_limits::quiet_NaN(); + qreal maxValue = std::numeric_limits::quiet_NaN(); + + size_t lastUpdatedBinIndex = 0; + int maxBinCount = 0; + int maxBinIndex = 0; + + // Satistics + Statistics stats; +}; + +#endif // HISTOGRAMCHART_H diff --git a/main.cpp b/main.cpp index dcebc85..ffeb905 100644 --- a/main.cpp +++ b/main.cpp @@ -2,6 +2,9 @@ #include #include +#include + +#include "histogramchart.h" #include "Manager.h" extern Manager mgmt; @@ -10,7 +13,10 @@ int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - QGuiApplication app(argc, argv); + QGuiApplication app(argc, argv); + + qmlRegisterType("Test", 1, 0, "HistogramChart"); + QQmlApplicationEngine engine; @@ -18,6 +24,8 @@ int main(int argc, char *argv[]) { engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + engine.rootObjects().first()->dumpObjectTree(); + if (engine.rootObjects().isEmpty()) return -1; diff --git a/main.qml b/main.qml index b656d3c..d9649d6 100644 --- a/main.qml +++ b/main.qml @@ -3,217 +3,96 @@ import QtQuick.Window 2.2 import QtQuick.Controls 2.4 import QtQuick.Layouts 1.3 +import Test 1.0 + Window { id: window + objectName: "qmlWindow" visible: true width: 640 height: 680 title: qsTr("Hello World") - Column { - id: column + Connections { + target: mgmt - Label { - text: "FTM dist1: " + ((mgmt.dist1 ? mgmt.dist1+sld1.value : 0)/1000).toFixed(2); - } + onNewDistMeas: { - Label { - text: "FTM dist2: " + ((mgmt.dist2 ? mgmt.dist2+sld1.value : 0)/1000).toFixed(2); - } - - Label { - text: "FTM dist3: " + ((mgmt.dist3 ? mgmt.dist3+sld1.value : 0)/1000).toFixed(2); - } - - Label { - text: "FTM dist4: " + ((mgmt.dist4 ? mgmt.dist4+sld1.value : 0)/1000).toFixed(2); - } - - - Slider { - width: 400; - id: sld1; - from: -1000; - to: 1000; - value: mgmt.offset; - onValueChanged: { - mgmt.offset = value; - leCanvas.requestPaint(); + if (cbNUC.currentIndex == idx) { + chart.pushData(value); + lblMean.text = "Mean: " + chart.mean.toFixed(3) + "\nStdDev: " + chart.stdDev.toFixed(3); + lblCount.text = "Count: " + chart.totalCount + "\nMax bin: " + chart.maxBinValue.toFixed(3); + lblRunTime.text = "Time: " + (mgmt.runTimeInMs() / 1000.0).toFixed(0) + "s"; } - } - - Label { - text: "offset: " + sld1.value; - } - - Label { - text: "UWB dist1: " + mgmt.uwbDist1.toFixed(2); } + } - Label { - text: "UWB dist2: " + mgmt.uwbDist2.toFixed(2); - } + GridLayout { + anchors.fill: parent; - Label { - text: "UWB dist3: " + mgmt.uwbDist3.toFixed(2); - } + Row { + Layout.row: 0; + Layout.column: 0; + spacing: 3; - Label { - text: "UWB dist4: " + mgmt.uwbDist4.toFixed(2); - } - - - Connections { - target: mgmt - onDistChanged: leCanvas.requestPaint(); - } - - - RowLayout { - Button { - text: "party hard"; - onClicked: mgmt.trigger(); - } - - Button { - text: "stop" - onClicked: mgmt.stop(); - } - Button { - text: "reset sld" - onClicked: { - sld1.value = 0; + ComboBox { + id: cbNUC; + model: ["NUC1", "NUC2", "NUC3", "NUC4", "NUC5"]; + onCurrentIndexChanged: { + chart.reset(); } } + Button { - text: "High Five" + id: btnTrigger; + text: "Start"; onClicked: { - mgmt.manualCheckpoint(); + if (mgmt.trigger()) { + // running + btnTrigger.text = "Stop"; + } else { + btnTrigger.text = "Start"; + } + } + } + + Button { + text: "Reset" + onClicked: { + chart.reset(); + chart.update(); } } } + Row { + Layout.row: 1; + Layout.column: 0; + spacing: 5; - } - - Canvas { - - id: leCanvas; - anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.leftMargin: 0 - anchors.bottom: parent.bottom - anchors.bottomMargin: 0 - anchors.top: column.bottom - anchors.topMargin: 20 - - readonly property double s: 0.02; - - - function leArc(ctx, cx, cy, dist, stdDev, caption) { - - // center circle - ctx.fillStyle = (dist < 0 ? "#FF0000" : "#000000"); - ctx.beginPath(); - ctx.arc(cx*s, cy*s, 2, 0, 360); - ctx.fill(); - - ctx.font = "12px Arial"; - ctx.fillText(caption, cx*s, cy*s); - - // error circle -// ctx.beginPath(); -// ctx.arc(cx*s, cy*s, (dist+sld1.value)*s, 0, 360); -// ctx.closePath(); -// ctx.lineWidth = stdDev*s*0.5; -// ctx.strokeStyle = "#66000000"; -// ctx.stroke(); - - // circle - if (dist > 0) { - ctx.lineWidth = 1; - ctx.strokeStyle = "#aa000000"; - ctx.beginPath(); - ctx.arc(cx*s, cy*s, dist*s, 0, 360); - ctx.stroke(); + Label { + id: lblMean; } - } - onPaint: { - var ctx = getContext("2d") + Label { + id: lblCount; + } - ctx.reset(); + Label { + id: lblRunTime; + } + } - ctx.fillStyle = "#dddddd"; - ctx.clearRect(0, 0, leCanvas.width, leCanvas.height); + HistogramChart { + Layout.row: 2; + Layout.column: 0; + Layout.fillHeight: true; + Layout.fillWidth: true; - //ctx.strokeStyle = Qt.rgba(0, 0, 0, 1) - //ctx.lineWidth = 1 + id: chart + objectName: "qmlChart" + } -// var ox = 4000; -// var oy = 4000; - -// var cx1 = ox+0; -// var cy1 = oy+0; - -// var cx2 = ox+0; -// var cy2 = oy+7250; - -// var cx3 = ox+9000; -// var cy3 = oy+7250; - -// var cx4 = ox+9000; -// var cy4 = oy+0; - - var ox = 4000; - var oy = 4000; - - var cx1 = ox+0; - var cy1 = oy+0; - - var cx2 = ox+9000; - var cy2 = oy+0; - - var cx3 = ox+9000; - var cy3 = oy+6200; - - var cx4 = ox+0; - var cy4 = oy+6200; - - leArc(ctx, cx1, cy1, mgmt.dist1, mgmt.stdDev1, 1); - leArc(ctx, cx2, cy2, mgmt.dist2, mgmt.stdDev2, 2); - leArc(ctx, cx3, cy3, mgmt.dist3, mgmt.stdDev3, 3); - leArc(ctx, cx4, cy4, mgmt.dist4, mgmt.stdDev4, 4); - - var sigma = 2000; - var stepSize = 333; - - var maxP = Math.pow( 1.0 / Math.sqrt(2*Math.PI*sigma), 4.1); - -// for (var y = 0; y < leCanvas.height/s; y += stepSize) { -// for (var x = 0; x < leCanvas.width/s; x += stepSize) { - -// var d1 = Math.sqrt( Math.pow(x-cx1, 2) + Math.pow(y-cy1, 2) ) - (mgmt.dist1-sld1.value); -// var d2 = Math.sqrt( Math.pow(x-cx2, 2) + Math.pow(y-cy2, 2) ) - (mgmt.dist2-sld1.value); -// var d3 = Math.sqrt( Math.pow(x-cx3, 2) + Math.pow(y-cy3, 2) ) - (mgmt.dist3-sld1.value); -// var d4 = Math.sqrt( Math.pow(x-cx4, 2) + Math.pow(y-cy4, 2) ) - (mgmt.dist4-sld1.value); - -// var p = 1; -// p *= 1.0 / Math.sqrt(2*Math.PI*sigma) * Math.exp( - d1*d1/(2*sigma*sigma) ); -// p *= 1.0 / Math.sqrt(2*Math.PI*sigma) * Math.exp( - d2*d2/(2*sigma*sigma) ); -// p *= 1.0 / Math.sqrt(2*Math.PI*sigma) * Math.exp( - d3*d3/(2*sigma*sigma) ); -// p *= 1.0 / Math.sqrt(2*Math.PI*sigma) * Math.exp( - d4*d4/(2*sigma*sigma) ); - -// //p = Math.pow(p, 1); - -// if (p > maxP / 50) { -// ctx.fillStyle = Qt.rgba(1,0,0, p/maxP); -// ctx.fillRect(x*s, y*s, stepSize*s, stepSize*s); -// } -// } -// } - } - } + } }