package de.tu.darmstadt.seemoo.ansian.model.demodulation.morse;
import java.util.ArrayList;
import java.util.List;
import android.util.Log;
import de.greenrobot.event.EventBus;
import de.greenrobot.event.Subscribe;
import de.tu.darmstadt.seemoo.ansian.control.events.DemodulationEvent;
import de.tu.darmstadt.seemoo.ansian.control.events.FFTDataEvent;
import de.tu.darmstadt.seemoo.ansian.control.events.StateEvent;
import de.tu.darmstadt.seemoo.ansian.control.events.morse.MorseStateEvent;
import de.tu.darmstadt.seemoo.ansian.control.events.morse.RequestMorseStateEvent;
import de.tu.darmstadt.seemoo.ansian.model.FFTSample;
import de.tu.darmstadt.seemoo.ansian.model.SamplePacket;
import de.tu.darmstadt.seemoo.ansian.model.demodulation.AM;
import de.tu.darmstadt.seemoo.ansian.model.demodulation.Demodulation;
import de.tu.darmstadt.seemoo.ansian.model.preferences.MorsePreference;
import de.tu.darmstadt.seemoo.ansian.model.preferences.Preferences;
public class Morse extends Demodulation {
private String LOGTAG = "Morse";
private List<FFTSample> ffts;
private MorseStats stats;
private int initMs;
private long timestamp;
// private MorseDecodingThread thread;
private FFTSample last;
public static enum State {
CONFIG, INIT, INIT_TIMING, DECODE, STOPPED, INIT_STATS
}
public static enum Mode {
AUTOMATIC, SEMI, MANUAL
}
private static State state = State.STOPPED;
private static Mode mode;
private MorsePreference preference;
private AM am;
public Morse() {
am = new AM();
setState(State.CONFIG);
EventBus.getDefault().register(this);
MIN_USER_FILTER_WIDTH = 10000;
MAX_USER_FILTER_WIDTH = 200000;
preference = Preferences.MORSE_PREFERENCE;
init();
}
void init() {
mode = Mode.values()[preference.getMode()];
setState(State.INIT);
Log.d(LOGTAG, mode.toString());
if (mode == Mode.AUTOMATIC) {
estimateDitTime();
} else {
stats = new MorseStats(preference.getDitDuration());
setState(State.DECODE);
}
}
void estimateDitTime() {
setState(State.INIT_TIMING);
ffts = new ArrayList<FFTSample>();
initMs = preference.getInitTime();
timestamp = -1;
};
private void initializeStats() {
setState(State.INIT_STATS);
FFTSample[] samples = new FFTSample[ffts.size()];
samples = ffts.toArray(samples);
stats = new MorseStats(samples, initMs);
setState(State.DECODE);
}
private void setState(State pState) {
Log.d(LOGTAG, "" + pState);
state = pState;
EventBus.getDefault().postSticky(new MorseStateEvent(pState));
}
@Override
public DemoType getType() {
return DemoType.MORSE;
}
@Override
public void demodulate(SamplePacket input, SamplePacket output) {
if (preference.isAmDemod())
am.demodulate(input, output);
}
@Subscribe
public void onEvent(FFTDataEvent event) {
FFTSample sample = event.getSample();
if (sample != null)
switch (state) {
case CONFIG:
break;
case INIT:
break;
case INIT_TIMING:
ffts.add(sample);
// set timestamp for first fft sample to use
if (timestamp == -1)
timestamp = sample.getTimestamp();
else {
long time = (sample.getTimestamp() - timestamp);
if (time > initMs) {
initializeStats();
}
}
break;
case INIT_STATS:
break;
case DECODE:
if (mode != Mode.MANUAL && stats != null) {
stats.calcThreshold(sample);
if (preference.isAutomaticReinit())
if (!stats.checkStats())
init();
}
decode(sample);
break;
case STOPPED:
break;
default:
break;
}
}
@Subscribe
public void onEvent(DemodulationEvent event) {
if (event.getDemodulation() == DemoType.MORSE)
init();
else
setState(State.STOPPED);
}
@Subscribe
public void onStateEvent(RequestMorseStateEvent event) {
switch (event.getState()) {
case INIT:
init();
break;
default:
break;
}
}
@Subscribe
public void onStateEvent(StateEvent event) {
if (event.getState() == de.tu.darmstadt.seemoo.ansian.control.StateHandler.State.STOPPED)
setState(State.STOPPED);
}
private void decode(FFTSample sample) {
sample.setMorseBit(stats.estimateValue(sample));
if (last == null) {
last = sample;
} else {
boolean lastBit = last.getMorseBit();
boolean currentBit = sample.getMorseBit();
// signal changed
if (lastBit != currentBit) {
long time = sample.getTimestamp() - last.getTimestamp();
// ascending edge -> was high
boolean high = lastBit == true;
if (stats.decode(high, time))
last = sample;
}
}
}
public static State getState() {
return state;
}
public static Mode getMode() {
return mode;
}
}