Working connect/disconnect, OPR ERR and KEY REL flashing, code cleanup with Butterknife

This commit is contained in:
Adrian Rumpold
2017-12-25 12:40:11 +01:00
parent 83f2073901
commit 4d5977032e
4 changed files with 184 additions and 102 deletions

View File

@@ -11,6 +11,11 @@ import java.net.SocketAddress;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import de.rumpold.androiddsky.network.YaAgcClient; import de.rumpold.androiddsky.network.YaAgcClient;
import de.rumpold.androiddsky.ui.DSKYActivity; import de.rumpold.androiddsky.ui.DSKYActivity;
@@ -19,9 +24,18 @@ import de.rumpold.androiddsky.ui.DSKYActivity;
* Created by Adriano on 17.05.2016. * Created by Adriano on 17.05.2016.
*/ */
public class DSKY { public class DSKY {
private static final String TAG = "TAG"; public interface ConnectionListener {
void onConnect();
void onDisconnect();
}
private static final String TAG = "DSKY";
private final Lock connectLock = new ReentrantLock();
private final DSKYActivity activity; private final DSKYActivity activity;
private ConnectionListener listener;
private final YaAgcClient client; private final YaAgcClient client;
private String prog; private String prog;
@@ -36,19 +50,19 @@ public class DSKY {
private char[] register2 = new char[5]; private char[] register2 = new char[5];
private char[] register3 = new char[5]; private char[] register3 = new char[5];
private boolean compActy; private volatile boolean compActy;
private boolean uplinkActy; private volatile boolean uplinkActy;
private boolean noAtt; private volatile boolean noAtt;
private boolean gimbalLock; private volatile boolean gimbalLock;
private boolean tracker; private volatile boolean tracker;
private boolean temp; private volatile boolean temp;
private boolean vel; private volatile boolean vel;
private boolean alt; private volatile boolean alt;
private boolean progError; private volatile boolean progError;
private boolean keyRel; private volatile boolean keyRel;
private boolean oprErr; private volatile boolean oprErr;
private boolean stby; private volatile boolean stby;
private boolean restart; private volatile boolean restart;
private final Map<String, Integer> keycodeMap = new HashMap<>(); private final Map<String, Integer> keycodeMap = new HashMap<>();
@@ -74,20 +88,10 @@ public class DSKY {
keycodeMap.put("PRO", 1 << 13); keycodeMap.put("PRO", 1 << 13);
} }
public DSKY(DSKYActivity activity) { public DSKY(DSKYActivity activity, ConnectionListener listener) {
this.activity = activity; this.activity = activity;
this.listener = listener;
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity.getApplicationContext()); this.client = new YaAgcClient(this);
final String agcHost = preferences.getString("agc_host", null);
final int agcPort = Integer.parseInt(preferences.getString("agc_port", "-1"));
if (agcHost == null || agcPort <= 0) {
this.client = null;
return;
} else {
final SocketAddress agcAddress = new InetSocketAddress(agcHost, agcPort);
this.client = new YaAgcClient(this, agcAddress);
}
Arrays.fill(register1, ' '); Arrays.fill(register1, ' ');
Arrays.fill(register2, ' '); Arrays.fill(register2, ' ');
@@ -103,14 +107,53 @@ public class DSKY {
@Override @Override
public void run() { public void run() {
try { try {
if (client != null) { Log.d(TAG, "Acquiring connect lock... ");
client.connect(); connectLock.lock();
Log.d(TAG, "Done.");
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity.getApplicationContext());
final String agcHost = preferences.getString("agc_host", null);
final int agcPort = Integer.parseInt(preferences.getString("agc_port", "-1"));
final SocketAddress agcAddress = new InetSocketAddress(agcHost, agcPort);
final boolean success = client.connect(agcAddress);
if (success) {
Log.i(TAG, "Successfully connected");
listener.onConnect();
} else {
Log.w(TAG, "Connection failed");
} }
} catch (IOException e) { } catch (IOException e) {
// throw new RuntimeException("Cannot connect to yaAGC", e); // throw new RuntimeException("Cannot connect to yaAGC", e);
} finally {
connectLock.unlock();
} }
} }
}); });
new Timer().schedule(new TimerTask() {
private final AtomicBoolean _keyRel = new AtomicBoolean(false);
private final AtomicBoolean _oprErr = new AtomicBoolean(false);
@Override
public void run() {
Log.v("BLINK", String.format("keyRel=%b/%b, oprErr=%b/%b",
keyRel, _keyRel.get(), oprErr, _oprErr.get()));
handle(R.id.lbl_keyRel, _keyRel, keyRel);
handle(R.id.lbl_oprErr, _oprErr, oprErr);
}
private void handle(int indicator, AtomicBoolean internalState, boolean state) {
if (state) {
internalState.set(!internalState.get());
activity.updateIndicator(indicator, internalState.get());
} else {
internalState.set(false);
activity.updateIndicator(indicator, false);
}
}
}, 667, 667);
} }
public void refreshDisplay() { public void refreshDisplay() {
@@ -119,9 +162,9 @@ public class DSKY {
activity.updateIndicator(R.id.lbl_uplinkActy, uplinkActy); activity.updateIndicator(R.id.lbl_uplinkActy, uplinkActy);
activity.updateIndicator(R.id.lbl_prog, progError); activity.updateIndicator(R.id.lbl_prog, progError);
activity.updateIndicator(R.id.lbl_tracker, tracker); activity.updateIndicator(R.id.lbl_tracker, tracker);
activity.updateIndicator(R.id.lbl_oprErr, oprErr); // activity.updateIndicator(R.id.lbl_oprErr, oprErr);
activity.updateIndicator(R.id.lbl_stby, stby); activity.updateIndicator(R.id.lbl_stby, stby);
activity.updateIndicator(R.id.lbl_keyRel, keyRel); // activity.updateIndicator(R.id.lbl_keyRel, keyRel);
activity.updateIndicator(R.id.lbl_restart, restart); activity.updateIndicator(R.id.lbl_restart, restart);
activity.updateIndicator(R.id.lbl_compActy, compActy); activity.updateIndicator(R.id.lbl_compActy, compActy);
@@ -155,7 +198,9 @@ public class DSKY {
client.disconnect(); client.disconnect();
} }
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Cannot connect to yaAGC", e); throw new RuntimeException("Cannot disconnect from yaAGC", e);
} finally {
listener.onDisconnect();
} }
} }
}); });

