diff --git a/app/build.gradle b/app/build.gradle index 26a4072..be84649 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,13 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 23 - buildToolsVersion "23.0.2" + compileSdkVersion 25 + buildToolsVersion "26.0.0" defaultConfig { applicationId "rumpold.de.androiddsky" minSdkVersion 21 - targetSdkVersion 23 + targetSdkVersion 25 versionCode 1 versionName "1.0" } @@ -22,6 +22,8 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' - compile 'com.android.support:appcompat-v7:23.4.0' - compile 'com.android.support:support-v4:23.4.0' + + def supportLibVersion = "25.4.0" + compile "com.android.support:appcompat-v7:$supportLibVersion" + compile "com.android.support:support-v4:$supportLibVersion" } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7d1c75d..e343f86 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,5 +21,5 @@ - + \ No newline at end of file diff --git a/app/src/main/java/de/rumpold/androiddsky/DSKY.java b/app/src/main/java/de/rumpold/androiddsky/DSKY.java index d5b9dc3..991c8d4 100755 --- a/app/src/main/java/de/rumpold/androiddsky/DSKY.java +++ b/app/src/main/java/de/rumpold/androiddsky/DSKY.java @@ -7,8 +7,6 @@ import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; import de.rumpold.androiddsky.network.YaAgcClient; import de.rumpold.androiddsky.ui.DSKYActivity; @@ -17,8 +15,7 @@ import de.rumpold.androiddsky.ui.DSKYActivity; * Created by Adriano on 17.05.2016. */ public class DSKY { - public static final String TAG = "TAG"; - public static final int UPDATE_RATE = 25; + private static final String TAG = "TAG"; private final DSKYActivity activity; private final YaAgcClient client; @@ -30,9 +27,10 @@ public class DSKY { private char signR1; private char signR2; private char signR3; - private String[] register1 = new String[5]; - private String[] register2 = new String[5]; - private String[] register3 = new String[5]; + + private char[] register1 = new char[5]; + private char[] register2 = new char[5]; + private char[] register3 = new char[5]; private boolean compActy; private boolean uplinkActy; @@ -47,9 +45,9 @@ public class DSKY { private boolean oprErr; private boolean stby; private boolean restart; - private final ScheduledThreadPoolExecutor executor; private final Map keycodeMap = new HashMap<>(); + { keycodeMap.put("0", 16); keycodeMap.put("1", 1); @@ -69,17 +67,20 @@ public class DSKY { keycodeMap.put("ENTR", 28); keycodeMap.put("CLR", 30); keycodeMap.put("NOUN", 31); + keycodeMap.put("PRO", 1 << 13); } public DSKY(DSKYActivity activity) { this.activity = activity; this.client = new YaAgcClient(this); - this.executor = new ScheduledThreadPoolExecutor(1); + Arrays.fill(register1, ' '); + Arrays.fill(register2, ' '); + Arrays.fill(register3, ' '); + } - Arrays.fill(register1, ""); - Arrays.fill(register2, ""); - Arrays.fill(register3, ""); + public DSKYActivity getActivity() { + return activity; } public void connect() { @@ -93,43 +94,39 @@ public class DSKY { } } }); - - executor.scheduleAtFixedRate(new Runnable() { - @Override - public void run() { - activity.updateIndicator(R.id.lbl_gimbalLock, gimbalLock); - activity.updateIndicator(R.id.lbl_noAtt, noAtt); - activity.updateIndicator(R.id.lbl_uplinkActy, uplinkActy); - activity.updateIndicator(R.id.lbl_prog, progError); - activity.updateIndicator(R.id.lbl_tracker, tracker); - activity.updateIndicator(R.id.lbl_oprErr, oprErr); - activity.updateIndicator(R.id.lbl_stby, stby); - activity.updateIndicator(R.id.lbl_keyRel, keyRel); - activity.updateIndicator(R.id.lbl_restart, restart); - - activity.updateIndicator(R.id.lbl_compActy, compActy); - activity.updateDisplay(R.id.lbl_progId, prog); - activity.updateDisplay(R.id.lbl_verb, verb); - activity.updateDisplay(R.id.lbl_noun, noun); - - activity.updateDisplay(R.id.lbl_R1, concat(register1)); - activity.updateDisplay(R.id.lbl_R2, concat(register2)); - activity.updateDisplay(R.id.lbl_R3, concat(register3)); - - - activity.updateDisplay(R.id.lbl_sign_R1, String.valueOf(signR1)); - activity.updateDisplay(R.id.lbl_sign_R2, String.valueOf(signR2)); - activity.updateDisplay(R.id.lbl_sign_R3, String.valueOf(signR3)); - } - }, UPDATE_RATE, UPDATE_RATE, TimeUnit.MILLISECONDS); } - private String concat(String[] array) { - final StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < array.length; i++) { - buffer.append(array[i]); + public void refreshDisplay() { + activity.updateIndicator(R.id.lbl_gimbalLock, gimbalLock); + activity.updateIndicator(R.id.lbl_noAtt, noAtt); + activity.updateIndicator(R.id.lbl_uplinkActy, uplinkActy); + activity.updateIndicator(R.id.lbl_prog, progError); + activity.updateIndicator(R.id.lbl_tracker, tracker); + activity.updateIndicator(R.id.lbl_oprErr, oprErr); + activity.updateIndicator(R.id.lbl_stby, stby); + activity.updateIndicator(R.id.lbl_keyRel, keyRel); + activity.updateIndicator(R.id.lbl_restart, restart); + + activity.updateIndicator(R.id.lbl_compActy, compActy); + activity.updateDisplay(R.id.lbl_progId, prog); + activity.updateDisplay(R.id.lbl_verb, verb); + activity.updateDisplay(R.id.lbl_noun, noun); + + activity.updateDisplay(R.id.lbl_R1, join(register1)); + activity.updateDisplay(R.id.lbl_R2, join(register2)); + activity.updateDisplay(R.id.lbl_R3, join(register3)); + + activity.updateDisplay(R.id.lbl_sign_R1, String.valueOf(signR1)); + activity.updateDisplay(R.id.lbl_sign_R2, String.valueOf(signR2)); + activity.updateDisplay(R.id.lbl_sign_R3, String.valueOf(signR3)); + } + + private static String join(char[] chars) { + final StringBuilder builder = new StringBuilder(chars.length); + for (char ch : chars) { + builder.append(ch); } - return buffer.toString(); + return builder.toString(); } public void disconnect() { @@ -143,8 +140,6 @@ public class DSKY { } } }); - - executor.shutdownNow(); } public void setCompActy(boolean compActy) { @@ -211,46 +206,59 @@ public class DSKY { this.verb = verb; } - public void setRegister1(int index, String digit) { + public void setRegister1(int index, char digit) { Log.d(TAG, "setRegister1: " + index + ", " + digit); this.register1[index] = digit; } - public void setRegister2(int index, String digit) { + public void setRegister2(int index, char digit) { Log.d(TAG, "setRegister2: " + index + ", " + digit); this.register2[index] = digit; } - public void setRegister3(int index, String digit) { + public void setRegister3(int index, char digit) { Log.d(TAG, "setRegister3: " + index + ", " + digit); this.register3[index] = digit; } - public void setSignR1(char signR1) { - this.signR1 = signR1; + public void setSignR1(boolean signR1P, boolean signR1N) { + if (signR1N == signR1P) { + signR1 = ' '; + } else if (signR1P) { + signR1 = '+'; + } else { + signR1 = '-'; + } } - public void setSignR2(char signR2) { - this.signR2 = signR2; + public void setSignR2(boolean signR2P, boolean signR2N) { + if (signR2N == signR2P) { + signR2 = ' '; + } else if (signR2P) { + signR2 = '+'; + } else { + signR2 = '-'; + } } - public void setSignR3(char signR3) { - this.signR3 = signR3; + public void setSignR3(boolean signR3P, boolean signR3N) { + if (signR3N == signR3P) { + signR3 = ' '; + } else if (signR3P) { + signR3 = '+'; + } else { + signR3 = '-'; + } } public void buttonPressed(final String button) { Log.d(TAG, "buttonPressed: " + button); - AsyncTask.execute(new Runnable() { @Override public void run() { try { - if ("PRO".equals(button)) { - client.sendProceed(); - } else { - final Integer keyCode = keycodeMap.get(button); - client.sendKeyCode(keyCode); - } + final Integer keyCode = keycodeMap.get(button); + client.sendKeyCode(keyCode); } catch (IOException e) { Log.w(TAG, "buttonPressed: Could not send key press", e); } diff --git a/app/src/main/java/de/rumpold/androiddsky/network/AgcPacket.java b/app/src/main/java/de/rumpold/androiddsky/network/AgcPacket.java index aa3df89..e4ec049 100755 --- a/app/src/main/java/de/rumpold/androiddsky/network/AgcPacket.java +++ b/app/src/main/java/de/rumpold/androiddsky/network/AgcPacket.java @@ -1,13 +1,15 @@ package de.rumpold.androiddsky.network; +import android.util.Log; + import java.nio.ByteBuffer; -import java.nio.ByteOrder; /** * Created by Adriano on 17.05.2016. */ public class AgcPacket { - public static final int PACKET_LENGTH = 4; + private static final int PACKET_LENGTH = 4; + private static final String TAG = AgcPacket.class.getSimpleName(); private final boolean u; private final boolean t; @@ -31,22 +33,13 @@ public class AgcPacket { */ public static AgcPacket parseAgcPacket(ByteBuffer bytes) { try { - bytes.rewind(); - - /*final StringBuilder sb = new StringBuilder(); - for (byte b : bytes.array()) { - sb.append(String.format("%8s", Integer.toBinaryString(((int) b) & 0xff)).replace(' ', '0')); - sb.append(' '); - } - Log.d("AGCPacket", "AgcPacket: " + sb.toString());*/ - - bytes.order(ByteOrder.BIG_ENDIAN); if (bytes.remaining() != PACKET_LENGTH) { // invalid packet length - throw new IllegalArgumentException("packet length"); + //throw new IllegalArgumentException("packet length, " + bytes.remaining() + " != " + PACKET_LENGTH); + return null; } - /* PARSE BYTE #1 */ + /* PARSE BYTE #1 */ int byteNum = 0; char c = (char) ((short) bytes.get() & 0xff); validateByteHeader(c, byteNum); @@ -56,7 +49,7 @@ public class AgcPacket { boolean t = (c & 0b0001_0000) > 0; int ioPort = c & 0b0000_1111; - /* PARSE BYTE #2 */ + /* PARSE BYTE #2 */ ++byteNum; c = (char) ((short) bytes.get() & 0xff); validateByteHeader(c, byteNum); @@ -64,14 +57,14 @@ public class AgcPacket { ioPort = (ioPort << 3) | (c & 0b0011_1000) >> 3; int dataCode = (c & 0b0000_0111); - /* PARSE BYTE #3 */ + /* PARSE BYTE #3 */ ++byteNum; c = (char) ((short) bytes.get() & 0xff); validateByteHeader(c, byteNum); dataCode = (dataCode << 6) | (c & 0b0011_1111); - /* PARSE BYTE #4 */ + /* PARSE BYTE #4 */ ++byteNum; c = (char) ((short) bytes.get() & 0xff); validateByteHeader(c, byteNum); @@ -80,14 +73,16 @@ public class AgcPacket { return new AgcPacket(dataCode, u, t, ioPort); } catch (Exception e) { + Log.w(TAG, "parseAgcPacket: ", e); return null; } } private static void validateByteHeader(char c, int byteNum) { - if ((c & 0b1100_0000) >> 6 != byteNum) { + final int header = (c & 0b1100_0000) >> 6; + if (header != byteNum) { // invalid byte header - throw new IllegalArgumentException("packet byte header in byte #" + byteNum); + throw new IllegalArgumentException("packet byte header in byte #" + byteNum + ", got " + header); } } @@ -99,14 +94,6 @@ public class AgcPacket { return ioPort; } - public boolean t() { - return t; - } - - public boolean u() { - return u; - } - @Override public String toString() { return "AgcPacket{" + diff --git a/app/src/main/java/de/rumpold/androiddsky/network/YaAgcClient.java b/app/src/main/java/de/rumpold/androiddsky/network/YaAgcClient.java index cfe4e1b..3ffdd7b 100755 --- a/app/src/main/java/de/rumpold/androiddsky/network/YaAgcClient.java +++ b/app/src/main/java/de/rumpold/androiddsky/network/YaAgcClient.java @@ -1,6 +1,7 @@ package de.rumpold.androiddsky.network; import android.util.Log; +import android.widget.Toast; import java.io.IOException; import java.net.InetSocketAddress; @@ -13,32 +14,50 @@ import de.rumpold.androiddsky.DSKY; * Created by Adriano on 17.05.2016. */ public class YaAgcClient { - public static final int YAAGC_SERVER_PORT = 19698; - private static final String TAG = "YaAGC client"; - public static final int KEYBOARD_CHANNEL = 015; - private final DSKY dsky; + private static final String YAAGC_HOST = "192.168.178.67"; + private static final int YAAGC_SERVER_PORT = 19698; + private static final String TAG = YaAgcClient.class.getSimpleName(); + private static final int KEYBOARD_CHANNEL = 015; + + private final DSKY dsky; private SocketChannel agcChannel; private Thread handler; + /* Last state of the +/- indicators for each register */ + private boolean lastR1P = false; + private boolean lastR1N = false; + private boolean lastR2P = false; + private boolean lastR2N = false; + private boolean lastR3P = false; + private boolean lastR3N = false; + private class DSKYHandler implements Runnable { @Override public void run() { - final ByteBuffer buf = ByteBuffer.allocate(4); + final ByteBuffer buf = ByteBuffer.allocate(64); while (!Thread.interrupted()) { try { - buf.rewind(); if (!agcChannel.isConnected()) { - Thread.sleep(500); + Thread.sleep(100); continue; } - - agcChannel.read(buf); + buf.rewind(); + int numRead = agcChannel.read(buf); buf.rewind(); - handleAgcPacket(AgcPacket.parseAgcPacket(buf)); + final int subPacketCount = numRead / 4; + for (int index = 0; index < subPacketCount; ++index) { + final ByteBuffer subPacket = (ByteBuffer) buf.slice().limit(4); + handleAgcPacket(AgcPacket.parseAgcPacket(subPacket)); + + buf.position(buf.position() + 4); + } } catch (IOException | InterruptedException e) { - e.printStackTrace(); + Toast.makeText(dsky.getActivity().getApplicationContext(), + "Connection failure", + Toast.LENGTH_SHORT).show(); + Log.w(TAG, "Connection error", e); } } } @@ -50,7 +69,7 @@ public class YaAgcClient { public void connect() throws IOException { agcChannel = SocketChannel.open(); - agcChannel.connect(new InetSocketAddress("137.250.170.198", YAAGC_SERVER_PORT)); + agcChannel.connect(new InetSocketAddress(YAAGC_HOST, YAAGC_SERVER_PORT)); handler = new Thread(new DSKYHandler(), "DSKY I/O Handler"); handler.start(); @@ -68,16 +87,11 @@ public class YaAgcClient { agcChannel.close(); } - - public void sendProceed() throws IOException { - sendChannelOutput(KEYBOARD_CHANNEL, 1 << 13); - } - public void sendKeyCode(int keyCode) throws IOException { sendChannelOutput(KEYBOARD_CHANNEL, keyCode); } - protected void sendChannelOutput(int channel, int data) throws IOException { + private void sendChannelOutput(int channel, int data) throws IOException { final byte[] packet = new byte[]{ (byte) (((channel >> 3) & 0b1111) & 0xff), (byte) ((0b0100_0000 | (channel & 0b111) << 3 | ((data >> 12) & 0b111)) & 0xff), @@ -90,196 +104,216 @@ public class YaAgcClient { agcChannel.write(buffer); } - protected String extractDigit(int digitCode) { + private char extractDigit(int digitCode) { switch (digitCode) { case 0: - return " "; + return ' '; case 21: - return "0"; + return '0'; case 3: - return "1"; + return '1'; case 25: - return "2"; + return '2'; case 27: - return "3"; + return '3'; case 15: - return "4"; + return '4'; case 30: - return "5"; + return '5'; case 28: - return "6"; + return '6'; case 19: - return "7"; + return '7'; case 29: - return "8"; + return '8'; case 31: - return "9"; + return '9'; default: - throw new IllegalArgumentException("Invalid TAG digit code: " + digitCode); + throw new IllegalArgumentException("Invalid digit code: " + digitCode); } } - protected void handleAgcPacket(AgcPacket packet) { + private void handleAgcPacket(AgcPacket packet) { if (packet == null) { return; } switch (packet.getIoPort()) { - case 010: { - // TAG 7-segment displays - final int digitIdx = (packet.getDataCode() >> 11) & 0b1111; - final int data = packet.getDataCode() & 0b1_11111_11111; + case 010: + handleChannel10(packet); + break; - final int b = (data >> 10) & 0b1; - final int c = (data >> 5) & 0b11111; - final int d = data & 0b11111; + case 011: + handleChannel11(packet); + break; + } - switch (digitIdx) { - case 11: { - // PROG digits + // Update register sign indicator displays + dsky.setSignR1(lastR1P, lastR1N); + dsky.setSignR2(lastR2P, lastR2N); + dsky.setSignR3(lastR3P, lastR3N); - final String prog = extractDigit(c) + extractDigit(d); - dsky.setProg(prog); + dsky.refreshDisplay(); + } - Log.d(TAG, "[DSKY PROG] " + prog); - break; - } + /** + * Handle changes of the indicator lights, transmitted on I/O channel 11 + * + * @param packet + */ + private void handleChannel11(AgcPacket packet) { + final boolean compActy = (packet.getDataCode() & 0b0000_0010) != 0; + final boolean uplinkActy = (packet.getDataCode() & 0b0000_0100) != 0; + final boolean temp = (packet.getDataCode() & 0b0000_1000) != 0; - case 10: { - // Verb digits - final String verb = extractDigit(c) + extractDigit(d); - dsky.setVerb(verb); + dsky.setCompActy(compActy); + dsky.setUplinkActy(uplinkActy); + dsky.setTemp(temp); - Log.d(TAG, "[DSKY VERB] " + verb); - break; - } + Log.d(TAG, String.format("[DSKY indicators] compActy = %s, uplinkActy = %s, temp = %s", + compActy, uplinkActy, temp)); + } - case 9: { - // Noun digits - final String noun = extractDigit(c) + extractDigit(d); - dsky.setNoun(noun); + /** + * Handle changes of display segments, transmitted on I/O channel 10 + * + * @param packet + */ + private void handleChannel10(AgcPacket packet) { + final int digitIdx = (packet.getDataCode() >> 11) & 0b1111; + final int data = packet.getDataCode() & 0b1_11111_11111; - Log.d(TAG, "[DSKY NOUN] " + noun); - break; - } + final int b = (data >> 10) & 0b1; + final int c = (data >> 5) & 0b11111; + final int d = data & 0b11111; - case 8: { - // First digit of R1 - dsky.setRegister1(0, extractDigit(d)); - break; - } + switch (digitIdx) { + case 11: { + // PROG digits + final String prog = "" + extractDigit(c) + extractDigit(d); + dsky.setProg(prog); - case 7: { - // 2nd & 3rd digit of R1, + sign R1 - dsky.setRegister1(1, extractDigit(c)); - dsky.setRegister1(2, extractDigit(d)); - dsky.setSignR1(b > 0 ? '+' : ' '); - break; - } + Log.d(TAG, "[DSKY PROG] " + prog); + break; + } - case 6: { - // 4th & 5th digit of R1, - sign R1 - dsky.setRegister1(3, extractDigit(c)); - dsky.setRegister1(4, extractDigit(d)); - dsky.setSignR1(b > 0 ? '-' : ' '); - break; - } + case 10: { + // Verb digits + final String verb = "" + extractDigit(c) + extractDigit(d); + dsky.setVerb(verb); - case 5: { - // 1st & 2nd digit of R2, + sign R2 - dsky.setRegister2(0, extractDigit(c)); - dsky.setRegister2(1, extractDigit(d)); - dsky.setSignR2(b > 0 ? '+' : ' '); - break; - } + Log.d(TAG, "[DSKY VERB] " + verb); + break; + } - case 4: { - // 3rd & 4th digit of R2, - sign R2 - dsky.setRegister2(2, extractDigit(c)); - dsky.setRegister2(3, extractDigit(d)); - dsky.setSignR2(b > 0 ? '-' : ' '); - break; - } + case 9: { + // Noun digits + final String noun = "" + extractDigit(c) + extractDigit(d); + dsky.setNoun(noun); - case 3: { - // 5th digit of R2, 1st digit of R3 - dsky.setRegister2(4, extractDigit(c)); - dsky.setRegister3(0, extractDigit(d)); - break; - } + Log.d(TAG, "[DSKY NOUN] " + noun); + break; + } - case 2: { - // 2nd & 3rd digit of R3, + sign R3 - dsky.setRegister3(1, extractDigit(c)); - dsky.setRegister3(2, extractDigit(d)); - dsky.setSignR3(b > 0 ? '+' : ' '); - break; - } + case 8: { + // First digit of R1 + dsky.setRegister1(0, extractDigit(d)); + break; + } - case 1: { - // 4th & 5th digit of R3, - sign R3 - dsky.setRegister3(3, extractDigit(c)); - dsky.setRegister3(4, extractDigit(d)); - dsky.setSignR3(b > 0 ? '-' : ' '); - break; - } - - case 12: { - // Indicators - final boolean vel = (data & 0b0_00000_00100) > 0; - final boolean noAtt = (data & 0b0_00000_01000) > 0; - final boolean alt = (data & 0b0_00000_10000) > 0; - final boolean gimbalLock = (data & 0b0_00001_00000) > 0; - final boolean tracker = (data & 0b0_00100_00000) > 0; - final boolean prog = (data & 0b0_01000_00000) > 0; - - dsky.setVel(vel); - dsky.setNoAtt(noAtt); - dsky.setAlt(alt); - dsky.setGimbalLock(gimbalLock); - dsky.setTracker(tracker); - dsky.setProgError(prog); - - Log.d(TAG, String.format("[DSKY indicators] vel = %s, noAtt = %s, alt = %s, gimbalLock = %s, tracker = %s, prog = %s", - vel, noAtt, alt, gimbalLock, tracker, prog)); - break; - } - - default: + case 7: { + // 2nd & 3rd digit of R1, + sign R1 + dsky.setRegister1(1, extractDigit(c)); + dsky.setRegister1(2, extractDigit(d)); + lastR1P = b > 0; + if (lastR1P) { + lastR1N = false; } - break; } - case 011: { - // TAG indicator lights - final boolean compActy = (packet.getDataCode() & 0b0000_0010) != 0; - final boolean uplinkActy = (packet.getDataCode() & 0b0000_0100) != 0; - final boolean temp = (packet.getDataCode() & 0b0000_1000) != 0; - - dsky.setCompActy(compActy); - dsky.setUplinkActy(uplinkActy); - dsky.setTemp(temp); - - Log.d(TAG, String.format("[DSKY indicators] compActy = %s, uplinkActy = %s, temp = %s", - compActy, uplinkActy, temp)); - + case 6: { + // 4th & 5th digit of R1, - sign R1 + dsky.setRegister1(3, extractDigit(c)); + dsky.setRegister1(4, extractDigit(d)); + lastR1N = b > 0; + if (lastR1N) { + lastR1P = false; + } break; } - default: + case 5: { + // 1st & 2nd digit of R2, + sign R2 + dsky.setRegister2(0, extractDigit(c)); + dsky.setRegister2(1, extractDigit(d)); + lastR2P = b > 0; + break; + } + + case 4: { + // 3rd & 4th digit of R2, - sign R2 + dsky.setRegister2(2, extractDigit(c)); + dsky.setRegister2(3, extractDigit(d)); + lastR2N = b > 0; + break; + } + + case 3: { + // 5th digit of R2, 1st digit of R3 + dsky.setRegister2(4, extractDigit(c)); + dsky.setRegister3(0, extractDigit(d)); + break; + } + + case 2: { + // 2nd & 3rd digit of R3, + sign R3 + dsky.setRegister3(1, extractDigit(c)); + dsky.setRegister3(2, extractDigit(d)); + lastR3P = b > 0; + break; + } + + case 1: { + // 4th & 5th digit of R3, - sign R3 + dsky.setRegister3(3, extractDigit(c)); + dsky.setRegister3(4, extractDigit(d)); + lastR3N = b > 0; + break; + } + + case 12: { + // Indicators + final boolean vel = (data & 0b0_00000_00100) > 0; + final boolean noAtt = (data & 0b0_00000_01000) > 0; + final boolean alt = (data & 0b0_00000_10000) > 0; + final boolean gimbalLock = (data & 0b0_00001_00000) > 0; + final boolean tracker = (data & 0b0_00100_00000) > 0; + final boolean prog = (data & 0b0_01000_00000) > 0; + + dsky.setVel(vel); + dsky.setNoAtt(noAtt); + dsky.setAlt(alt); + dsky.setGimbalLock(gimbalLock); + dsky.setTracker(tracker); + dsky.setProgError(prog); + + Log.d(TAG, String.format("[DSKY indicators] vel = %s, noAtt = %s, alt = %s, gimbalLock = %s, tracker = %s, prog = %s", + vel, noAtt, alt, gimbalLock, tracker, prog)); + break; + } } } } \ No newline at end of file diff --git a/app/src/main/java/de/rumpold/androiddsky/ui/DSKYActivity.java b/app/src/main/java/de/rumpold/androiddsky/ui/DSKYActivity.java index adcb3a8..11118ad 100755 --- a/app/src/main/java/de/rumpold/androiddsky/ui/DSKYActivity.java +++ b/app/src/main/java/de/rumpold/androiddsky/ui/DSKYActivity.java @@ -1,13 +1,10 @@ package de.rumpold.androiddsky.ui; -import android.annotation.SuppressLint; -import android.graphics.Color; import android.os.Bundle; import android.os.Handler; import android.support.annotation.IdRes; -import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; -import android.view.MotionEvent; +import android.view.HapticFeedbackConstants; import android.view.View; import android.widget.Button; import android.widget.TextView; @@ -20,91 +17,45 @@ import de.rumpold.androiddsky.R; * status bar and navigation/system bar) with user interaction. */ public class DSKYActivity extends AppCompatActivity { - /** - * Whether or not the system UI should be auto-hidden after - * {@link #AUTO_HIDE_DELAY_MILLIS} milliseconds. - */ - private static final boolean AUTO_HIDE = true; - - /** - * If {@link #AUTO_HIDE} is set, the number of milliseconds to wait after - * user interaction before hiding the system UI. - */ - private static final int AUTO_HIDE_DELAY_MILLIS = 3000; - /** * Some older devices needs a small delay between UI widget updates * and a change of the status and navigation bar. */ private static final int UI_ANIMATION_DELAY = 300; - private final Handler mHideHandler = new Handler(); - - private View mContentView; - private final Runnable mHidePart2Runnable = new Runnable() { - @SuppressLint("InlinedApi") - @Override - public void run() { - // Delayed removal of status and navigation bar - - // Note that some of these constants are new as of API 16 (Jelly Bean) - // and API 19 (KitKat). It is safe to use them, as they are inlined - // at compile-time and do nothing on earlier devices. - mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE - | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); - } - }; - private View mControlsView; - private final Runnable mShowPart2Runnable = new Runnable() { - @Override - public void run() { - // Delayed display of UI elements - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.show(); - } - mControlsView.setVisibility(View.VISIBLE); - } - }; - private boolean mVisible; - private final Runnable mHideRunnable = new Runnable() { - @Override - public void run() { - hide(); - } - }; + private final Handler mViewHandler = new Handler(); private final DSKY dsky = new DSKY(this); + private int rightActiveColor; + private int activeColor; + private int passiveColor; public void updateIndicator(@IdRes final int id, final boolean state) { - mHideHandler.post(new Runnable() { + mViewHandler.post(new Runnable() { @Override public void run() { TextView indicator = (TextView) findViewById(id); - if (indicator != null) { - if (state) { - final int color; - if ("right".equals(indicator.getTag())) { - color = getResources().getColor(R.color.indicatorRightActive); - } else { - color = getResources().getColor(R.color.indicatorActive); - } + if (indicator == null) { + return; + } - indicator.setBackgroundColor(color); + if (state) { + final int color; + if ("right".equals(indicator.getTag())) { + color = rightActiveColor; } else { - indicator.setBackgroundColor(getResources().getColor(R.color.indicatorPassive)); + color = activeColor; } + indicator.setBackgroundColor(color); + } else { + indicator.setBackgroundColor(passiveColor); } } }); } public void updateDisplay(@IdRes final int id, final String value) { - mHideHandler.post(new Runnable() { + mViewHandler.post(new Runnable() { @Override public void run() { TextView display = (TextView) findViewById(id); @@ -113,48 +64,27 @@ public class DSKYActivity extends AppCompatActivity { }); } - /** - * Touch listener to use for in-layout UI controls to delay hiding the - * system UI. This is to prevent the jarring behavior of controls going away - * while interacting with activity UI. - */ - private final View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() { - @Override - public boolean onTouch(View view, MotionEvent motionEvent) { - if (AUTO_HIDE) { - delayedHide(AUTO_HIDE_DELAY_MILLIS); - } - return false; - } - }; - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dsky); - mVisible = true; - mControlsView = findViewById(R.id.controlBar); - mContentView = findViewById(R.id.contentView); + // Colors + rightActiveColor = getResources().getColor(R.color.indicatorRightActive); + activeColor = getResources().getColor(R.color.indicatorActive); + passiveColor = getResources().getColor(R.color.indicatorPassive); + createButtonListeners(); + } - // Set up the user interaction to manually show or hide the system UI. - mContentView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - toggle(); - } - }); - - // Upon interacting with UI controls, delay any scheduled hide() - // operations to prevent the jarring behavior of controls going away - // while interacting with the UI. - - View.OnClickListener buttonListener = new View.OnClickListener() { + private void createButtonListeners() { + final View.OnClickListener buttonListener = new View.OnClickListener() { @Override public void onClick(View view) { final Button button = (Button) view; + button.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, + HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); dsky.buttonPressed(button.getText().toString()); } }; @@ -183,12 +113,6 @@ public class DSKYActivity extends AppCompatActivity { @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); - - // Trigger the initial hide() shortly after the activity has been - // created, to briefly hint to the user that UI controls - // are available. - delayedHide(100); - dsky.connect(); } @@ -197,47 +121,4 @@ public class DSKYActivity extends AppCompatActivity { super.onDestroy(); dsky.disconnect(); } - - private void toggle() { - if (mVisible) { - hide(); - } else { - show(); - } - } - - private void hide() { - // Hide UI first - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.hide(); - } - mControlsView.setVisibility(View.GONE); - mVisible = false; - - // Schedule a runnable to remove the status and navigation bar after a delay - mHideHandler.removeCallbacks(mShowPart2Runnable); - mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY); - } - - @SuppressLint("InlinedApi") - private void show() { - // Show the system bar - mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); - mVisible = true; - - // Schedule a runnable to display UI elements after a delay - mHideHandler.removeCallbacks(mHidePart2Runnable); - mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY); - } - - /** - * Schedules a call to hide() in [delay] milliseconds, canceling any - * previously scheduled calls. - */ - private void delayedHide(int delayMillis) { - mHideHandler.removeCallbacks(mHideRunnable); - mHideHandler.postDelayed(mHideRunnable, delayMillis); - } } diff --git a/app/src/main/java/de/rumpold/androiddsky/util/BufferUtils.java b/app/src/main/java/de/rumpold/androiddsky/util/BufferUtils.java new file mode 100644 index 0000000..ecc0db1 --- /dev/null +++ b/app/src/main/java/de/rumpold/androiddsky/util/BufferUtils.java @@ -0,0 +1,31 @@ +package de.rumpold.androiddsky.util; + +import android.util.Log; + +import org.apache.commons.lang3.StringUtils; + +import java.nio.ByteBuffer; + +/** + * Created by Adriano on 11.06.2017. + */ + +public class BufferUtils { + private static void printBuffer(String tag, ByteBuffer buf) { + buf.rewind(); + int index = 0; + while (buf.remaining() > 0) { + ++index; + final int b = (int) buf.get(); + if (b == 0) { + continue; + } + + final String bitString = StringUtils.leftPad(Integer.toBinaryString(b), 32, '0').substring(24); + Log.d(tag, "printBuffer: " + index + ": " + bitString); + } + Log.d(tag, "--------------------------------------------------"); + + buf.rewind(); + } +} diff --git a/app/src/main/res/layout/activity_dsky.xml b/app/src/main/res/layout/activity_dsky.xml index 574b328..5770f68 100755 --- a/app/src/main/res/layout/activity_dsky.xml +++ b/app/src/main/res/layout/activity_dsky.xml @@ -1,47 +1,26 @@ - + - + - - - - - - - - - - - - + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal|bottom" /> + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_7seg.xml b/app/src/main/res/layout/layout_7seg.xml index 6522e77..e3ce686 100755 --- a/app/src/main/res/layout/layout_7seg.xml +++ b/app/src/main/res/layout/layout_7seg.xml @@ -1,15 +1,10 @@ - + + style="@style/number_label" + android:text="PROG" /> + style="@style/number_display" + android:text="00" /> - - + - + + style="@style/number_label" + android:text="VERB" /> + style="@style/number_display" + android:text="00" /> - + + style="@style/number_label" + android:text="NOUN" /> + style="@style/number_display" + android:text="00" /> - - + + android:layout_gravity="center" + android:layout_span="2"> + style="@style/number_display" + android:text="+" /> + style="@style/number_display" + android:text="00000" /> - + + style="@style/number_display" + android:text="+" /> - + style="@style/number_display" + android:text="00000" /> - - + + android:layout_gravity="center" + android:layout_span="2"> + style="@style/number_display" + android:text="+" /> + style="@style/number_display" + android:text="00000" /> - \ No newline at end of file diff --git a/app/src/main/res/layout/layout_keyboard.xml b/app/src/main/res/layout/layout_keyboard.xml index 0be5b1e..0e51afa 100755 --- a/app/src/main/res/layout/layout_keyboard.xml +++ b/app/src/main/res/layout/layout_keyboard.xml @@ -1,189 +1,153 @@ + android:gravity="center" + android:orientation="horizontal"> + android:gravity="center_vertical" + android:orientation="vertical">