package org.schmivits.airball.airdata;
import android.util.Log;
import org.schmivits.airball.util.ValueModel;
import org.schmivits.dynonskyview.ADAHRSDataBlock;
import org.schmivits.dynonskyview.DynonSerialFormat;
import java.util.Timer;
import java.util.TimerTask;
public abstract class DynonSerialFlightData implements FlightData {
private static final long KEEP_ALIVE_DELAY = 500L; // milliseconds
private final UpdateSourceHelper mUpdateSourceHelper = new UpdateSourceHelper();
private final ValueModel<Aircraft> mAircraftModel;
private final BetaModel.Config mBetaModelConfig;
private ADAHRSDataBlock mCurrentDataBlock;
/** Current beta as a ratio of full scale, [-1.0, 1.0] */
private float mCurrentBetaRatio;
/** Current altitude in feet */
private float mCurrentAltitude;
private Timer mKeepAlive = null;
public DynonSerialFlightData(
final Aircraft aircraft,
BetaModel.Config config) {
mBetaModelConfig = config;
mAircraftModel = new ValueModel<Aircraft>() {
@Override public boolean isValid() { return true; }
@Override public Aircraft getValue() { return aircraft; }
};
updateKeepalive();
addDataBlock(null);
}
@Override public void addUpdateListener(Runnable r) {
synchronized (mUpdateSourceHelper) {
mUpdateSourceHelper.addUpdateListener(r);
}
}
@Override public void removeUpdateListener(Runnable r) {
synchronized (mUpdateSourceHelper) {
mUpdateSourceHelper.removeUpdateListener(r);
}
}
private void updateKeepalive() {
if (mKeepAlive != null) {
mKeepAlive.cancel();
mKeepAlive = null;
}
mKeepAlive = new Timer();
mKeepAlive.schedule(
new TimerTask() {
@Override public void run() {
addDataBlock(null);
}
},
KEEP_ALIVE_DELAY);
}
protected void addDataLine(String line) {
try {
addDataBlock(DynonSerialFormat.wordToData(line));
updateKeepalive();
} catch (Exception e) {
Log.v(getClass().getName(), "Error in addDataLine: " + e.toString());
// Corrupt data; drop on the floor
// If this goes on too long, our timeout will fire and invalidate UI
}
}
private void addDataBlock(ADAHRSDataBlock block) {
mCurrentDataBlock = block;
if (block == null) {
mCurrentAltitude = Float.NaN;
} else {
if (!Float.isNaN(block.displayedAltitude)) {
mCurrentAltitude = (float)
(block.displayedAltitude / Constants.METERS_PER_FOOT);
}
}
if (block == null ||
Float.isNaN(block.lateralAcceleration) ||
Float.isNaN(block.airspeed)) {
// mCurrentBetaRatio = Float.NaN;
} else {
mCurrentBetaRatio = BetaModel.computeBetaRatio(
mBetaModelConfig,
block.lateralAcceleration,
(float) (block.airspeed / Constants.METERS_PER_SECOND_PER_KNOT),
mCurrentAltitude);
}
mUpdateSourceHelper.fire();
}
private abstract class AirdataValueModel implements ValueModel<Float> {
@SuppressWarnings("unused") private final String mName;
public AirdataValueModel(String name) { mName = name; }
@Override public boolean isValid() {
return !Float.isNaN(get());
}
@Override public Float getValue() { return isValid() ? get() : 0.0f; }
private float get() { return (mCurrentDataBlock == null) ? Float.NaN : getFromBlock(); }
protected abstract float getFromBlock();
}
private final ValueModel<Float> mAirspeed = new AirdataValueModel("airspeed") {
@Override public float getFromBlock() { return mCurrentDataBlock.airspeed; }
};
private final ValueModel<Float> mAlpha = new AirdataValueModel("angleOfAttack") {
@Override public float getFromBlock() { return mCurrentDataBlock.angleOfAttack; }
};
private final ValueModel<Float> mBeta = new AirdataValueModel("beta") {
@Override public float getFromBlock() { return mCurrentBetaRatio; }
};
private final ValueModel<Float> mAltitude = new AirdataValueModel("currentAltitude") {
@Override public float getFromBlock() { return mCurrentAltitude; }
};
private final ValueModel<Float> mClimbRate = new AirdataValueModel("verticalSpeed") {
@Override public float getFromBlock() { return mCurrentDataBlock.verticalSpeed; }
};
private final Airdata mAirdata = new Airdata() {
@Override public ValueModel<Float> getAirspeed() { return mAirspeed; }
@Override public ValueModel<Float> getAlpha() { return mAlpha; }
@Override public ValueModel<Float> getBeta() { return mBeta; }
@Override public ValueModel<Float> getAltitude() { return mAltitude; }
@Override public ValueModel<Float> getClimbRate() { return mClimbRate; }
};
@Override
public ValueModel<Aircraft> getAircraft() { return mAircraftModel; }
@Override
public Airdata getAirdata() { return mAirdata; }
@Override
public String getConnectionStatus() {
return null;
}
}