diff --git a/Main.qml b/Main.qml index 7a705dd..e7844b9 100644 --- a/Main.qml +++ b/Main.qml @@ -19,11 +19,47 @@ Window { property int font_normal_text_size: 16 property double distance: 0 property int distance_count: 0 + property int distance_count_thres: 3 property string mode: "http" // visibility: Window.FullScreen Component.onCompleted: { - if(Qt.platform.os !== "android") { + loading_popup.open(); + } + + + Popup { + id: loading_popup + background: Rectangle { + color: "#B0121212" + radius: 5 + border.color: root.accent_color + border.width: 1 } + height: parent.height / 10 + width: parent.width / 1.1 + anchors.centerIn: Overlay.overlay + closePolicy: Popup.NoAutoClose + BusyIndicator { + id: loading_indicator + running: true + anchors { + left: parent.left + verticalCenter: parent.verticalCenter + } + } + Text { + id: loading_text + text: "Loading..." + anchors { + leftMargin: 20 + left: loading_indicator.right + verticalCenter: parent.verticalCenter + } + verticalAlignment: Text.AlignVCenter + color: root.accent_color + font.pointSize: root.font_enlarged_text_size + } + } Rectangle { @@ -687,7 +723,10 @@ Window { root.distance = listener.distance; error_text.error_string = ""; console.log("Distance count: ", root.distance_count); - if(root.distance_count >= 5) { + if(root.distance_count >= root.distance_count_thres) { + if(loading_popup.opened) { + loading_popup.close(); + } status_label.text = "Recieving values"; let current_min_reading = Math.max(0, (parseFloat(min_thres_input.text))); let effective_max_reading = Math.max(0, (parseFloat(max_thres_input.text)) - current_min_reading); @@ -704,7 +743,7 @@ Window { water_level.color = root.water_color; } if(root.distance_count > 1000) { - root.distance_count = 5; + root.distance_count = root.distance_count_thres; } console.log("Current reading is: " + current_reading) console.log("Normalized height is: " + normalized_height) diff --git a/README.md b/README.md index 96a9151..7198d51 100644 --- a/README.md +++ b/README.md @@ -5,4 +5,13 @@ Builds for android and desktop.
On Android Creates a service from service.cpp and android/src/org/qtproject/example/appwaterLevelSensor/WaterLevelService.java.
Changes in AndroidManifest.xml are important.
On Desktop just waits for values from a UDP Broadcast on local network with port 8176 and shows those values.
-On Android the service does that, and creates an alert notification if the value in broadcast is less than alert threshold.
\ No newline at end of file +On Android the service does that, and creates an alert notification if the value in broadcast is less than alert threshold.
+ + +
+Create a new socket in Worker that will instantly start listening.
+In the service launch the threads and immediately send client hello to the worker socket.
+On client hello send command data to the android service.
+On quit send server bye to android service.
+On server bye deinit the sockets that send data to cpp server.
+On next launch, the command and client threads can be reinitialized from the StartService java class.
\ No newline at end of file diff --git a/android/src/org/qtproject/example/appwaterLevelSensor/WaterLevelService.java b/android/src/org/qtproject/example/appwaterLevelSensor/WaterLevelService.java index 2d3709f..cc765d0 100644 --- a/android/src/org/qtproject/example/appwaterLevelSensor/WaterLevelService.java +++ b/android/src/org/qtproject/example/appwaterLevelSensor/WaterLevelService.java @@ -25,25 +25,87 @@ import org.json.JSONException; import org.json.JSONObject; import org.json.JSONArray; import android.widget.Toast; +import android.os.IBinder; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; public class WaterLevelService extends Service { private static float alert_thres_distance = 1000000; - private boolean bits_flipped = false; - private String mode = ""; - private String url = ""; - private Thread udpThread; - private Thread cmdThread; - private boolean resetBinds = false; + private static boolean bits_flipped = false; + private static String mode = ""; + private static String url = ""; + private static Thread udpThread; + private static Thread cmdThread; + private static boolean resetBinds = false; + private final IBinder binder = new LocalBinder(); + final Messenger mMessenger = new Messenger(new IncomingHandler()); + public static final int MSG_RESTART_THREADS = 1; - public synchronized boolean checkBound() { + + class IncomingHandler extends Handler { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_RESTART_THREADS: + Log.d("UDP Service MainThread", "Received IPC request to restart threads"); + restartThreads(); + break; + default: + super.handleMessage(msg); + } + } + } + + + public synchronized void restartThreads() { + Log.d("UDP Service MainThread", "In synchronized thread stopper."); + udpThread.interrupt(); + cmdThread.interrupt(); + try { + udpThread.join(); + cmdThread.join(); + } catch (InterruptedException e) { + Log.d("UDP Service MainThread", "Thread joining was interrupted because of: " + e); + } + + new Thread(new + Runnable() { + @Override + public void run() { + try { + // Move your socket and thread starting logic here + if (udpThread == null || !udpThread.isAlive()) { + udpThread = new Thread(new UDPClient()); + udpThread.start(); + } + if (cmdThread == null || !cmdThread.isAlive()) { + cmdThread = new Thread(new UDPCommandClient()); + cmdThread.start(); + } + } catch (Exception e) { + Log.e("UDP Service MainThread", "Restarting the threads", e); + } + } + }).start(); + Log.d("UDP Service MainThread", "Actually restarting the thread"); + } + + public static synchronized boolean checkBound() { return resetBinds; } - public synchronized void setBound(boolean value) { + public static synchronized void setBound(boolean value) { resetBinds = value; } + public class LocalBinder extends android.os.Binder { + WaterLevelService getService() { + return WaterLevelService.this; + } + } + public class UDPCommandClient implements Runnable { private DatagramSocket socket_cmd_recv; private DatagramSocket socket_cmd_send; @@ -51,7 +113,7 @@ public class WaterLevelService extends Service { @Override public void run() { - Log.d("UDP Service", "Command thread initialising"); + Log.d("UDP Service CommandThread", "Command thread initialising"); try { socket_cmd_recv = new DatagramSocket(null); socket_cmd_send = new DatagramSocket(null); @@ -59,15 +121,30 @@ public class WaterLevelService extends Service { socket_cmd_recv.setReuseAddress(true); socket_cmd_send.setReuseAddress(true); socket_cmd_recv.bind(new InetSocketAddress(8178)); - socket_cmd_send.bind(new InetSocketAddress(8179)); - Log.d("UDP Service", "Created command thread sockets"); + socket_cmd_send.bind(new InetSocketAddress(8187)); + boolean not_send_set = true; + Log.d("UDP Service CommandThread", "Created command thread sockets"); while (!Thread.currentThread().isInterrupted()) { if(socket_cmd_recv.isClosed()) { socket_cmd_recv.bind(new InetSocketAddress(8178)); } if(socket_cmd_send.isClosed()) { - socket_cmd_send.bind(new InetSocketAddress(8179)); + socket_cmd_send.bind(new InetSocketAddress(8187)); } + + if(not_send_set) { + String s_data = new String(""); + byte[] buff_s = s_data.getBytes(StandardCharsets.UTF_8); + DatagramPacket packet = new DatagramPacket(buff_s, buff_s.length, InetAddress.getByName("127.0.0.1"), 8186); + try { + socket_cmd_send.connect(InetAddress.getByName("127.0.0.1"), 8186); + socket_cmd_send.send(packet); + } catch(Exception e) { + Log.d("UDP Service CommandThread", "Failed to send data to client due to: " + e); + } + Log.d("UDP Service CommandThread", "Sent set message to client"); + } + byte[] buffer = new byte[1024]; DatagramPacket packet = new DatagramPacket(buffer, buffer.length); try { @@ -76,7 +153,8 @@ public class WaterLevelService extends Service { continue; } String str = new String(buffer, StandardCharsets.UTF_8); - Log.d("UDP Service ", "Received command packet " + str); + Log.d("UDP Service CommandThread", "Received command packet " + str); + not_send_set = false; if(str.startsWith("", ""); - Log.d("UDP Service ", "Flipping " + str); + Log.d("UDP Service CommandThread", "Flipping " + str); if(str.toLowerCase() == "false") { bits_flipped = false; } @@ -110,21 +188,21 @@ public class WaterLevelService extends Service { str = str.replace("", ""); - Log.d("UDP Service ", "Mode " + str); + Log.d("UDP Service CommandThread", "Mode " + str); mode = str.toLowerCase(); } else if(str.startsWith("", ""); - Log.d("UDP Service ", "Url " + str); + Log.d("UDP Service CommandThread", "Url " + str); url = str.toLowerCase(); } } } catch (IOException e) { // showToast("IOException: " + e); - Log.e("UDP Service", "IOException Error" + e); + Log.e("UDP Service CommandThread", "IOException Error" + e); } } @@ -134,11 +212,12 @@ public class WaterLevelService extends Service { private DatagramSocket socket_recv; private DatagramSocket socket_send; private Instant prevAlertTimestamp; + private InetAddress address; private boolean started = false; @Override public void run() { - Log.d("UDP Service", "Client Thread initialising"); + Log.d("UDP Service ClientThread", "Client Thread initialising"); android.net.wifi.WifiManager wifi = (android.net.wifi.WifiManager) getSystemService(Context.WIFI_SERVICE); android.net.wifi.WifiManager.MulticastLock multicastLock = wifi.createMulticastLock("water_level_lock"); android.net.wifi.WifiManager.WifiLock wifiLock = wifi.createWifiLock(android.net.wifi.WifiManager.WIFI_MODE_FULL_HIGH_PERF, "WaterLevel:WifiLock"); @@ -167,16 +246,19 @@ public class WaterLevelService extends Service { socket_send.setReuseAddress(true); socket_send.bind(new InetSocketAddress(8177)); socket_recv.bind(new InetSocketAddress(8176)); - Log.d("UDP Service", "Created Sockets"); + Log.d("UDP Service ClientThread", "Created Sockets"); int count = 0; while (!Thread.currentThread().isInterrupted()) { count++; if(count == 3) { - Log.i("UDP Service", "Thread is running with mode: " + mode); + Log.i("UDP Service ClientThread", "Thread is running with mode: " + mode); count = 0; } if(checkBound()) { - Log.i("UDP Service", "Reconnecting sockets"); + Log.i("UDP Service ClientThread", "Reconnecting sockets"); + this.address = InetAddress.getByName("127.0.0.1"); + socket_recv.disconnect(); + socket_send.disconnect(); socket_recv.close(); socket_send.close(); socket_recv = null; @@ -190,7 +272,7 @@ public class WaterLevelService extends Service { socket_send.bind(new InetSocketAddress(8177)); socket_recv.bind(new InetSocketAddress(8176)); setBound(false); - Log.i("UDP Service", "Reconnected sockets"); + Log.i("UDP Service ClientThread", "Reconnected sockets"); } // if(checkBound()) { // Log.i("UDP Service", "Reset socket binds: " + mode); @@ -238,9 +320,10 @@ public class WaterLevelService extends Service { try { Thread.sleep(2000); } catch (InterruptedException e) { - continue; + Log.d("UDP Service ClientThread", "Thread exiting due to interrupt."); + return; } - Log.d("UDP Service", "Http String Url: " + url); + Log.d("UDP Service ClientThread", "Http String Url: " + url); URL t_url = new URL(url); HttpURLConnection con = (HttpURLConnection) t_url.openConnection(); con.setRequestMethod("GET"); @@ -248,7 +331,7 @@ public class WaterLevelService extends Service { con.setReadTimeout(5000); con.setInstanceFollowRedirects(true); int status = con.getResponseCode(); - Log.d("UDP Service", "Got status from http: " + status); + Log.d("UDP Service ClientThread", "Got status from http: " + status); if(status == 200) { BufferedReader streamReader = new BufferedReader(new InputStreamReader(con.getInputStream())); String data = streamReader.readLine(); @@ -258,10 +341,10 @@ public class WaterLevelService extends Service { float f = (float ) arr.getDouble(0); updated = obj.getString("updated_on"); buffer = ByteBuffer.allocate(4).putFloat(f).array(); - Log.d("UDP Service", "Got value from http: " + f); - Log.d("UDP Service", "Last updated on: " + updated); + Log.d("UDP Service ClientThread", "Got value from http: " + f); + Log.d("UDP Service ClientThread", "Last updated on: " + updated); } catch (JSONException e) { - Log.e("UDP Service", "Invalid Json"); + Log.e("UDP Service ClientThread", "Invalid Json"); // showToast("Invalid Json" + e); continue; } @@ -273,12 +356,13 @@ public class WaterLevelService extends Service { } } else { - Log.d("UDP Service", "Invalid mode: " + mode); + Log.d("UDP Service ClientThread", "Invalid mode: " + mode); // showToast("Invalid mode: " + mode); try { Thread.sleep(3000); } catch (InterruptedException e) { - continue; + Log.d("UDP Service ClientThread", "Thread exiting due to interrupt."); + return; } continue; } @@ -289,8 +373,8 @@ public class WaterLevelService extends Service { else { f = ByteBuffer.wrap(buffer).order(ByteOrder.BIG_ENDIAN).getFloat(); } - Log.d("UDP Service ", "Received packet: " + f); - Log.d("UDP Service ", "Threshold is: " + alert_thres_distance); + Log.d("UDP Service ClientThread", "Received packet: " + f); + Log.d("UDP Service ClientThread", "Threshold is: " + alert_thres_distance); boolean duration_passed = false; if(!started) { duration_passed = true; @@ -311,7 +395,7 @@ public class WaterLevelService extends Service { .setContentText("Water Level is below alert threshold") .setPriority(Notification.PRIORITY_LOW); manager.notify(2, builder.build()); - Log.d("UDP Service", "Notification sent"); + Log.d("UDP Service ClientThread", "Notification sent"); if(!started) { started = true; } @@ -319,20 +403,20 @@ public class WaterLevelService extends Service { if(socket_send.isClosed()) { socket_send.bind(new InetSocketAddress(8177)); } - DatagramPacket send_packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("localhost"), 8180); + DatagramPacket send_packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("127.0.0.1"), 8180); socket_send.send(send_packet); - Log.d("UDP Service ", "Sent packet"); + Log.d("UDP Service ClientThread", "Sent packet"); if(mode.equals("http")) { byte[] buff2 = updated.getBytes(StandardCharsets.UTF_8); - DatagramPacket send_packet_2 = new DatagramPacket(buff2, buff2.length, InetAddress.getByName("localhost"), 8185); + DatagramPacket send_packet_2 = new DatagramPacket(buff2, buff2.length, InetAddress.getByName("127.0.0.1"), 8185); socket_send.send(send_packet_2); - Log.d("UDP Service ", "Sent last updated packet"); + Log.d("UDP Service ClientThread", "Sent last updated packet"); } } } catch (IOException e) { // showToast("IOException: " + e); - Log.e("UDP Service", "IOException Error" + e); + Log.e("UDP Service ClientThread", "IOException Error" + e); } finally { if (wifiLock.isHeld()) wifiLock.release(); @@ -347,7 +431,7 @@ public class WaterLevelService extends Service { } public void startWaterLevelService() { - Log.d("UDP Service", "Starting the service from Activity"); + Log.d("UDP Service MainThread", "Starting the service from Activity"); Intent intent = new Intent(this, WaterLevelService.class); @@ -355,25 +439,25 @@ public class WaterLevelService extends Service { } public WaterLevelService() { super(); - Log.i("UDP Service", "Class is created"); + Log.i("UDP Service MainThread", "Class is created"); } @Override - public android.os.IBinder onBind(android.content.Intent intent) { return null; } + public android.os.IBinder onBind(android.content.Intent intent) { return mMessenger.getBinder(); } @Override public void onCreate() { super.onCreate(); Notification notification = createNotification(); startForeground(1, notification); - Log.i("UDP Service", "Creating Service"); + Log.i("UDP Service MainThread", "Creating Service"); } @Override public void onDestroy() { super.onDestroy(); - Log.i("UDP Service", "Destroying Service"); + Log.i("UDP Service MainThread", "Destroying Service"); } @Override @@ -383,7 +467,7 @@ public class WaterLevelService extends Service { if (intent == null) { - Log.w("UDP Service", "Service restarted with null intent. Stopping to avoid crash."); + Log.w("UDP Service MainThread", "Service restarted with null intent. Stopping to avoid crash."); stopSelf(); return START_NOT_STICKY; } @@ -402,12 +486,12 @@ public class WaterLevelService extends Service { cmdThread.start(); } } catch (Exception e) { - Log.e("UDP Service", "Error starting threads", e); + Log.e("UDP Service MainThread", "Error starting threads", e); } } }).start(); - Log.d("UDP Service", "Actually starting the thread"); + Log.d("UDP Service MainThread", "Actually starting the thread"); int ret = super.onStartCommand(intent, flags, startId); @@ -444,7 +528,7 @@ public class WaterLevelService extends Service { } public static void startQtAndroidService(QtActivity activity) { - Log.d("UDP Service", "Starting the service"); + Log.d("UDP Service MainThread", "Starting the service"); Intent intent = new Intent(activity, WaterLevelService.class); activity.startForegroundService(intent); diff --git a/android/src/org/qtproject/example/appwaterLevelSensor/WaterLevelServiceStarter.java b/android/src/org/qtproject/example/appwaterLevelSensor/WaterLevelServiceStarter.java index 84a36f6..9dccce9 100644 --- a/android/src/org/qtproject/example/appwaterLevelSensor/WaterLevelServiceStarter.java +++ b/android/src/org/qtproject/example/appwaterLevelSensor/WaterLevelServiceStarter.java @@ -10,9 +10,51 @@ import android.app.ActivityManager.RunningServiceInfo; import org.qtproject.qt.android.bindings.QtActivity; import android.os.Handler; import android.os.Looper; +import android.content.ServiceConnection; +import android.content.ComponentName; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; public class WaterLevelServiceStarter { + private static Messenger mServiceMessenger = null; + private static boolean mBound = false; + private static boolean restart_bind = false; + private static ServiceConnection connection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + mServiceMessenger = new Messenger(service); + mBound = true; + Log.d("UDP Service StarterThread", "Connected to Service object reference"); + if(restart_bind) + { + sendRestartMessage(); + Log.d("UDP Service StarterThread", "Restart Threads in Service."); + } + restart_bind = false; + } + + @Override + public void onServiceDisconnected(ComponentName arg0) { + mServiceMessenger = null; + mBound = false; + } + }; + + public static void startAndBindService(Context context) { + Intent intent = new Intent(context, WaterLevelService.class); + context.startForegroundService(intent); + context.bindService(intent, connection, Context.BIND_AUTO_CREATE); + } + + public static void bindService(Context context) { + restart_bind = true; + Intent intent = new Intent(context, WaterLevelService.class); + context.bindService(intent, connection, Context.BIND_AUTO_CREATE); + } private static boolean isMyServiceRunning(Class serviceClass, Context context) { ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); @@ -24,6 +66,7 @@ public class WaterLevelServiceStarter { return false; } + private static int getServicePid(Class serviceClass, Context context) { ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { @@ -34,6 +77,20 @@ public class WaterLevelServiceStarter { return 0; } + + public static void sendRestartMessage() { + if (!mBound || mServiceMessenger == null) { + Log.d("UDP Service StarterThread", "Service is not running."); + } + try { + Message msg = Message.obtain(null, WaterLevelService.MSG_RESTART_THREADS); + mServiceMessenger.send(msg); + Log.d("UDP Service StarterThread", "Sent restart signal to remote process"); + } catch (RemoteException e) { + Log.e("UDP Service StarterThread", "Failed to send message", e); + } + } + public static void startService(Context context) { // Log.d("UDP Service", "Starting service via QtActivity instance"); @@ -45,15 +102,16 @@ public class WaterLevelServiceStarter { new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { + if (!isMyServiceRunning(WaterLevelService.class, context)) { - Log.d("UDP Service", "Starting service safely on Main Looper"); - Intent intent = new Intent(context, WaterLevelService.class); - context.startForegroundService(intent); + Log.d("UDP Service StarterThread", "Starting service safely on Main Looper"); + startAndBindService(context); } else { - Log.d("UDP Service", "Service already running"); + Log.d("UDP Service StarterThread", "Service already running, so restarting the threads."); + bindService(context); } - Log.d("UDP Service", "Background service running with pid: " + getServicePid(WaterLevelService.class, context)); + Log.d("UDP Service StarterThread", "Background service running with pid: " + getServicePid(WaterLevelService.class, context)); } }); } diff --git a/udplistener.cpp b/udplistener.cpp index e44a9eb..155df4e 100644 --- a/udplistener.cpp +++ b/udplistener.cpp @@ -11,6 +11,7 @@ UDPListener::UDPListener(QObject *parent) connect(worker, &Worker::lastUpdateddatagramReceived, this, &UDPListener::lastUpdateddatagramReceived); connect(worker, &Worker::datagramReceived, this, &UDPListener::datagramRecieved); connect(worker, &Worker::socketError, this, &UDPListener::socketError); + connect(worker, &Worker::sendConfig, this, &UDPListener::sendConfigOnSet); connect(this, &UDPListener::startWorker, worker, &Worker::run); connect(this, &UDPListener::changeWorkerMode, worker, &Worker::changeMode); thread->start(); @@ -33,52 +34,15 @@ void UDPListener::setDistance(double newDistance) emit distanceChanged(); } -void UDPListener::moveAppToBackground() +void UDPListener::sendConfigOnSet() { -#ifdef Q_OS_ANDROID - service->moveAppToBackground(); -#endif -} - -void UDPListener::lastUpdateddatagramReceived(QByteArray data) -{ - QString s_data = QString::fromUtf8(data); - qDebug() << "Main Class last updated on: " << s_data; - QDateTime time = QDateTime::fromString(s_data, "dd/MM/yy hh:mm:ss"); - QDateTime thres_time = QDateTime::currentDateTime().addSecs(-1800); - if(time.isValid() && time < thres_time) - { - emit lastUpdatedChanged(s_data, false); - } - else if(time > thres_time && time.isValid()) { - emit lastUpdatedChanged(s_data, true); - } - else if(!time.isValid()) { - emit lastUpdatedChanged("Invalid Date", true); - } -} - -void UDPListener::continueDestruction() -{ - destroyed = true; -} - -void UDPListener::resetAverages() -{ - averages.clear(); -} - -void UDPListener::setFlipBits(bool flip_bits) -{ - m_flip_bits = flip_bits; -} - -void UDPListener::setConfig(float distance, bool flip_bits, QString mode, QString url) -{ - setFlipBits(flip_bits); + bool flip_bits = m_flip_bits; + QString url = m_url; + QString mode = m_mode; + float distance = m_distance; if(!command_socket) { command_socket = new QUdpSocket(this); - bool bind = command_socket->bind(8181); + bool bind = command_socket->bind(QHostAddress::Any, 0); if(bind) { QNetworkDatagram data1, data2, data3, data4; data1.setDestination(QHostAddress::LocalHost, 8178); @@ -122,12 +86,63 @@ void UDPListener::setConfig(float distance, bool flip_bits, QString mode, QStrin command_socket->deleteLater(); command_socket = nullptr; + qDebug() << "Sent all Command Statements."; emit changeWorkerMode(mode, url); } else { showError("Command Socket Bind Failed"); } } +} + +void UDPListener::moveAppToBackground() +{ +#ifdef Q_OS_ANDROID + service->moveAppToBackground(); +#endif +} + +void UDPListener::lastUpdateddatagramReceived(QByteArray data) +{ + QString s_data = QString::fromUtf8(data); + qDebug() << "Main Class last updated on: " << s_data; + QDateTime time = QDateTime::fromString(s_data, "dd/MM/yy hh:mm:ss").addYears(100); + QDateTime thres_time = QDateTime::currentDateTime().addSecs(-1800); + if(time.isValid() && thres_time < time) + { + emit lastUpdatedChanged(s_data, false); + } + else if(thres_time > time && time.isValid()) { + emit lastUpdatedChanged(s_data, true); + } + else if(!time.isValid()) { + emit lastUpdatedChanged("Invalid Date", true); + } +} + +void UDPListener::continueDestruction() +{ + destroyed = true; +} + +void UDPListener::resetAverages() +{ + averages.clear(); +} + +void UDPListener::setFlipBits(bool flip_bits) +{ + m_flip_bits = flip_bits; +} + +void UDPListener::setConfig(float distance, bool flip_bits, QString mode, QString url) +{ + setFlipBits(flip_bits); + setDistance(distance); + setMode(mode); + setUrl(url); + emit changeWorkerMode(mode, url); + qDebug() << "Setting config from UI completed." << flip_bits << distance << mode << url; averages.clear(); } @@ -279,6 +294,11 @@ void Worker::stop() socket->close(); delete socket; } + if(socket_3) { + disconnect(socket_3, nullptr, nullptr, nullptr); + socket_3->close(); + delete socket_3; + } if(httpTimer) { disconnect(httpTimer, nullptr, nullptr, nullptr); delete httpTimer; @@ -295,27 +315,36 @@ void Worker::run() using namespace std::chrono_literals; socket = new QUdpSocket(this); socket_2 = new QUdpSocket(this); + socket_3 = new QUdpSocket(this); httpTimer = new QTimer(this); manager = new QNetworkAccessManager(this); #ifdef Q_OS_ANDROID // If it is android use it as a command socket; - bool bind = socket->bind(QHostAddress::Any, 8180, QUdpSocket::ReuseAddressHint); - bool bind2 = socket_2->bind(QHostAddress::Any, 8185, QUdpSocket::ReuseAddressHint); + bool bind = socket->bind(QHostAddress::LocalHost, 8180, QUdpSocket::ReuseAddressHint | QUdpSocket::ShareAddress); + bool bind2 = socket_2->bind(QHostAddress::LocalHost, 8185, QUdpSocket::ReuseAddressHint | QUdpSocket::ShareAddress); + bool bind3 = socket_3->bind(QHostAddress::LocalHost, 8186, QUdpSocket::ReuseAddressHint | QUdpSocket::ShareAddress); #else // Else use it as a receiver; bool bind = socket->bind(QHostAddress("192.168.1.255"), 8176); bool bind2 = true; #endif - if(!bind || !bind2) + if(!bind || !bind2 || !bind3) { qDebug() << "UI Worker socket bind failed" << bind << socket->errorString(); + qDebug() << "UI Worker socket bind failed" << bind2 << socket_2->errorString(); + qDebug() << "UI Worker socket bind failed" << bind3 << socket_3->errorString(); emit socketError(socket->errorString()); emit socketError(socket_2->errorString()); + emit socketError(socket_3->errorString()); qApp->exit(-1); } connect(httpTimer, &QTimer::timeout, this, &Worker::httpTimerTimeout); connect(socket, &QUdpSocket::readyRead, this, &Worker::socketDataReceived); connect(socket_2, &QUdpSocket::readyRead, this, &Worker::socket2DataReceived); + connect(socket_3, &QUdpSocket::readyRead, this, &Worker::socket3DataReceived); +#ifdef Q_OS_ANDROID + qDebug() << "Waiting for message from service."; +#endif } @@ -333,6 +362,43 @@ void Worker::changeMode(QString mode, QString url) httpTimer->stop(); socketDataReceived(); } + if(socket) { + if(socket->hasPendingDatagrams()) { + socketDataReceived(); + } + } + if(socket_2) { + if(socket_2->hasPendingDatagrams()) { + socket2DataReceived(); + } + } + if(socket_3) { + if(socket_3->hasPendingDatagrams()) { + socket3DataReceived(); + } + } + +} + +void Worker::socket3DataReceived() +{ + if(socket_3->hasPendingDatagrams()) { + while(this->mode == "" && this->url == "") { + QCoreApplication::processEvents(); + // qDebug() << "Worker is waiting for mode to be set."; + } + size_t data_size = socket_3->pendingDatagramSize(); + qDebug() << "Socket 3 has pending data: " << data_size; + if(data_size < 100000) { + char buff[data_size]; + socket_3->readDatagram(buff, data_size); + QByteArray data = QByteArray::fromRawData(buff, data_size); + if(QString::fromUtf8(data) == "") { + qDebug() << "Data Received from Service Threads."; + emit sendConfig(); + } + } + } } void Worker::socket2DataReceived() @@ -349,6 +415,9 @@ void Worker::socket2DataReceived() else if(mode == "udp") { qDebug() << "Last Updated on Socket data received in udp mode ignoring it."; } + else { + qDebug() << "Mode is not set in socket 2"; + } } } @@ -373,5 +442,34 @@ void Worker::socketDataReceived() else if(mode == "http") { qDebug() << "Socket data received in http mode ignoring it."; } + else { + qDebug() << "Mode is not set in socket."; + } } } + +QString UDPListener::mode() const +{ + return m_mode; +} + +void UDPListener::setMode(const QString &newMode) +{ + if (m_mode == newMode) + return; + m_mode = newMode; + emit modeChanged(); +} + +QString UDPListener::url() const +{ + return m_url; +} + +void UDPListener::setUrl(const QString &newUrl) +{ + if (m_url == newUrl) + return; + m_url = newUrl; + emit urlChanged(); +} diff --git a/udplistener.h b/udplistener.h index 8c123c8..079dd35 100644 --- a/udplistener.h +++ b/udplistener.h @@ -25,6 +25,7 @@ class Worker: public QObject { Q_OBJECT QUdpSocket *socket = nullptr; QUdpSocket *socket_2 = nullptr; + QUdpSocket *socket_3 = nullptr; QString mode = ""; QString url = ""; QNetworkAccessManager *manager = nullptr; @@ -32,6 +33,7 @@ class Worker: public QObject { public: explicit Worker(QObject *parent = nullptr); signals: + void sendConfig(); void stopped(); void socketError(QString error); void lastUpdateddatagramReceived(QByteArray data); @@ -43,6 +45,7 @@ public slots: void run(); void changeMode(QString mode, QString url); private slots: + void socket3DataReceived(); void socket2DataReceived(); void socketDataReceived(); }; @@ -52,6 +55,8 @@ class UDPListener : public QObject Q_OBJECT QML_ELEMENT Q_PROPERTY(double distance READ distance WRITE setDistance NOTIFY distanceChanged FINAL) + Q_PROPERTY(QString mode READ mode WRITE setMode NOTIFY modeChanged FINAL) + Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged FINAL) bool destroyed = false; #ifdef Q_OS_ANDROID service *service = nullptr; @@ -60,6 +65,12 @@ public: explicit UDPListener(QObject *parent = nullptr); double distance() const; void setDistance(double newDistance); + QString mode() const; + void setMode(const QString &newMode); + + QString url() const; + void setUrl(const QString &newUrl); + signals: void lastUpdatedChanged(QString last_updated, bool warn); void stopWorker(); @@ -70,7 +81,12 @@ signals: void disconnected(); void distanceReceived(double dist, QString timestamp); void changeWorkerMode(QString mode, QString url); + void modeChanged(); + void initLoadFinished(); + void urlChanged(); + public slots: + void sendConfigOnSet(); void moveAppToBackground(); void lastUpdateddatagramReceived(QByteArray data); void continueDestruction(); @@ -93,6 +109,8 @@ private: QThread *thread = nullptr; QTimer *timer = nullptr; bool m_flip_bits; + QString m_mode; + QString m_url; }; #endif // UDPLISTENER_H