diff --git a/_android/AndroidManifest.xml b/_android/AndroidManifest.xml
new file mode 100644
index 0000000..5978c42
--- /dev/null
+++ b/_android/AndroidManifest.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_android/src/MyActivity.java b/_android/src/MyActivity.java
new file mode 100644
index 0000000..871850e
--- /dev/null
+++ b/_android/src/MyActivity.java
@@ -0,0 +1,23 @@
+package our.java.stuff;
+
+import android.os.Bundle;
+import org.qtproject.qt5.android.bindings.QtActivity;
+
+public class MyActivity extends QtActivity {
+
+ public static MyActivity act;
+
+ @Override
+ public void onCreate(Bundle savedState) {
+ MyActivity.act = this;
+ super.onCreate(savedState);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ MyActivity.act = null;
+ }
+
+
+}
diff --git a/_android/src/WiFi.java b/_android/src/WiFi.java
new file mode 100644
index 0000000..e883432
--- /dev/null
+++ b/_android/src/WiFi.java
@@ -0,0 +1,101 @@
+package java.indoor;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiManager;
+import android.os.Debug;
+import android.util.Log;
+import java.util.List;
+import java.io.ByteArrayOutputStream;
+
+public class WiFi {
+
+ private static Activity act;
+ private static WifiManager manager;
+ private static BroadcastReceiver receiver;
+
+
+
+ /** called when a scan is completed successfully */
+ public static native void onScanComplete(final byte[] result);
+
+ /**
+ * start WiFi scanning in the background.
+ * will call onScanComplete() once a scan is available
+ */
+ public static int start() {
+
+ Log.d("wifi", "start()");
+
+ MyActivity act = MyActivity.act;
+ manager = (WifiManager) act.getSystemService(Context.WIFI_SERVICE);
+
+ reset();
+
+ WiFi.receiver = new BroadcastReceiver() {
+ public final void onReceive(final Context context, final Intent intent) {
+ final byte[] result = serialize(manager.getScanResults());
+ WiFi.onScanComplete(result);
+ triggerOneScan();
+ }
+ };
+
+ // register scan callback
+ act.registerReceiver(WiFi.receiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
+
+ // start the first scan
+ triggerOneScan();
+
+ return 0;
+
+ }
+
+ /** convert the given scan-result to a binary byte[] representation */
+ private static byte[] serialize(final List lst) {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ for (final ScanResult res : lst) {
+ baos.write(res.BSSID.getBytes());
+ baos.write((byte)res.level);
+ baos.write((byte)0);
+ baos.write((byte)0);
+ }
+ } catch (final Exception e) {;}
+ return baos.toByteArray();
+ }
+
+
+
+ /** reset the WiFi subsystem (better scanning) */
+ private static void reset() {
+ WiFi.manager.disconnect();
+ WiFi.manager.createWifiLock(manager.WIFI_MODE_SCAN_ONLY, "Indoor");
+ //WiFi.manager.setWifiEnabled(false);
+ //WiFi.manager.setWifiEnabled(true);
+ WiFi.manager.disconnect();
+ WiFi.manager.disconnect();
+ WiFi.manager.disconnect();
+ WiFi.manager.disconnect();
+ WiFi.manager.disconnect();
+ WiFi.manager.disconnect();
+ }
+
+ /** try to trigger one scan process */
+ private static void triggerOneScan() {
+
+ Log.d("wifi", "triggerOneScan()");
+
+ try {
+ if(!manager.startScan()) {throw new RuntimeException("Cant start WiFi!");}
+ }catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+
+}
diff --git a/deployment.pri b/deployment.pri
new file mode 100644
index 0000000..265ce71
--- /dev/null
+++ b/deployment.pri
@@ -0,0 +1,13 @@
+unix:!android {
+ isEmpty(target.path) {
+ qnx {
+ target.path = /tmp/$${TARGET}/bin
+ } else {
+ target.path = /opt/$${TARGET}/bin
+ }
+ export(target.path)
+ }
+ INSTALLS += target
+}
+
+export(INSTALLS)
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..9ba96e7
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,51 @@
+#include
+#include
+
+
+#include "sensors/SensorFactory.h"
+
+
+#include
+
+class LeListener : public SensorListener, public SensorListener, public SensorListener {
+
+public:
+ void onSensorData(const WiFiSensorData& data) override {
+ const std::string str = "\n" + data.asString();
+ qDebug(str.c_str());
+ }
+ void onSensorData(const AccelerometerData& data) override {
+ const std::string str = data.asString();
+ qDebug(str.c_str());
+ }
+ void onSensorData(const StepData& data) override {
+ qDebug("STEP!");
+ }
+
+};
+
+int main(int argc, char *argv[]) {
+// test();
+ LeListener listener;
+ WiFiSensor& wifi = SensorFactory::getWiFi();
+ wifi.addListener(&listener);
+ wifi.start();
+
+// AccelerometerSensor& acc = SensorFactory::getAccelerometer();
+// acc.addListener(&listener);
+// acc.start();
+
+ StepSensor& steps = SensorFactory::getSteps();
+ steps.addListener(&listener);
+ steps.start();;
+
+ std::this_thread::sleep_for(std::chrono::seconds(10000));
+
+// QGuiApplication app(argc, argv);
+
+// QQmlApplicationEngine engine;
+// engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+
+// return app.exec();
+
+}
diff --git a/misc/Debug.h b/misc/Debug.h
new file mode 100644
index 0000000..4ff5dac
--- /dev/null
+++ b/misc/Debug.h
@@ -0,0 +1,16 @@
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include
+
+class Debug {
+
+public:
+
+ static void error(const std::string& err) {
+ qDebug(err.c_str());
+ throw err;
+ }
+};
+
+#endif // DEBUG_H
diff --git a/misc/fixc11.h b/misc/fixc11.h
new file mode 100644
index 0000000..a8507fb
--- /dev/null
+++ b/misc/fixc11.h
@@ -0,0 +1,13 @@
+#ifndef FIXC11_H
+#define FIXC11_H
+
+#include
+
+//namespace std {
+
+// template T sqrt(const T val) {return ::sqrt(val);}
+
+//}
+
+
+#endif // FIXC11_H
diff --git a/qml.qrc b/qml.qrc
new file mode 100644
index 0000000..7684346
--- /dev/null
+++ b/qml.qrc
@@ -0,0 +1,6 @@
+
+
+ main.qml
+ MainForm.ui.qml
+
+
diff --git a/sensors/AccelerometerSensor.h b/sensors/AccelerometerSensor.h
new file mode 100644
index 0000000..b4ed6c0
--- /dev/null
+++ b/sensors/AccelerometerSensor.h
@@ -0,0 +1,22 @@
+#ifndef ACCELEROMETERSENSOR_H
+#define ACCELEROMETERSENSOR_H
+
+#include "Sensor.h"
+
+struct AccelerometerData {
+ float x;
+ float y;
+ float z;
+ AccelerometerData(const float x, const float y, const float z) : x(x), y(y), z(z) {;}
+ std::string asString() const {
+ std::stringstream ss;
+ ss << "(" << x << "," << y << "," << z << ")";
+ return ss.str();
+ }
+};
+
+class AccelerometerSensor : public Sensor {
+
+};
+
+#endif // ACCELEROMETERSENSOR_H
diff --git a/sensors/Sensor.h b/sensors/Sensor.h
new file mode 100644
index 0000000..8c37d9d
--- /dev/null
+++ b/sensors/Sensor.h
@@ -0,0 +1,50 @@
+#ifndef SENSOR_H
+#define SENSOR_H
+
+#include
+#include
+
+/** listen for sensor events */
+template class SensorListener {
+
+public:
+
+ /** incoming sensor data */
+ virtual void onSensorData(const T& data) = 0;
+
+};
+
+
+/** base-class for all sensors */
+template class Sensor {
+
+private:
+
+ std::vector*> listeners;
+
+public:
+
+ /** start this sensor */
+ virtual void start() = 0;
+
+ /** stop this sensor */
+ virtual void stop() = 0;
+
+ /** add the given listener to the sensor */
+ void addListener(SensorListener* l) {
+ listeners.push_back(l);
+ }
+
+protected:
+
+ /** inform all attached listeners */
+ void informListeners(const T& sensorData) const {
+ for (SensorListener* l : listeners) {
+ l->onSensorData(sensorData);
+ }
+ }
+
+
+};
+
+#endif // SENSOR_H
diff --git a/sensors/SensorFactory.h b/sensors/SensorFactory.h
new file mode 100644
index 0000000..cac9a92
--- /dev/null
+++ b/sensors/SensorFactory.h
@@ -0,0 +1,47 @@
+#ifndef SENSORFACTORY_H
+#define SENSORFACTORY_H
+
+#include "Sensor.h"
+
+#include "WiFiSensor.h"
+#include "dummy/WiFiSensorDummy.h"
+#include "linux/WiFiSensorLinux.h"
+#include "android/WiFiSensorAndroid.h"
+
+#include "AccelerometerSensor.h"
+#include "dummy/AccelerometerSensorDummy.h"
+#include "android/AccelerometerSensorAndroid.h"
+
+#include "StepSensor.h"
+
+class SensorFactory {
+
+public:
+
+ /** get the WiFi sensor */
+ static WiFiSensor& getWiFi() {
+#ifdef ANDROID
+ return WiFiSensorAndroid::get();
+#else
+ return WiFiSensorDummy::get();
+#endif
+ }
+
+ /** get the Accelerometer sensor */
+ static AccelerometerSensor& getAccelerometer() {
+ #ifdef ANDROID
+ return AccelerometerSensor::get();
+#else
+ return AccelerometerSensorDummy::get();
+#endif
+ }
+
+ /** get the Step sensor */
+ static StepSensor& getSteps() {
+ static StepSensor steps(getAccelerometer());
+ return steps;
+ }
+
+};
+
+#endif // SENSORFACTORY_H
diff --git a/sensors/StepSensor.h b/sensors/StepSensor.h
new file mode 100644
index 0000000..ecdc42b
--- /dev/null
+++ b/sensors/StepSensor.h
@@ -0,0 +1,66 @@
+#ifndef STEPSENSOR_H
+#define STEPSENSOR_H
+
+
+#include "../misc/fixc11.h"
+#include "AccelerometerSensor.h"
+#include "Sensor.h"
+
+struct StepData {
+ ;
+};
+
+class StepSensor : public Sensor, public SensorListener {
+
+private:
+
+ AccelerometerSensor& acc;
+
+public:
+
+ /** hidden ctor. use singleton */
+ StepSensor(AccelerometerSensor& acc) : acc(acc) {
+ ;
+ }
+
+ void start() override {
+ acc.addListener(this);
+ acc.start();
+ }
+
+ void stop() override {
+ throw "todo";
+ }
+
+ virtual void onSensorData(const AccelerometerData& data) override {
+ parse(data);
+ }
+
+
+protected:
+
+ const float threshold = 11.0;
+ const int blockTime = 25;
+ int block = 0;
+
+ void parse(const AccelerometerData& data) {
+
+ const float x = data.x;
+ const float y = data.y;
+ const float z = data.z;
+
+ const float mag = std::sqrt( (x*x) + (y*y) + (z*z) );
+
+ if (block > 0) {
+ --block;
+ } else if (mag > threshold) {
+ informListeners(StepData());
+ block = blockTime;
+ }
+
+ }
+
+};
+
+
+#endif // STEPSENSOR_H
diff --git a/sensors/WiFiSensor.h b/sensors/WiFiSensor.h
new file mode 100644
index 0000000..8da04b4
--- /dev/null
+++ b/sensors/WiFiSensor.h
@@ -0,0 +1,43 @@
+#ifndef WIFISENSOR_H
+#define WIFISENSOR_H
+
+#include
+#include
+#include "Sensor.h"
+
+
+struct WiFiSensorDataEntry {
+ std::string bssid;
+ float rssi;
+ WiFiSensorDataEntry(const std::string& bssid, const float rssi) : bssid(bssid), rssi(rssi) {;}
+ std::string asString() const {
+ std::stringstream ss;
+ ss << bssid << '\t' << (int)rssi;
+ return ss.str();
+ }
+};
+
+
+struct WiFiSensorData {
+ std::vector entries;
+ std::string asString() const {
+ std::stringstream ss;
+ for(const WiFiSensorDataEntry& e : entries) {ss << e.asString() << '\n';}
+ return ss.str();
+ }
+};
+
+
+/** interface for all wifi sensors */
+class WiFiSensor : public Sensor {
+
+protected:
+
+ /** hidden ctor. use SensorFactory */
+ WiFiSensor() {
+
+ }
+
+};
+
+#endif // WIFISENSOR_H
diff --git a/sensors/android/AccelerometerSensorAndroid.h b/sensors/android/AccelerometerSensorAndroid.h
new file mode 100644
index 0000000..bcc6639
--- /dev/null
+++ b/sensors/android/AccelerometerSensorAndroid.h
@@ -0,0 +1,55 @@
+#ifndef ACCELEROMETERSENSOR_H
+#define ACCELEROMETERSENSOR_H
+
+
+#ifdef ANDROID
+
+#include
+
+#include "../AccelerometerSensor.h"
+
+#include
+
+
+
+class AccelerometerSensorAndroid : public AccelerometerSensor {
+
+private:
+
+ QAccelerometer acc;
+
+ /** hidden ctor. use singleton */
+ AccelerometerSensorAndroid() {
+ ;
+ }
+
+public:
+
+ /** singleton access */
+ static AccelerometerSensor& get() {
+ static AccelerometerSensor acc;
+ return acc;
+ }
+
+ void start() override {
+
+ auto onSensorData = [&] () {
+ AccelerometerData data(acc.reading()->x(), acc.reading()->y(), acc.reading()->z());
+ informListeners(data);
+ };
+
+ acc.connect(&acc, &QAccelerometer::readingChanged, onSensorData);
+ acc.start();
+
+ }
+
+ void stop() override {
+ throw "todo";
+ }
+
+
+};
+
+#endif ANDROID
+
+#endif // ACCELEROMETERSENSOR_H
diff --git a/sensors/android/WiFiSensorAndroid.h b/sensors/android/WiFiSensorAndroid.h
new file mode 100644
index 0000000..07ea415
--- /dev/null
+++ b/sensors/android/WiFiSensorAndroid.h
@@ -0,0 +1,76 @@
+#ifndef WIFISENSORANDROID_H
+#define WIFISENSORANDROID_H
+
+
+#ifdef ANDROID
+
+#include
+
+#include "Debug.h"
+#include "WiFiSensor.h"
+
+class WiFiSensorAndroid : public WiFiSensor {
+
+private:
+
+ /** hidden ctor. use singleton! */
+ WiFiSensorAndroid() {;}
+
+public:
+
+ /** singleton access */
+ static WiFiSensorAndroid& get() {
+ static WiFiSensorAndroid wifi;
+ return wifi;
+ }
+
+ void start() override {
+
+ // start scanning
+ int res = QAndroidJniObject::callStaticMethod("java/indoor/WiFi", "start", "()I");
+ (void) res;
+
+ }
+
+ /** called from java. handle the given incoming scan result */
+ void handle(const std::string& data) {
+
+ // to-be-constructed sensor data
+ WiFiSensorData sensorData;
+
+ // parse each mac->rssi entry
+ for (int i = 0; i < (int)data.length(); i += 17+1+2) {
+ const std::string bssid = data.substr(i, 17);
+ const int8_t rssi = data[i+17];
+ const int8_t pad1 = data[i+18];
+ const int8_t pad2 = data[i+19];
+ if (pad1 != 0 || pad2 != 0) {Debug::error("padding error within WiFi scan result");}
+ sensorData.entries.push_back(WiFiSensorDataEntry(bssid, rssi));
+ }
+
+ // call listeners
+ informListeners(sensorData);
+
+ }
+
+};
+
+
+extern "C" {
+
+ /** called after each successful WiFi scan */
+ JNIEXPORT void JNICALL Java_java_indoor_WiFi_onScanComplete(JNIEnv* env, jobject jobj, jbyteArray arrayID) {
+ (void) env; (void) jobj;
+ jsize length = env->GetArrayLength(arrayID);
+ jboolean isCopy;
+ jbyte* data = env->GetByteArrayElements(arrayID, &isCopy);
+ std::string str((char*)data, length);
+ env->ReleaseByteArrayElements(arrayID, data, JNI_ABORT);
+ WiFiSensorAndroid::get().handle(str);
+ }
+
+}
+
+#endif
+
+#endif // WIFISENSORANDROID_H
diff --git a/sensors/dummy/AccelerometerSensorDummy.h b/sensors/dummy/AccelerometerSensorDummy.h
new file mode 100644
index 0000000..4af499c
--- /dev/null
+++ b/sensors/dummy/AccelerometerSensorDummy.h
@@ -0,0 +1,27 @@
+#ifndef ACCELEROMETERSENSORDUMMY_H
+#define ACCELEROMETERSENSORDUMMY_H
+
+#include "../AccelerometerSensor.h"
+
+class AccelerometerSensorDummy : public AccelerometerSensor {
+
+
+public:
+
+ /** singleton access */
+ static AccelerometerSensorDummy& get() {
+ static AccelerometerSensorDummy acc;
+ return acc;
+ }
+
+ void start() override {
+ //throw "todo";
+ }
+
+ void stop() override {
+ throw "todo";
+ }
+
+};
+
+#endif // ACCELEROMETERSENSORDUMMY_H
diff --git a/sensors/dummy/WiFiSensorDummy.h b/sensors/dummy/WiFiSensorDummy.h
new file mode 100644
index 0000000..5f94310
--- /dev/null
+++ b/sensors/dummy/WiFiSensorDummy.h
@@ -0,0 +1,92 @@
+#ifndef WIFISENSORDUMMY_H
+#define WIFISENSORDUMMY_H
+
+#include "../WiFiSensor.h"
+#include
+
+#include
+#include
+
+#include
+#include
+
+
+class WiFiSensorDummy : public WiFiSensor {
+
+private:
+
+ bool enabled;
+
+public:
+
+
+ /** singleton access */
+ static WiFiSensorDummy& get() {
+ static WiFiSensorDummy wifi;
+ return wifi;
+ }
+
+
+ void start() override {
+
+ enabled = true;
+ std::thread t(&WiFiSensorDummy::simulate, this);
+ t.detach();
+
+ }
+
+ void stop() override {
+ enabled = false;
+ }
+
+private:
+
+
+ struct DummyAP {
+ std::string mac;
+ Point2 pos;
+ DummyAP(const std::string mac, const Point2 pos) : mac(mac), pos(pos) {;}
+ };
+
+ void simulate() {
+
+ std::vector aps;
+ aps.push_back(DummyAP("00:00:00:00:00:01", Point2(0, 0)));
+ aps.push_back(DummyAP("00:00:00:00:00:02", Point2(20, 0)));
+ aps.push_back(DummyAP("00:00:00:00:00:03", Point2(10, 20)));
+
+ float deg = 0;
+
+ while(enabled) {
+
+ // wait
+ std::this_thread::sleep_for(std::chrono::milliseconds(500));
+
+ // circle-run around center
+ deg += M_PI * 0.4;
+
+ const float cx = 10;
+ const float cy = 10;
+ const float rad = 5;
+
+ const float x = cx + std::sin(deg) * rad;
+ const float y = cy + std::cos(deg) * rad;
+
+ // construct scan data
+ WiFiSensorData scan;
+ for (DummyAP& ap : aps) {
+ const float dist = ap.pos.getDistance(Point2(x, y));
+ const float rssi = LogDistanceModel::distanceToRssi(-40, 1.5, dist);
+ scan.entries.push_back(WiFiSensorDataEntry(ap.mac, rssi));
+ }
+
+ // call
+ informListeners(scan);
+
+ }
+
+ }
+
+};
+
+#endif // WIFISENSORDUMMY_H
diff --git a/sensors/linux/WiFiSensorLinux.h b/sensors/linux/WiFiSensorLinux.h
new file mode 100644
index 0000000..17f4b56
--- /dev/null
+++ b/sensors/linux/WiFiSensorLinux.h
@@ -0,0 +1,33 @@
+#ifndef WIFISENSORLINUX_H
+#define WIFISENSORLINUX_H
+
+#include "../WiFiSensor.h"
+
+class WiFiSensorLinux : public WiFiSensor {
+
+
+private:
+
+ WiFiSensorLinux() {
+
+ }
+
+public:
+
+ /** singleton access */
+ static WiFiSensorLinux& get() {
+ static WiFiSensorLinux wifi;
+ return wifi;
+ }
+
+ void start() override {
+
+ }
+
+ void stop() override {
+
+ }
+
+};
+
+#endif // WIFISENSORLINUX_H
diff --git a/yasmin.pro b/yasmin.pro
new file mode 100644
index 0000000..8d0f007
--- /dev/null
+++ b/yasmin.pro
@@ -0,0 +1,54 @@
+TEMPLATE = app
+
+QT += qml
+
+# android?
+#QT += androidextras sensors
+#DEFINES += ANDROID
+
+CONFIG += c++11
+
+# use files in ./_android for the project as well
+ANDROID_PACKAGE_SOURCE_DIR = $$PWD/_android
+
+INCLUDEPATH += \
+ ../
+
+OTHER_FILES += \
+ _android/src/WiFi.java \
+ _android/AndroidManifest.xml
+
+SOURCES += \
+ main.cpp \
+
+RESOURCES += qml.qrc
+
+# Additional import path used to resolve QML modules in Qt Creator's code model
+QML_IMPORT_PATH =
+
+# Default rules for deployment.
+include(deployment.pri)
+
+target.path = $$[QT_INSTALL_EXAMPLES]/androidextras/notification
+INSTALLS += target
+
+#DISTFILES += \
+# android-sources/AndroidManifest.xml \
+# android-sources/src/WiFi.java
+
+HEADERS += \
+ sensors/linux/WiFiSensorLinux.h \
+ sensors/android/WiFiSensorAndroid.h \
+ sensors/StepSensor.h \
+ sensors/AccelerometerSensor.h \
+ sensors/android/AccelerometerSensorAndroid.h \
+ sensors/dummy/AccelerometerSensorDummy.h \
+ sensors/Sensor.h \
+ sensors/SensorFactory.h \
+ sensors/WiFiSensor.h \
+ misc/Debug.h \
+ misc/fixc11.h \
+ sensors/dummy/WiFiSensorDummy.h
+
+DISTFILES += \
+ android-sources/src/MyActivity.java