From c5d3402f9804a23033a2e1dd6cc240ccdb441cb6 Mon Sep 17 00:00:00 2001 From: Nathaniel Wesley Filardo Date: Sat, 11 Feb 2017 00:59:15 -0500 Subject: [PATCH] Move some CtFwS logic to library --- lib/.gitignore | 1 + lib/build.gradle | 8 ++ .../ctfwstimer/lib/CtFwSGameState.java | 103 ++++++++++++++++++ .../ctfwstimer/lib/CtFwSMessageFilter.java | 46 ++++++++ mobile/build.gradle | 2 + .../ctfwstimer/CtFwSCallbacksMQTT.java | 59 ++-------- .../ctfwstimer/CtFwSDisplay.java | 2 + .../ctfwstimer/CtFwSGameState.java | 65 ----------- .../ctfwstimer/MainActivity.java | 2 + settings.gradle | 2 +- 10 files changed, 175 insertions(+), 115 deletions(-) create mode 100644 lib/.gitignore create mode 100644 lib/build.gradle create mode 100644 lib/src/main/java/com/acmetensortoys/ctfwstimer/lib/CtFwSGameState.java create mode 100644 lib/src/main/java/com/acmetensortoys/ctfwstimer/lib/CtFwSMessageFilter.java delete mode 100644 mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSGameState.java diff --git a/lib/.gitignore b/lib/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/lib/.gitignore @@ -0,0 +1 @@ +/build diff --git a/lib/build.gradle b/lib/build.gradle new file mode 100644 index 0000000..49df001 --- /dev/null +++ b/lib/build.gradle @@ -0,0 +1,8 @@ +apply plugin: 'java' + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) +} + +sourceCompatibility = "1.7" +targetCompatibility = "1.7" diff --git a/lib/src/main/java/com/acmetensortoys/ctfwstimer/lib/CtFwSGameState.java b/lib/src/main/java/com/acmetensortoys/ctfwstimer/lib/CtFwSGameState.java new file mode 100644 index 0000000..d86e9da --- /dev/null +++ b/lib/src/main/java/com/acmetensortoys/ctfwstimer/lib/CtFwSGameState.java @@ -0,0 +1,103 @@ +package com.acmetensortoys.ctfwstimer.lib; + +import java.util.NoSuchElementException; +import java.util.Scanner; + +public class CtFwSGameState { + public boolean configured; + public long startT; // NTP seconds for game start + public int setupD; + public int rounds; + public int roundD; + public long endT = 0; // NTP seconds for game end (if >= startT) + + public int flagsTotal; + public boolean flagsVisible = false; + public int flagsRed = 0; + public int flagsYel = 0; + + public void setFlags(boolean visible) { + flagsVisible = visible; + } + public void setFlags(int red, int yel) { + flagsRed = red; flagsYel = yel; + } + + public void mqttConfigMessage(String st) { + String tm = st.trim(); + switch (tm) { + case "none": + this.configured = false; + break; + default: + try { + Scanner s = new Scanner(tm); + this.startT = s.nextLong(); + this.setupD = s.nextInt(); + this.rounds = s.nextInt(); + this.roundD = s.nextInt(); + this.flagsTotal = s.nextInt(); + this.configured = true; + } catch (NoSuchElementException e) { + this.configured = false; + } + break; + } + } + public void mqttFlagsMessage(String st) { + String tm = st.trim(); + switch(tm) { + case "?": + this.setFlags(false); + break; + default: + Scanner s = new Scanner(tm); + try { + this.setFlags(true); + this.setFlags(s.nextInt(),s.nextInt()); + } catch (NumberFormatException e) { + this.setFlags(false); + } + } + } + + public class Now { + public String rationale = null; // null if game is in play, otherwise other fields invalid + public int round = 0; // 0 for setup + public long roundStart = 0, roundEnd = 0; // NTP seconds + public boolean stop = false; + } + public Now getNow(long now) { + Now res = new Now(); + if (!configured) { + res.rationale = "Game not configured"; + res.stop = true; + } else if (endT >= startT) { + res.rationale = "Game over!"; + res.stop = true; + } else if (now <= startT) { + res.rationale = "Start time in the future!"; + } + if (res.rationale != null) { + return res; + } + long elapsed = now - startT; + if (elapsed < setupD) { + res.round = 0; + res.roundStart = startT; + res.roundEnd = startT + setupD; + return res; + } + elapsed -= setupD; + res.round = (int)(elapsed / roundD); + if (res.round >= rounds) { + res.rationale = "Game over!"; + res.stop = true; + return res; + } + res.roundStart = startT + setupD + (res.round * roundD); + res.roundEnd = res.roundStart + roundD; + res.round += 1; + return res; + } +} diff --git a/lib/src/main/java/com/acmetensortoys/ctfwstimer/lib/CtFwSMessageFilter.java b/lib/src/main/java/com/acmetensortoys/ctfwstimer/lib/CtFwSMessageFilter.java new file mode 100644 index 0000000..be919df --- /dev/null +++ b/lib/src/main/java/com/acmetensortoys/ctfwstimer/lib/CtFwSMessageFilter.java @@ -0,0 +1,46 @@ +package com.acmetensortoys.ctfwstimer.lib; + +import java.util.NoSuchElementException; +import java.util.Scanner; + +public class CtFwSMessageFilter { + final private CtFwSGameState mCgs; + public CtFwSMessageFilter(CtFwSGameState cgs) { + mCgs = cgs; + } + + public class Msg { + public long when; + public String msg; + + public Msg(long when, String msg) { + this.when = when; + this.msg = msg; + } + } + + private long lastMsgTimestamp = 0; + + public Msg filter(String str) { + Scanner s = new Scanner(str); + long t; + try { + t = s.nextLong(); + } catch (NoSuchElementException nse) { + // Maybe they forgot a time stamp. That's not ideal, but... fake it? + // XXX Back off a bit, for time sync reasons + lastMsgTimestamp = System.currentTimeMillis()/1000 - 30; + return new Msg(lastMsgTimestamp, str); + } + + // If there is no configuration, assume the message is new enough + // If there *is* a configuration, check the time. + if ((!mCgs.configured || t >= mCgs.startT) && (lastMsgTimestamp <= t)) { + s.useDelimiter("\\z"); + lastMsgTimestamp = t; + return new Msg(lastMsgTimestamp, s.next().trim()); + } + + return null; + } +} diff --git a/mobile/build.gradle b/mobile/build.gradle index 31f6c5a..b4c4015 100644 --- a/mobile/build.gradle +++ b/mobile/build.gradle @@ -36,6 +36,8 @@ dependencies { }) wearApp project(':wear') + compile project(":lib") + compile('org.eclipse.paho:org.eclipse.paho.android.service:1.1.1') { exclude module: 'support-v4' } diff --git a/mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSCallbacksMQTT.java b/mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSCallbacksMQTT.java index e2f9d99..30e43df 100644 --- a/mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSCallbacksMQTT.java +++ b/mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSCallbacksMQTT.java @@ -2,6 +2,9 @@ package com.acmetensortoys.ctfwstimer; import android.util.Log; +import com.acmetensortoys.ctfwstimer.lib.CtFwSGameState; +import com.acmetensortoys.ctfwstimer.lib.CtFwSMessageFilter; + import org.eclipse.paho.client.mqttv3.IMqttMessageListener; import org.eclipse.paho.client.mqttv3.MqttMessage; @@ -11,10 +14,12 @@ import java.util.Scanner; class CtFwSCallbacksMQTT { final private CtFwSDisplay mCdl; final private CtFwSGameState mCgs; + final private CtFwSMessageFilter mCmf; CtFwSCallbacksMQTT(CtFwSDisplay cdl, CtFwSGameState cgs) { mCdl = cdl; mCgs = cgs; + mCmf = new CtFwSMessageFilter(mCgs); } IMqttMessageListener onConfig = new IMqttMessageListener() { @@ -22,25 +27,7 @@ class CtFwSCallbacksMQTT { public void messageArrived(String topic, MqttMessage message) throws Exception { String tm = message.toString().trim(); Log.d("CtFwS", "Message(Config): " + tm); - - switch (tm) { - case "none": - mCgs.configured = false; - break; - default: - try { - Scanner s = new Scanner(tm); - mCgs.startT = s.nextLong(); - mCgs.setupD = s.nextInt(); - mCgs.rounds = s.nextInt(); - mCgs.roundD = s.nextInt(); - mCgs.flagsTotal = s.nextInt(); - mCgs.configured = true; - } catch (NoSuchElementException e) { - mCgs.configured = false; - } - break; - } + mCgs.mqttConfigMessage(tm); mCdl.notifyGameState(); } }; @@ -63,41 +50,15 @@ class CtFwSCallbacksMQTT { public void messageArrived(String topic, MqttMessage message) throws Exception { String tm = message.toString().trim(); Log.d("CtFwS", "Message(Flags): " + tm); - - switch(tm) { - case "?": - mCgs.setFlags(false); - break; - default: - Scanner s = new Scanner(tm); - try { - mCgs.setFlags(true); - mCgs.setFlags(s.nextInt(),s.nextInt()); - } catch (NumberFormatException e) { - mCgs.setFlags(false); - } - } + mCgs.mqttFlagsMessage(tm); mCdl.notifyFlags(); } }; - private long lastMsgTimestamp = 0; private void onMessageCommon(String str) { - Scanner s = new Scanner(str); - try { - long t = s.nextLong(); - // If there is no configuration, assume the message is new enough - // If there *is* a configuration, check the time. - if ((!mCgs.configured || t >= mCgs.startT) && (lastMsgTimestamp <= t)) { - s.useDelimiter("\\z"); - lastMsgTimestamp = t; - mCdl.notifyMessage(t, s.next().trim()); - } - } catch (NoSuchElementException nse) { - // Maybe they forgot a time stamp. That's not ideal, but... fake it? - lastMsgTimestamp = System.currentTimeMillis()/1000; - mCdl.notifyMessage(lastMsgTimestamp, str); - lastMsgTimestamp -= 30; // XXX Back off a bit, for time sync reasons + CtFwSMessageFilter.Msg m = mCmf.filter(str); + if (m != null) { + mCdl.notifyMessage(m.when, m.msg); } } diff --git a/mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSDisplay.java b/mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSDisplay.java index c0ceba6..f4b9adc 100644 --- a/mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSDisplay.java +++ b/mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSDisplay.java @@ -9,6 +9,8 @@ import android.widget.Chronometer; import android.widget.ProgressBar; import android.widget.TextView; +import com.acmetensortoys.ctfwstimer.lib.CtFwSGameState; + // TODO nwf is bad at UI design; someone who isn't him should improve this class CtFwSDisplay { diff --git a/mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSGameState.java b/mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSGameState.java deleted file mode 100644 index 3c12b2e..0000000 --- a/mobile/src/main/java/com/acmetensortoys/ctfwstimer/CtFwSGameState.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.acmetensortoys.ctfwstimer; - -import java.util.NoSuchElementException; -import java.util.Scanner; - -class CtFwSGameState { - boolean configured; - long startT; // NTP seconds for game start - int setupD; - int rounds; - int roundD; - long endT = 0; // NTP seconds for game end (if >= startT) - - int flagsTotal; - boolean flagsVisible = false; - int flagsRed = 0; - int flagsYel = 0; - - void setFlags(boolean visible) { - flagsVisible = visible; - } - void setFlags(int red, int yel) { - flagsRed = red; flagsYel = yel; - } - - class Now { - String rationale = null; // null if game is in play, otherwise other fields invalid - int round = 0; // 0 for setup - long roundStart = 0, roundEnd = 0; // NTP seconds - boolean stop = false; - } - public Now getNow(long now) { - Now res = new Now(); - if (!configured) { - res.rationale = "Game not configured"; - res.stop = true; - } else if (endT >= startT) { - res.rationale = "Game over!"; - res.stop = true; - } else if (now <= startT) { - res.rationale = "Start time in the future!"; - } - if (res.rationale != null) { - return res; - } - long elapsed = now - startT; - if (elapsed < setupD) { - res.round = 0; - res.roundStart = startT; - res.roundEnd = startT + setupD; - return res; - } - elapsed -= setupD; - res.round = (int)(elapsed / roundD); - if (res.round >= rounds) { - res.rationale = "Game over!"; - res.stop = true; - return res; - } - res.roundStart = startT + setupD + (res.round * roundD); - res.roundEnd = res.roundStart + roundD; - res.round += 1; - return res; - } -} diff --git a/mobile/src/main/java/com/acmetensortoys/ctfwstimer/MainActivity.java b/mobile/src/main/java/com/acmetensortoys/ctfwstimer/MainActivity.java index ef15e37..6bc9e0a 100644 --- a/mobile/src/main/java/com/acmetensortoys/ctfwstimer/MainActivity.java +++ b/mobile/src/main/java/com/acmetensortoys/ctfwstimer/MainActivity.java @@ -26,6 +26,8 @@ import org.eclipse.paho.client.mqttv3.MqttConnectOptions; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; +import com.acmetensortoys.ctfwstimer.lib.CtFwSGameState; + public class MainActivity extends AppCompatActivity { static private final String mqttClientId = MqttClient.generateClientId(); diff --git a/settings.gradle b/settings.gradle index 6a4e79f..a4a0c6b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':mobile', ':wear' +include ':mobile', ':wear', ':lib' -- 2.50.1