diff --git a/CelluloUnity_Cellulo.cpp b/CelluloUnity_Cellulo.cpp index 001718c..d1e6778 100644 --- a/CelluloUnity_Cellulo.cpp +++ b/CelluloUnity_Cellulo.cpp @@ -1,39 +1,39 @@ #ifdef __ANDROID__ #include "CelluloUnity_Cellulo.h" #include #include jint load(JavaVM *vm, void *reserved, const char* so_file) { jint (*that_jni_onload)(JavaVM *vm, void *reserved); char *error; void* handle = dlopen(so_file, RTLD_LAZY); if (!handle) { qDebug() << dlerror(); exit(EXIT_FAILURE); } *(void **) (&that_jni_onload) = dlsym(handle, "JNI_OnLoad"); if ((error = dlerror()) != NULL) { qDebug() << error; exit(EXIT_FAILURE); } return (*that_jni_onload)(vm, reserved); } jint JNI_OnLoad(JavaVM *vm, void *reserved) { qDebug() << "Begin JNI_Onload()"; jint res = load(vm, reserved, "libQt5Core.so"); load(vm, reserved, "libQt5AndroidExtras.so"); load(vm, reserved, "libQt5Bluetooth.so"); - //load(vm, reserved, "libqtforandroid.so"); enables bluetooth. Does not work. See https://c4science.ch/T2160 + load(vm, reserved, "libqtforandroid.so"); // FIXME: enables bluetooth. Does not work. See https://c4science.ch/T2160 qDebug() << "End JNI_Onload()"; return res; } #endif diff --git a/cellulo-qml-plugin b/cellulo-qml-plugin index b09baf9..dfe4fe7 120000 --- a/cellulo-qml-plugin +++ b/cellulo-qml-plugin @@ -1 +1 @@ -../cellulo-qml-plugin/ \ No newline at end of file +../cellulo-qml-plugin \ No newline at end of file diff --git a/cellulo-unity.pri b/cellulo-unity.pri index fedd22c..ac3053d 100644 --- a/cellulo-unity.pri +++ b/cellulo-unity.pri @@ -1,50 +1,52 @@ QT += quick bluetooth CONFIG += qt c++11 nostrip linux:!android { CONFIG += link_pkgconfig packagesExist(bluez){ PKGCONFIG += bluez DEFINES += BT_MULTIADAPTER_SUPPORT message("BlueZ found, enabling Bluetooth multiadapter support.") } else{ message("BlueZ not found, disabling Bluetooth multiadapter support.") } } android{ QT += androidextras } DEFINES += CELLULOUNITY_LIBRARY # The following define makes your compiler emit warnings if you use # any feature of Qt which has been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ + $$PWD/cellulopoolclient.cpp \ $$PWD/cellulounity.cpp \ $$PWD/cellulothread.cpp \ $$PWD/cellulorobotwrapper.cpp \ $$PWD/CelluloUnity_Cellulo.cpp HEADERS += \ + $$PWD/cellulopoolclient.h \ $$PWD/cellulounity.h \ $$PWD/cellulo-unity_global.h \ $$PWD/cellulothread.h \ $$PWD/cellulorobotwrapper.h \ $$PWD/CelluloUnity_Cellulo.h LIBS += -lcelluloplugin -L$$[QT_INSTALL_QML]/Cellulo -L./ INCLUDEPATH += $$PWD/cellulo-qml-plugin/src $$PWD/cellulo-qml-plugin/include diff --git a/cellulo-unity.pro.user.4.8-pre1 b/cellulo-unity.pro.user.4.8-pre1 new file mode 100644 index 0000000..fdf61d1 --- /dev/null +++ b/cellulo-unity.pro.user.4.8-pre1 @@ -0,0 +1,649 @@ + + + + + + EnvironmentId + {bde6ebf8-4fa3-41e9-b52b-779c68ef39b0} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + ProjectExplorer.Project.Target.0 + + Desktop Qt 5.10.0 clang 64bit + Desktop Qt 5.10.0 clang 64bit + qt.qt5.5100.clang_64_kit + 0 + 0 + 0 + + /Users/ulysse/Desktop/cellulo/cellulo-unity-build-desktop + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + /Users/ulysse/Desktop/cellulo/build-cellulo-unity-Desktop_Qt_5_10_0_clang_64bit-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + + /Users/ulysse/Desktop/cellulo/build-cellulo-unity-Desktop_Qt_5_10_0_clang_64bit-Profile + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + true + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + 2 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Profile + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 3 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy locally + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + + + %{buildDir} + Custom Executable + + ProjectExplorer.CustomExecutableRunConfiguration + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.Target.1 + + Android for armeabi-v7a (GCC 4.9, Qt 5.10.0 for Android armv7) + Android for armeabi-v7a (GCC 4.9, Qt 5.10.0 for Android armv7) + {5f20c1aa-1f43-4399-85f3-460d51e81321} + 0 + 0 + 0 + + /Users/ulysse/Desktop/cellulo/cellulo-unity-build-android + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + + true + Copy application data + + Qt4ProjectManager.AndroidPackageInstallationStep + + + + + true + Build Android APK + + QmakeProjectManager.AndroidBuildApkStep + 1 + false + + 4 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + /Users/ulysse/Desktop/cellulo/build-cellulo-unity-Android_for_armeabi_v7a_GCC_4_9_Qt_5_10_0_for_Android_armv7-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + + true + Copy application data + + Qt4ProjectManager.AndroidPackageInstallationStep + + + + + true + Build Android APK + + QmakeProjectManager.AndroidBuildApkStep + 1 + false + + 4 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + + /Users/ulysse/Desktop/cellulo/build-cellulo-unity-Android_for_armeabi_v7a_GCC_4_9_Qt_5_10_0_for_Android_armv7-Profile + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + true + false + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + false + + + + + true + Copy application data + + Qt4ProjectManager.AndroidPackageInstallationStep + + + + + true + Build Android APK + + QmakeProjectManager.AndroidBuildApkStep + 1 + false + + 4 + Build + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + -w + -r + + true + clean + + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Profile + + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 3 + + + + true + Deploy to Android device + + Qt4ProjectManager.AndroidDeployQtStep + false + + 1 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy to Android device + Deploy to Android device + Qt4ProjectManager.AndroidDeployConfiguration2 + + 1 + + + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + + + + cellulo-unity + + Qt4ProjectManager.AndroidRunConfiguration:/Users/ulysse/Desktop/cellulo/cellulo-unity/cellulo-unity.pro + cellulo-unity.pro + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 2 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/cellulopoolclient.cpp b/cellulopoolclient.cpp new file mode 100644 index 0000000..a1ee1ac --- /dev/null +++ b/cellulopoolclient.cpp @@ -0,0 +1,25 @@ +#include "cellulopoolclient.h" + +void CelluloPoolClientWrapper::init_() +{ + client = new CelluloRobotPoolClient; + connect(client, &CelluloRobotPoolClient::newRobotFound, this, &CelluloPoolClientWrapper::onNewRobot); + qDebug() << "POOL Object created"; +} + +void CelluloPoolClientWrapper::deinit_() +{ + client->deleteLater(); + client = nullptr; +} + +CelluloPoolClientWrapper::CelluloPoolClientWrapper() +{ + robots_N = 0; +} + +void CelluloPoolClientWrapper::onNewRobot(CelluloBluetooth* robot) { + qDebug() << "ATTENTION ROBOT FOUND " << robot->getMacAddr(); + robots.push_back(robot); + robots_N++; +} \ No newline at end of file diff --git a/cellulopoolclient.h b/cellulopoolclient.h new file mode 100644 index 0000000..e110de5 --- /dev/null +++ b/cellulopoolclient.h @@ -0,0 +1,45 @@ +#ifndef CELLULOPOOLCLIENT_H +#define CELLULOPOOLCLIENT_H + +#include +#include +#include "cellulo-qml-plugin/src/comm/relay/CelluloRobotPoolClient.h" +#include +#include + +using Cellulo::CelluloRobotPoolClient; +using Cellulo::CelluloBluetooth; + + +class CelluloPoolClientWrapper : public QObject +{ Q_OBJECT + + Q_INVOKABLE void init_(); + Q_INVOKABLE void deinit_(); + + CelluloRobotPoolClient *client; + + QVector robots; +public: + CelluloPoolClientWrapper(); + QVector getRobots() { + return robots; + } + + int robots_N; + +public slots: + void init() + { + QMetaObject::invokeMethod(this, "init_", Qt::BlockingQueuedConnection); + } + + void deinit() + { + QMetaObject::invokeMethod(this, "deinit_", Qt::BlockingQueuedConnection); + } + + void onNewRobot(CelluloBluetooth* robot); +}; + +#endif // CELLULOPOOLCLIENT_H \ No newline at end of file diff --git a/cellulothread.cpp b/cellulothread.cpp index 70788f6..22d8f14 100644 --- a/cellulothread.cpp +++ b/cellulothread.cpp @@ -1,21 +1,23 @@ #include "cellulothread.h" #include CelluloThread::CelluloThread() { } void CelluloThread::run() { qDebug() << "CelluloThread::run..."; + + int argc; + char* argv[2]; argc = 1; argv[0] = strdup("CelluloThread"); argv[1] = nullptr; - qDebug() << "CelluloThread creating QCoreApp"; - QCoreApplication app(argc, argv); - application = &app; + qDebug() << "CelluloThread creating QCoreApp..."; + application = new QCoreApplication(argc, argv); qDebug() << "Starting the event loop..."; - app.exec(); + application->exec(); } diff --git a/cellulothread.h b/cellulothread.h index 2b79a9b..5e0cf55 100644 --- a/cellulothread.h +++ b/cellulothread.h @@ -1,20 +1,18 @@ #ifndef CELLULOTHREAD_H #define CELLULOTHREAD_H #include #include #include class CelluloThread : public QThread { Q_OBJECT private: QPointer application; - int argc; - char* argv[2]; public: CelluloThread(); void run() override; }; #endif // CELLULOTHREAD_H diff --git a/cellulounity.cpp b/cellulounity.cpp index ec9a625..1e3097b 100644 --- a/cellulounity.cpp +++ b/cellulounity.cpp @@ -1,204 +1,269 @@ #include "cellulounity.h" #include "cellulothread.h" #include "cellulorobotwrapper.h" +#include "cellulopoolclient.h" #include using Cellulo::CelluloBluetoothScanner; using Cellulo::CelluloBluetooth; CelluloThread* thread = nullptr; CelluloBluetoothScanner* scanner = nullptr; +CelluloPoolClientWrapper* client = nullptr; + +// Number of robots used from the pool +int used_robots; /* * Library initialization */ void initialize() { if (thread == nullptr) { qDebug() << "Creating thread..."; thread = new CelluloThread; qDebug() << "Starting thread..."; thread->start(); } // initializing the library again... - if (scanner != nullptr) { - qDebug() << "Deleting scanner..."; + if (scanner != nullptr && client != nullptr) { + qDebug() << "Client deinit..."; + client->deinit(); + qDebug() << "Deleting scanner and client..."; scanner->deleteLater(); - qDebug() << "Setting ptr to nullptr"; + client->deleteLater(); + qDebug() << "Setting ptrs to nullptr"; scanner = nullptr; + client = nullptr; } if (scanner == nullptr) { qDebug() << "Creating scanner..."; scanner = new CelluloBluetoothScanner; - qDebug() << "Moving scanner to thread..."; scanner->moveToThread(thread); } + + if (client == nullptr) { + qDebug() << "Creating pool..."; + client = new CelluloPoolClientWrapper; + qDebug() << "Moving pool to thread..."; + client->moveToThread(thread); + qDebug() << "Initializing pool..."; + client->init(); + used_robots = 0; + } } /* * Scanner bindings */ void startScanning() { if (scanner == nullptr) { qDebug() << "Cannot start scanning because initialize() was not called"; return; } qDebug() << "Starting scanner..."; scanner->start(); } void stopScanning() { if (scanner == nullptr) { qDebug() << "Cannot stop scanning because initialize() was not called"; return; } qDebug() << "Stopping scanner..."; scanner->stop(); } void clearScanResults() { if(scanner == nullptr) { qDebug() << "Cannot clear scan results because initialize() was not called"; return; } qDebug() << "Clearing scanner results..."; scanner->clear(); } int getScanResultsLength() { if (scanner == nullptr) { qDebug() << "Cannot get scan results length because initialize() was not called"; return -1; } return scanner->getFoundRobots().length(); } const char * getScanResultAtIndex(int index) { if (scanner == nullptr) { qDebug() << "Cannot get scan result at index" << index << "because initialize() was not called"; return nullptr; } QByteArray utf8 = scanner->getFoundRobots().at(index).toUtf8(); return utf8.constData(); } /* * Robot creation */ +int64_t newRobotFromPool() { + if (client == nullptr) { + qDebug() << "Cannot create a new robot because initialize() was not called"; + return 0; + } + + if (used_robots >= client->robots_N) { + qDebug() << "Cannot create a new robot because the pool is exhausted. Connect to more and restart the app."; + return 0; + } + + Cellulo::CelluloBluetooth* robot1 = client->getRobots().at(used_robots++); + + qDebug() << "Wrapping robot" << robot1; + CelluloRobotWrapper* robot = new CelluloRobotWrapper(robot1); + + qDebug() << "Moving robot to thread..."; + robot->moveToThread(thread); + + qDebug() << "Initializing robot..."; + robot->init(); + + qDebug() << "Got wrapped robot" << robot; + + return (int64_t) robot; +} + int64_t newRobotFromMAC(const char * address) { if (scanner == nullptr) { qDebug() << "Cannot create a new robot because initialize() was not called"; return 0; } qDebug() << "Creating bluetooth object..."; CelluloBluetooth* bluetooth = new CelluloBluetooth(); qDebug() << "Moving bluetooth object to thread..."; bluetooth->moveToThread(thread); qDebug() << "Moving bluetooth timers to thread..."; bluetooth->moveTimersToThread(thread); qDebug() << "Setting robot MAC address" << address; bluetooth->setMacAddr(QString::fromUtf8(address)); qDebug() << "Setting automatic connect"; bluetooth->setAutoConnect(1); qDebug() << "Creating robot object..."; CelluloRobotWrapper* robot = new CelluloRobotWrapper(bluetooth); qDebug() << "Moving robot to thread..."; robot->moveToThread(thread); qDebug() << "Initializing robot..."; robot->init(); qDebug() << "Got wrapped robot" << robot; - // TODO: use something less ugly than that + return (int64_t) robot; } /* * Robot bindings */ void setGoalVelocity(int64_t robot, float vx, float vy, float w) { ((CelluloRobotWrapper*) robot)->setGoalVelocity(vx, vy, w); } void setGoalPose(int64_t robot, float x, float y, float theta, float v, float w) { ((CelluloRobotWrapper*) robot)->setGoalPose(x, y, theta, v, w); } void setGoalPosition(int64_t robot, float x, float y, float v) { ((CelluloRobotWrapper*) robot)->setGoalPosition(x, y, v); } void clearTracking(int64_t robot) { ((CelluloRobotWrapper*) robot)->clearTracking(); } void clearHapticFeedback(int64_t robot) { ((CelluloRobotWrapper*) robot)->clearHapticFeedback(); } void setVisualEffect(int64_t robot, int64_t effect, int64_t r, int64_t g, int64_t b, int64_t value) { ((CelluloRobotWrapper*) robot)->setVisualEffect(effect, QColor(r, g, b), value); } void setCasualBackdriveAssistEnabled(int64_t robot, int64_t enabled) { ((CelluloRobotWrapper*) robot)->setCasualBackdriveAssistEnabled(enabled); } void setHapticBackdriveAssist(int64_t robot, float xAssist, float yAssist, float thetaAssist) { ((CelluloRobotWrapper*) robot)->setHapticBackdriveAssist(xAssist, yAssist, thetaAssist); } void reset(int64_t robot) { ((CelluloRobotWrapper*) robot)->reset(); } void simpleVibrate(int64_t robot, float iX, float iY, float iTheta, int64_t period, int64_t duration) { ((CelluloRobotWrapper*) robot)->simpleVibrate(iX, iY, iTheta, period, duration); } float getX(int64_t robot) { return ((CelluloRobotWrapper*) robot)->robot->getX(); } float getY(int64_t robot) { return ((CelluloRobotWrapper*) robot)->robot->getY(); } float getTheta(int64_t robot) { return ((CelluloRobotWrapper*) robot)->robot->getTheta(); } int64_t getKidnapped(int64_t robot) { Cellulo::CelluloBluetooth* robot1 = (Cellulo::CelluloBluetooth*) ((CelluloRobotWrapper*) robot)->robot; return robot1->getKidnapped(); } void destroyRobot(int64_t robot) { qDebug() << "Removing callback..."; ((CelluloRobotWrapper*) robot)->kidnappedCallback = nullptr; qDebug() << "Calling deinit..."; ((CelluloRobotWrapper*) robot)->deinit(); } const char * getMacAddr(int64_t robot) { return ((CelluloRobotWrapper*) robot)->robot->getMacAddr().toUtf8().constData(); } int getConnectionStatus(int64_t robot) { return ((CelluloRobotWrapper*) robot)->robot->getConnectionStatus(); } + +/* + * Check number of robots + */ + +int64_t robotsRemaining() { + if (client == nullptr) { + qDebug() << "Cannot call robotsRemaining() because initialize() was not called"; + return 0; + } + return client->robots_N - used_robots; +} + +int64_t totalRobots() { + if (client == nullptr) { + qDebug() << "Cannot call totalRobots() because initialize() was not called"; + return 0; + } + return client->robots_N; +} \ No newline at end of file diff --git a/cellulounity.h b/cellulounity.h index 7d728a5..ae833d1 100644 --- a/cellulounity.h +++ b/cellulounity.h @@ -1,48 +1,53 @@ #ifndef CELLULOUNITY_H #define CELLULOUNITY_H #include "cellulo-qml-plugin/src/comm/CelluloBluetoothScanner.h" #include typedef void (*callback_t)(); extern "C" { // Library initialization void initialize(); // Scanner bindings void startScanning(); void stopScanning(); void clearScanResults(); int getScanResultsLength(); const char * getScanResultAtIndex(int index); // Robot creation + int64_t newRobotFromPool(); int64_t newRobotFromMAC(const char * address); // Robot bindings void setGoalVelocity(int64_t robot, float vx, float vy, float w); void setGoalPose(int64_t robot, float x, float y, float theta, float v, float w); void setGoalPosition(int64_t robot, float x, float y, float v); void clearTracking(int64_t robot); void clearHapticFeedback(int64_t robot); void setVisualEffect(int64_t robot, int64_t effect, int64_t r, int64_t g, int64_t b, int64_t value); void setCasualBackdriveAssistEnabled(int64_t robot, int64_t enabled); void setHapticBackdriveAssist(int64_t robot, float xAssist, float yAssist, float thetaAssist); void reset(int64_t robot); void simpleVibrate(int64_t robot, float iX, float iY, float iTheta, int64_t period, int64_t duration); float getX(int64_t robot); float getY(int64_t robot); float getTheta(int64_t robot); int64_t getKidnapped(int64_t robot); void destroyRobot(int64_t robot); + // Check number of robots + int64_t robotsRemaining(); + int64_t totalRobots(); + // Debug const char * getMacAddr(int64_t robot); int getConnectionStatus(int64_t robot); } #endif // CELLULOUNITY_H diff --git a/libcelluloplugin.dylib b/libcelluloplugin.dylib deleted file mode 100755 index 20471e9..0000000 Binary files a/libcelluloplugin.dylib and /dev/null differ