we are now able to record bluetooth fingerprints

for this, we use the same ui interface and fingerprint positions as wifi. if wifi has done 30 scans, also the ble
scans will be stopped. this is just a quick and dirte solution, as changing the gui completely for this two options
was to time consuming
This commit is contained in:
mail@toni-fetzer.de
2019-06-06 17:42:11 +02:00
parent 8a1f8430fb
commit ef6066ae14
9 changed files with 420 additions and 293 deletions

View File

@@ -22,6 +22,9 @@
#include <Indoor/sensors/radio/setup/WiFiOptimizerLogDistCeiling.h> #include <Indoor/sensors/radio/setup/WiFiOptimizerLogDistCeiling.h>
#include <Indoor/sensors/radio/model/WiFiModel.h> #include <Indoor/sensors/radio/model/WiFiModel.h>
#include <Indoor/sensors/beacon/model/BeaconModel.h>
#include <Indoor/sensors/beacon/model/BeaconModelLogDistCeiling.h>
#include <Indoor/Assertions.h> #include <Indoor/Assertions.h>
#include "ui/LoggerUI.h" #include "ui/LoggerUI.h"
@@ -244,6 +247,17 @@ WiFiModel* buildWiFiModelOnce(Floorplan::IndoorMap* map, const std::string& fpFi
} }
BeaconModel* buildBLEModelOnce(Floorplan::IndoorMap* map, const std::string& fpFile, const std::string& bleModelFile){
// ask questions
const QMessageBox::StandardButton replyWiFiFP = QMessageBox::question(nullptr, "BLE", "Use Fingerprints for Bluetooth Calibration?\n\nYes: Use fingerprints and num-optimize AP-Params\nNo: Use Beacons from the map.xml (pos+params)", QMessageBox::Yes|QMessageBox::No);
BeaconModel* bleModel = new BeaconModelLogDistCeiling(map);
return bleModel;
}
void Controller::on3DButton() { void Controller::on3DButton() {
static bool use3D = false; static bool use3D = false;
@@ -272,6 +286,7 @@ void Controller::loadGrid(QDir dir) {
QFile fMap(dir.path() + "/map.xml"); QFile fMap(dir.path() + "/map.xml");
QFile fGrid(dir.path() + "/grid.dat"); QFile fGrid(dir.path() + "/grid.dat");
QFile fWiFiFP(dir.path() + "/wifi_fp.dat"); QFile fWiFiFP(dir.path() + "/wifi_fp.dat");
QFile fBLEFP(dir.path() + "/ble_fp.dat");
Assert::isTrue(fMap.exists(), "map.xml missing"); Assert::isTrue(fMap.exists(), "map.xml missing");
//Assert::isTrue(fGrid.exists(), "grid.dat missing"); //Assert::isTrue(fGrid.exists(), "grid.dat missing");
@@ -285,6 +300,7 @@ void Controller::loadGrid(QDir dir) {
//Assert::isTrue(inp.good(), "failed to open grid.dat"); //Assert::isTrue(inp.good(), "failed to open grid.dat");
const std::string sWiFiFP = fWiFiFP.fileName().toStdString(); const std::string sWiFiFP = fWiFiFP.fileName().toStdString();
const std::string sBLEFP = fBLEFP.fileName().toStdString();
// create a new, empty grid // create a new, empty grid
if (grid) {delete grid; grid = nullptr;} if (grid) {delete grid; grid = nullptr;}
@@ -302,9 +318,10 @@ void Controller::loadGrid(QDir dir) {
nav = new GridBased::NavControllerGrid(this, im, grid); nav = new GridBased::NavControllerGrid(this, im, grid);
WiFiCalibrationDataModel* wifiCalib = new WiFiCalibrationDataModel(sWiFiFP); WiFiCalibrationDataModel* wifiCalib = new WiFiCalibrationDataModel(sWiFiFP);
BLECalibrationDataModel* bleCalib = new BLECalibrationDataModel(sBLEFP);
getMapView3D()->setMap(im); getMapView3D()->setMap(im);
getMapView2D()->setMap(wifiCalib, im); getMapView2D()->setMap(wifiCalib, bleCalib, im);
getMapView3D()->showGridImportance(grid); getMapView3D()->showGridImportance(grid);
getMapView2D()->showGridImportance(grid); getMapView2D()->showGridImportance(grid);
@@ -322,6 +339,7 @@ void Controller::loadNavMesh(QDir dir) {
QFile fGrid(dir.path() + "/grid.dat"); QFile fGrid(dir.path() + "/grid.dat");
QFile fWiFiFP(dir.path() + "/wifi_fp.dat"); QFile fWiFiFP(dir.path() + "/wifi_fp.dat");
QFile fWiFiModel(dir.path() + "/wifimodel.dat"); QFile fWiFiModel(dir.path() + "/wifimodel.dat");
QFile fBLEFP(dir.path() + "/ble_fp.dat");
Assert::isTrue(fMap.exists(), "map.xml missing"); Assert::isTrue(fMap.exists(), "map.xml missing");
@@ -331,6 +349,7 @@ void Controller::loadNavMesh(QDir dir) {
const std::string sWiFiFP = fWiFiFP.fileName().toStdString(); const std::string sWiFiFP = fWiFiFP.fileName().toStdString();
const std::string sWiFiModel = fWiFiModel.fileName().toStdString(); const std::string sWiFiModel = fWiFiModel.fileName().toStdString();
const std::string sBLEFP = fBLEFP.fileName().toStdString();
wifiModel = buildWiFiModelOnce(im, sWiFiFP, sWiFiModel); wifiModel = buildWiFiModelOnce(im, sWiFiFP, sWiFiModel);
@@ -346,9 +365,10 @@ void Controller::loadNavMesh(QDir dir) {
nav = new MeshBased::NavControllerMesh(this, im, navMesh, wifiModel); nav = new MeshBased::NavControllerMesh(this, im, navMesh, wifiModel);
WiFiCalibrationDataModel* wifiCalib = new WiFiCalibrationDataModel(sWiFiFP); WiFiCalibrationDataModel* wifiCalib = new WiFiCalibrationDataModel(sWiFiFP);
BLECalibrationDataModel* bleCalib = new BLECalibrationDataModel(sBLEFP);
getMapView3D()->setMap(im); getMapView3D()->setMap(im);
getMapView2D()->setMap(wifiCalib, im); getMapView2D()->setMap(wifiCalib, bleCalib, im);
//getMapView3D()->showGridImportance(grid); //getMapView3D()->showGridImportance(grid);
//getMapView2D()->showGridImportance(grid); //getMapView2D()->showGridImportance(grid);

View File

@@ -122,7 +122,7 @@ public class WiFi {
/** try to trigger one scan process */ /** try to trigger one scan process */
private static void triggerOneScan() { private static void triggerOneScan() {
Log.d("wifi", "triggerOneScan()"); //Log.d("wifi", "triggerOneScan()");
try { try {
if(!manager.startScan()) {throw new RuntimeException("Cant start WiFi!");} if(!manager.startScan()) {throw new RuntimeException("Cant start WiFi!");}

View File

@@ -66,7 +66,7 @@ public:
const int8_t pad2 = data[19]; const int8_t pad2 = data[19];
if (pad1 != 0 || pad2 != 0) {Debug::error("padding error within BLE scan result");} if (pad1 != 0 || pad2 != 0) {Debug::error("padding error within BLE scan result");}
Log::add("BLE", bssid + "; " + std::to_string(static_cast<int>(rssi))); //Log::add("BLE", bssid + "; " + std::to_string(static_cast<int>(rssi)));
// call listeners // call listeners
informListeners(BeaconMeasurement(curTS, Beacon(bssid), rssi)); informListeners(BeaconMeasurement(curTS, Beacon(bssid), rssi));

View File

@@ -1,4 +1,91 @@
#ifndef BLECALIBRATIONDATAMODEL_H #ifndef BLECALIBRATIONDATAMODEL_H
#define BLECALIBRATIONDATAMODEL_H #define BLECALIBRATIONDATAMODEL_H
#include <fstream>
#include <Indoor/sensors/beacon/setup/BeaconFingerprint.h>
class BLECalibrationDataModel {
private:
/** the file to save the calibration model to */
std::string file;
/** all fingerprints (position -> measurements) within the model */
std::vector<BeaconFingerprint> fingerprints;
public:
BLECalibrationDataModel(const std::string& file) : file(file) {
load();
}
const std::vector<BeaconFingerprint>& getFingerprints() {
return fingerprints;
}
/** deserialize the model */
void load() {
// open and check
std::ifstream inp(file.c_str());
if (inp.bad() || inp.eof() || ! inp.is_open()) { return; }
// read all entries
while (!inp.eof()) {
// each section starts with [fingerprint]
std::string section;
inp >> section;
if (inp.eof()) {break;}
if (section != "[fingerprint]") {throw Exception("error!");}
// deserialize it
BeaconFingerprint bfp;
bfp.read(inp);
if (bfp.measurements.entries.empty()) {continue;}
fingerprints.push_back(bfp);
}
inp.close();
}
/** serialize the model */
void save() {
// open and check
std::ofstream out(file.c_str());
if (out.bad()) {throw Exception("error while opening " + file + " for write");}
// write all entries
for (const BeaconFingerprint& wfp : fingerprints) {
out << "[fingerprint]\n";
wfp.write(out);
}
// done
out.close();
}
/** get the fingerprint for the given location. if no fingerprint exists, an empty one is created! */
BeaconFingerprint& getFingerprint(const Point3 pos_m) {
// try to find an existing one
for (BeaconFingerprint& bfp : fingerprints) {
// get within range of floating-point rounding issues
if (bfp.pos_m.getDistance(pos_m) < 0.01) {return bfp;}
}
// create a new one and return its reference
BeaconFingerprint bfp(pos_m);
fingerprints.push_back(bfp);
return fingerprints.back();
}
};
#endif // BLECALIBRATIONDATAMODEL_H #endif // BLECALIBRATIONDATAMODEL_H

View File

@@ -1,7 +1,7 @@
#include "WiFiCalibrationScanDialog.h" #include "WiFiCalibrationScanDialog.h"
WiFiCalibrationScanDialog::WiFiCalibrationScanDialog(WiFiFingerprint& model) : model(model) { WiFiCalibrationScanDialog::WiFiCalibrationScanDialog(WiFiFingerprint& wifiModel, BeaconFingerprint& bleModel) : wifiModel(wifiModel), bleModel(bleModel) {
dlg->resize(300, 300); dlg->resize(300, 300);

View File

@@ -10,7 +10,7 @@
#include "../sensors/SensorFactory.h" #include "../sensors/SensorFactory.h"
#include "../tools/calibration/WiFiCalibrationDataModel.h" #include "../tools/calibration/WiFiCalibrationDataModel.h"
#include "../tools/calibration/BLECalibrationDataModel.h"
/** /**
@@ -33,20 +33,20 @@ private:
} scan; } scan;
/** the measurements model to fill with scan-entries */ /** the measurements model to fill with scan-entries */
WiFiFingerprint& model; WiFiFingerprint& wifiModel;
//BeaconFingerprint& blemodel; BeaconFingerprint& bleModel;
public: public:
static void get(WiFiFingerprint& model) { static void get(WiFiFingerprint& wifiModel, BeaconFingerprint& bleModel) {
WiFiCalibrationScanDialog dlg(model); WiFiCalibrationScanDialog dlg(wifiModel, bleModel);
dlg.show(); dlg.show();
} }
private: private:
/** ctor */ /** ctor */
WiFiCalibrationScanDialog(WiFiFingerprint& model); WiFiCalibrationScanDialog(WiFiFingerprint& wifiModel, BeaconFingerprint& bleModel);
void show() { void show() {
refresh(); refresh();
@@ -63,28 +63,39 @@ private:
} }
Q_INVOKABLE void refresh() { Q_INVOKABLE void refresh() {
lblPoint->setText(QString(model.pos_m.asString().c_str())); lblPoint->setText(QString(wifiModel.pos_m.asString().c_str()));
lblStats->setText( QString::number(model.measurements.entries.size()) + " RSSI measurements\n" + QString::number(scan.recordsDone) + " scans"); lblStats->setText( QString::number(wifiModel.measurements.entries.size()) + " RSSI measurements\n" + QString::number(scan.recordsDone) + " scans");
barProg->setValue(scan.recordsDone); barProg->setValue(scan.recordsDone);
barProg->setMaximum(scan.numRecords); barProg->setMaximum(scan.numRecords);
} }
void clear() { void clear() {
model.measurements.entries.clear(); wifiModel.measurements.entries.clear();
bleModel.measurements.entries.clear();
refresh(); refresh();
} }
void startRecord() { void startRecord() {
scan.recordsDone = 0; scan.recordsDone = 0;
//add wifi
SensorFactory::get().getWiFi().addListener(this); SensorFactory::get().getWiFi().addListener(this);
if (!SensorFactory::get().getWiFi().isRunning()) { if (!SensorFactory::get().getWiFi().isRunning()) {
SensorFactory::get().getWiFi().start(); SensorFactory::get().getWiFi().start();
} }
//add ble
SensorFactory::get().getBLE().addListener(this);
if (!SensorFactory::get().getBLE().isRunning()) {
SensorFactory::get().getBLE().start();
}
} }
void stopRecord() { void stopRecord() {
SensorFactory::get().getWiFi().removeListener(this); SensorFactory::get().getWiFi().removeListener(this);
SensorFactory::get().getBLE().removeListener(this);
} }
virtual void onSensorData(Sensor<WiFiMeasurements>* sensor, const Timestamp ts, const WiFiMeasurements& data) override { virtual void onSensorData(Sensor<WiFiMeasurements>* sensor, const Timestamp ts, const WiFiMeasurements& data) override {
@@ -92,7 +103,7 @@ private:
(void) ts; (void) ts;
++scan.recordsDone; ++scan.recordsDone;
if (scan.recordsDone >= scan.numRecords) {stopRecord();} if (scan.recordsDone >= scan.numRecords) {stopRecord();}
model.measurements.entries.insert(model.measurements.entries.end(), data.entries.begin(), data.entries.end()); wifiModel.measurements.entries.insert(wifiModel.measurements.entries.end(), data.entries.begin(), data.entries.end());
QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection);
} }
@@ -100,8 +111,7 @@ private:
virtual void onSensorData(Sensor<BeaconMeasurement>* sensor, const Timestamp ts, const BeaconMeasurement& data) override { virtual void onSensorData(Sensor<BeaconMeasurement>* sensor, const Timestamp ts, const BeaconMeasurement& data) override {
(void) sensor; (void) sensor;
(void) ts; (void) ts;
bleModel.measurements.entries.push_back(data);
QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection);
} }

View File

@@ -93,14 +93,14 @@ void MapView2D::onLayerPlus() {
setRenderHeight(layerHeight_m); setRenderHeight(layerHeight_m);
} }
void MapView2D::setMap(WiFiCalibrationDataModel* mdl, Floorplan::IndoorMap* map) { void MapView2D::setMap(WiFiCalibrationDataModel* wifiMdl, BLECalibrationDataModel* bleMdl, Floorplan::IndoorMap* map) {
for (Floorplan::Floor* floor : map->floors) { for (Floorplan::Floor* floor : map->floors) {
Floor2D* f = new Floor2D(floor); Floor2D* f = new Floor2D(floor);
elementsA.push_back(f); elementsA.push_back(f);
} }
wifiCalib = new WiFiCalibTool(mdl, map); wifiCalib = new WiFiCalibTool(wifiMdl, bleMdl, map);
elementsB.push_back(wifiCalib); elementsB.push_back(wifiCalib);
const BBox3 bbox3 = FloorplanHelper::getBBox(map); const BBox3 bbox3 = FloorplanHelper::getBBox(map);

View File

@@ -15,6 +15,8 @@
#include "nav/grid/State.h" #include "nav/grid/State.h"
#include "nav/mesh/State.h" #include "nav/mesh/State.h"
#include "../tools/calibration/BLECalibrationDataModel.h"
namespace Floorplan { namespace Floorplan {
class IndoorMap; class IndoorMap;
} }
@@ -71,7 +73,7 @@ public:
explicit MapView2D(QWidget *parent = 0); explicit MapView2D(QWidget *parent = 0);
/** set the to-be-shown map */ /** set the to-be-shown map */
void setMap(WiFiCalibrationDataModel* mdl, Floorplan::IndoorMap* map); void setMap(WiFiCalibrationDataModel* wifiMdl, BLECalibrationDataModel* bleMdl, Floorplan::IndoorMap* map);
/** show importance factors for the grid */ /** show importance factors for the grid */
void showGridImportance(Grid<MyGridNode>* grid); void showGridImportance(Grid<MyGridNode>* grid);

View File

@@ -29,12 +29,15 @@ struct WiFiCalibPoint {
/** /**
* helper for wifi calibration * helper for wifi calibration
* TODO: Make this generic for BLE and WiFI
*/ */
class WiFiCalibTool : public Renderable2D { class WiFiCalibTool : public Renderable2D {
private: private:
WiFiCalibrationDataModel* mdl; WiFiCalibrationDataModel* wifiMdl;
BLECalibrationDataModel* bleMdl;
Floorplan::IndoorMap* map; Floorplan::IndoorMap* map;
std::vector<WiFiCalibPoint> currentlyVisible; std::vector<WiFiCalibPoint> currentlyVisible;
@@ -44,7 +47,7 @@ private:
public: public:
/** ctor */ /** ctor */
WiFiCalibTool(WiFiCalibrationDataModel* mdl, Floorplan::IndoorMap* map) : mdl(mdl), map(map) { WiFiCalibTool(WiFiCalibrationDataModel* wifiMdl, BLECalibrationDataModel* bleMdl, Floorplan::IndoorMap* map) : wifiMdl(wifiMdl), bleMdl(bleMdl), map(map) {
} }
@@ -82,9 +85,11 @@ protected:
const WiFiCalibPoint cp(fpLoc->name, p, pt); const WiFiCalibPoint cp(fpLoc->name, p, pt);
currentlyVisible.push_back(cp); currentlyVisible.push_back(cp);
const WiFiFingerprint& fp = mdl->getFingerprint(cp.pos_m); const WiFiFingerprint& wfp = wifiMdl->getFingerprint(cp.pos_m);
const BeaconFingerprint& bfp = bleMdl->getFingerprint(cp.pos_m);
const QString txt1(fpLoc->name.c_str()); const QString txt1(fpLoc->name.c_str());
const QString txt2 = QString::number(fp.measurements.entries.size()); const QString txt2 = QString::number(wfp.measurements.entries.size());
qp.setPen(Qt::black); qp.setPen(Qt::black);
if (currentlySelected.name == cp.name) { if (currentlySelected.name == cp.name) {
@@ -116,14 +121,17 @@ private:
void showCalib(const WiFiCalibPoint& cp) { void showCalib(const WiFiCalibPoint& cp) {
// get (or create an empty one) the fingerprint for this location // get (or create an empty one) the fingerprint for this location
WiFiFingerprint& fp = mdl->getFingerprint(cp.pos_m); WiFiFingerprint& wfp = wifiMdl->getFingerprint(cp.pos_m);
BeaconFingerprint& bfp = bleMdl->getFingerprint(cp.pos_m);
// edit it (blocking!) // edit it (blocking!)
WiFiCalibrationScanDialog::get(fp); WiFiCalibrationScanDialog::get(wfp, bfp);
// save the model // save the model
mdl->save(); wifiMdl->save();
//save bluetooth model here!
bleMdl->save();
} }
}; };