View File

@@ -8,7 +8,7 @@ import android.widget.Toast;
import java.io.IOException; import java.io.IOException;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.ClosedByInterruptException; import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import de.rumpold.androiddsky.DSKY; import de.rumpold.androiddsky.DSKY;
@@ -23,7 +23,6 @@ public class YaAgcClient {
private static final int KEYBOARD_CHANNEL = 015; private static final int KEYBOARD_CHANNEL = 015;
private final DSKY dsky; private final DSKY dsky;
private final SocketAddress agcAddress;
private SocketChannel agcChannel; private SocketChannel agcChannel;
private Thread handler; private Thread handler;
@@ -56,7 +55,7 @@ public class YaAgcClient {
buf.position(buf.position() + 4); buf.position(buf.position() + 4);
} }
} catch (ClosedByInterruptException | InterruptedException ignored) { } catch (AsynchronousCloseException | InterruptedException ignored) {
} catch (IOException e) { } catch (IOException e) {
Log.w(TAG, "Connection error", e); Log.w(TAG, "Connection error", e);
new Handler(Looper.getMainLooper()).post(new Runnable() { new Handler(Looper.getMainLooper()).post(new Runnable() {
@@ -72,12 +71,11 @@ public class YaAgcClient {
} }
} }
public YaAgcClient(DSKY dsky, SocketAddress agcAddress) { public YaAgcClient(DSKY dsky) {
this.dsky = dsky; this.dsky = dsky;
this.agcAddress = agcAddress;
} }
public void connect() throws IOException { public boolean connect(SocketAddress agcAddress) throws IOException {
Log.i(TAG, "Connecting to yaAGC at " + agcAddress); Log.i(TAG, "Connecting to yaAGC at " + agcAddress);
agcChannel = SocketChannel.open(); agcChannel = SocketChannel.open();
boolean success = agcChannel.connect(agcAddress); boolean success = agcChannel.connect(agcAddress);
@@ -87,6 +85,8 @@ public class YaAgcClient {
handler = new Thread(new DSKYHandler(), "DSKY I/O Handler"); handler = new Thread(new DSKYHandler(), "DSKY I/O Handler");
handler.start(); handler.start();
} }
return success;
} }
public void disconnect() throws IOException { public void disconnect() throws IOException {
@@ -103,7 +103,7 @@ public class YaAgcClient {
} }
public boolean isConnected() { public boolean isConnected() {
return agcChannel.isConnected(); return agcChannel != null && agcChannel.isConnected();
} }
public void sendKeyCode(int keyCode) throws IOException { public void sendKeyCode(int keyCode) throws IOException {
@@ -178,6 +178,10 @@ public class YaAgcClient {
handleChannel11(packet); handleChannel11(packet);
break; break;
case 013:
handleChannel13(packet);
break;
default: default:
return; return;
} }
@@ -190,6 +194,18 @@ public class YaAgcClient {
dsky.refreshDisplay(); dsky.refreshDisplay();
} }
/**
* Handle changes of additional indicators, transmitted on I/O channel 13
*
* @param packet
*/
private void handleChannel13(AgcPacket packet) {
final boolean stby = (packet.getDataCode() & 0b0100_0000_0000) != 0;
dsky.setStby(stby);
Log.d(TAG, String.format("[DSKY indicators] stby = %b", stby));
}
/** /**
* Handle changes of the indicator lights, transmitted on I/O channel 11 * Handle changes of the indicator lights, transmitted on I/O channel 11
* *
@@ -199,13 +215,17 @@ public class YaAgcClient {
final boolean compActy = (packet.getDataCode() & 0b0000_0010) != 0; final boolean compActy = (packet.getDataCode() & 0b0000_0010) != 0;
final boolean uplinkActy = (packet.getDataCode() & 0b0000_0100) != 0; final boolean uplinkActy = (packet.getDataCode() & 0b0000_0100) != 0;
final boolean temp = (packet.getDataCode() & 0b0000_1000) != 0; final boolean temp = (packet.getDataCode() & 0b0000_1000) != 0;
final boolean keyRel = (packet.getDataCode() & 0b0001_0000) != 0;
final boolean oprErr = (packet.getDataCode() & 0b0100_0000) != 0;
dsky.setCompActy(compActy); dsky.setCompActy(compActy);
dsky.setUplinkActy(uplinkActy); dsky.setUplinkActy(uplinkActy);
dsky.setTemp(temp); dsky.setTemp(temp);
dsky.setKeyRel(keyRel);
dsky.setOprErr(oprErr);
Log.d(TAG, String.format("[DSKY indicators] compActy = %s, uplinkActy = %s, temp = %s", Log.d(TAG, String.format("[DSKY indicators] compActy = %b, uplinkActy = %b, temp = %b, keyRel = %b",
compActy, uplinkActy, temp)); compActy, uplinkActy, temp, keyRel));
} }
/** /**

View File

@@ -6,13 +6,16 @@ import android.os.Handler;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.annotation.IdRes; import android.support.annotation.IdRes;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.HapticFeedbackConstants; import android.view.HapticFeedbackConstants;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
import butterknife.BindColor;
import butterknife.ButterKnife;
import butterknife.OnClick;
import de.rumpold.androiddsky.DSKY; import de.rumpold.androiddsky.DSKY;
import de.rumpold.androiddsky.R; import de.rumpold.androiddsky.R;
@@ -21,30 +24,33 @@ import de.rumpold.androiddsky.R;
* status bar and navigation/system bar) with user interaction. * status bar and navigation/system bar) with user interaction.
*/ */
public class DSKYActivity extends AppCompatActivity { public class DSKYActivity extends AppCompatActivity {
/** private static final String TAG = "DSKYActivity";
* 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 mViewHandler = new Handler(); private final Handler mViewHandler = new Handler();
private MenuItem disconnectButton;
private MenuItem connectButton;
private DSKY dsky; private DSKY dsky;
private int rightActiveColor;
private int activeColor;
private int passiveColor;
private int compActyColor;
public void updateIndicator(@IdRes final int id, final boolean state) { @BindColor(R.color.indicatorRightActive)
int rightActiveColor;
@BindColor(R.color.indicatorActive)
int activeColor;
@BindColor(R.color.indicatorPassive)
int passiveColor;
@BindColor(R.color.compActy)
int compActyColor;
public void updateIndicator(@IdRes final int id, final boolean active) {
mViewHandler.post(new Runnable() { mViewHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
TextView indicator = (TextView) findViewById(id); final TextView indicator = findViewById(id);
if (indicator == null) { if (indicator == null) {
return; return;
} }
if (state) { if (active) {
final int color; final int color;
if ("right".equals(indicator.getTag())) { if ("right".equals(indicator.getTag())) {
color = rightActiveColor; color = rightActiveColor;
@@ -65,7 +71,7 @@ public class DSKYActivity extends AppCompatActivity {
mViewHandler.post(new Runnable() { mViewHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
TextView display = (TextView) findViewById(id); final TextView display = findViewById(id);
display.setText(value); display.setText(value);
} }
}); });
@@ -74,29 +80,53 @@ public class DSKYActivity extends AppCompatActivity {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dsky); setContentView(R.layout.activity_dsky);
ButterKnife.bind(this);
dsky = new DSKY(this); dsky = new DSKY(this, new DSKY.ConnectionListener() {
@Override
public void onConnect() {
Log.i(TAG, "Connected to AGC");
mViewHandler.post(new Runnable() {
@Override
public void run() {
if (connectButton != null) {
connectButton.setVisible(false);
}
if (disconnectButton != null) {
disconnectButton.setVisible(true);
}
}
});
}
// Colors @Override
rightActiveColor = getResources().getColor(R.color.indicatorRightActive); public void onDisconnect() {
activeColor = getResources().getColor(R.color.indicatorActive); Log.i(TAG, "Disconnected from AGC");
passiveColor = getResources().getColor(R.color.indicatorPassive); mViewHandler.post(new Runnable() {
compActyColor = getResources().getColor(R.color.compActy); @Override
public void run() {
createButtonListeners(); if (connectButton != null) {
connectButton.setVisible(true);
}
if (disconnectButton != null) {
disconnectButton.setVisible(false);
}
}
});
}
});
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_connect: case R.id.action_connect:
if (!dsky.isConnected()) { dsky.connect();
dsky.connect(); return true;
} else {
dsky.disconnect(); case R.id.action_disconnect:
} dsky.disconnect();
return true; return true;
case R.id.action_settings: case R.id.action_settings:
@@ -112,39 +142,22 @@ public class DSKYActivity extends AppCompatActivity {
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.dsky_menu, menu); getMenuInflater().inflate(R.menu.dsky_menu, menu);
connectButton = menu.findItem(R.id.action_connect);
disconnectButton = menu.findItem(R.id.action_disconnect);
return super.onCreateOptionsMenu(menu); return super.onCreateOptionsMenu(menu);
} }
private void createButtonListeners() { @OnClick({R.id.btn_verb, R.id.btn_noun, R.id.btn_plus, R.id.btn_minus,
final View.OnClickListener buttonListener = new View.OnClickListener() { R.id.btn_0, R.id.btn_1, R.id.btn_2,
@Override R.id.btn_3, R.id.btn_4, R.id.btn_5,
public void onClick(View view) { R.id.btn_6, R.id.btn_7, R.id.btn_8, R.id.btn_9,
final Button button = (Button) view; R.id.btn_clr, R.id.btn_pro, R.id.btn_key_rel,
button.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, R.id.btn_entr, R.id.btn_rset})
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); public void dskyButtonCallback(Button button) {
dsky.buttonPressed(button.getText().toString()); button.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
} HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
}; dsky.buttonPressed(button.getText().toString());
findViewById(R.id.btn_verb).setOnClickListener(buttonListener);
findViewById(R.id.btn_noun).setOnClickListener(buttonListener);
findViewById(R.id.btn_plus).setOnClickListener(buttonListener);
findViewById(R.id.btn_minus).setOnClickListener(buttonListener);
findViewById(R.id.btn_0).setOnClickListener(buttonListener);
findViewById(R.id.btn_1).setOnClickListener(buttonListener);
findViewById(R.id.btn_2).setOnClickListener(buttonListener);
findViewById(R.id.btn_3).setOnClickListener(buttonListener);
findViewById(R.id.btn_4).setOnClickListener(buttonListener);
findViewById(R.id.btn_5).setOnClickListener(buttonListener);
findViewById(R.id.btn_6).setOnClickListener(buttonListener);
findViewById(R.id.btn_7).setOnClickListener(buttonListener);
findViewById(R.id.btn_8).setOnClickListener(buttonListener);
findViewById(R.id.btn_9).setOnClickListener(buttonListener);
findViewById(R.id.btn_clr).setOnClickListener(buttonListener);
findViewById(R.id.btn_pro).setOnClickListener(buttonListener);
findViewById(R.id.btn_key_rel).setOnClickListener(buttonListener);
findViewById(R.id.btn_entr).setOnClickListener(buttonListener);
findViewById(R.id.btn_rset).setOnClickListener(buttonListener);
} }
@Override @Override

View File

@@ -1,12 +1,16 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_disconnect"
android:title="Disconnect"
app:showAsAction="ifRoom" />
<item <item
android:id="@+id/action_connect" android:id="@+id/action_connect"
android:title="Connect" android:title="Connect"
app:showAsAction="ifRoom"/> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/action_settings" android:id="@+id/action_settings"
android:title="Settings" android:title="Settings"
app:showAsAction="never"/> app:showAsAction="never" />
</menu> </menu>