Last active
December 17, 2015 04:49
-
-
Save oyyq99999/5553436 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package reader; | |
import java.io.File; | |
import java.io.FileNotFoundException; | |
import java.io.FileOutputStream; | |
import java.io.PrintStream; | |
import gui.StackmatReaderGui; | |
import javax.sound.sampled.AudioFormat; | |
import javax.sound.sampled.AudioSystem; | |
import javax.sound.sampled.DataLine; | |
import javax.sound.sampled.LineUnavailableException; | |
import javax.sound.sampled.TargetDataLine; | |
public class StackmatReader implements Runnable { | |
private boolean invertedSignal; // whether to invert the signal | |
@SuppressWarnings("unused") | |
private boolean pro; // whether 3rd gen stackmat; | |
private AudioFormat format; | |
private TargetDataLine line; | |
private float samplingRate; | |
private final int baudRate = 1200; // the baud rate, fixed | |
private final int frameReadSize = 200; // read 130 bits to get the timer | |
// status | |
private byte threshold; // the threshold for changing | |
private byte[] timingInfo; // the chars of the current state | |
private StackmatReaderGui gui; | |
private PrintStream logPs; | |
public StackmatReader() { | |
this(44100f, (byte) 50); | |
} | |
public StackmatReader(float samplingRate) { | |
this(samplingRate, (byte) 50); | |
} | |
public StackmatReader(float samplingRate, byte threshold) { | |
this.gui = StackmatReaderGui.getInstance(); | |
this.invertedSignal = false; | |
this.pro = false; | |
this.timingInfo = new byte[10]; | |
this.samplingRate = samplingRate; | |
this.threshold = threshold; | |
this.format = new AudioFormat(this.samplingRate, 8, 1, true, false); | |
DataLine.Info lineInfo = new DataLine.Info(TargetDataLine.class, | |
this.format); | |
try { | |
this.line = (TargetDataLine) AudioSystem.getLine(lineInfo); | |
line.open(); | |
} catch (LineUnavailableException e) { | |
e.printStackTrace(); | |
System.exit(-1); | |
} | |
line.start(); | |
try { | |
this.logPs = new PrintStream(new File("E:\\stackmat.log")); | |
} catch (FileNotFoundException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
System.exit(-1); | |
} | |
} | |
public StackmatReader(byte threshold) { | |
this(44100f, threshold); | |
} | |
/** | |
* @param args | |
*/ | |
public static void main(String[] args) { | |
StackmatReader reader = new StackmatReader(8000f, (byte) 40); | |
new Thread(reader).start(); | |
} | |
public void run() { | |
double times = this.samplingRate * 1.0 / this.baudRate; | |
int bufferSize = (int) (times * this.frameReadSize + 1); | |
byte[] buf = new byte[bufferSize]; | |
byte[] orig = new byte[bufferSize]; | |
this.gui.setVisible(true); | |
boolean detected = false; | |
int skipSize = 0; | |
int lastI = 0; | |
while (true) { | |
int read = this.line.read(orig, 0, bufferSize); | |
detected = false; | |
if (read > 0) { | |
for (int i = 0; i < read; i++) { | |
logPs.print(orig[i] + " "); | |
// System.out.print(orig[i] + " "); | |
} | |
logPs.println(); | |
logPs.flush(); | |
// System.out.println(); | |
byte lastBit = 1; | |
byte lastByte = 0; | |
for (int i = 0; i < read; i++) { | |
if (Math.abs(orig[i] - lastByte) >= this.threshold) { | |
// System.out.println(orig[i]); | |
buf[i] = lastBit = bitValue(orig[i] - lastByte); | |
} else { | |
buf[i] = lastBit; | |
} | |
lastByte = orig[i]; | |
} | |
// for (int i = 0; i < read; i++) { | |
// if (orig[i] >= this.threshold) { | |
// buf[i] = lastBit = 1; | |
// } else if (orig[i] <= -this.threshold) { | |
// buf[i] = lastBit = 0; | |
// } else { | |
// buf[i] = lastBit; | |
// } | |
// } | |
int lastStart = 0; | |
byte[] data = new byte[this.frameReadSize]; | |
int index = 0; | |
for (int i = lastStart + 1; i < read; i++) { | |
if (i == read - 1) { | |
byte value = buf[lastStart]; | |
int count = (int)Math.round((i - lastStart) / times); | |
count = Math.max(count, 1); | |
for (int j = 0; j < count && index < data.length; j++) { | |
data[index++] = value; | |
} | |
continue; | |
} | |
if (buf[i] == buf[lastStart]) { | |
continue; | |
} | |
byte value = buf[lastStart]; | |
int count = (int) Math.round((i - lastStart) / times); | |
if (count >= 10) { // idle found | |
int frameSize = bufferSize - lastI + skipSize + i; | |
skipSize = (int) (frameSize - 12 * times - (bufferSize - i)); | |
skipSize = Math.max(skipSize, 0); | |
skipSize %= bufferSize / 2; | |
detected = true; | |
lastI = i; | |
} | |
for (int j = 0; j < count && index < data.length; j++) { | |
data[index++] = value; | |
} | |
lastStart = i; | |
} | |
for (int i = 0; i < data.length; i++) { | |
logPs.print(data[i]); | |
// System.out.print(data[i]); | |
} | |
logPs.println(); | |
logPs.flush(); | |
// System.out.println(); | |
if (detected) { | |
if (this.parseTime(data, index) == false) { | |
detected = false; | |
} else { | |
logPs.println("detected!"); | |
logPs.flush(); | |
System.err.println("detected!"); | |
} | |
} | |
} | |
if (!detected) { | |
skipSize = 0; | |
lastI = 0; | |
this.gui.setTimerState(null); | |
} else { | |
System.out.println(skipSize + " " + lastI); | |
} | |
line.read(buf, 0, skipSize); | |
} | |
} | |
private byte bitValue(int i) { | |
return i > 0 ? (byte) 1 : (byte) 0; | |
} | |
private boolean parseTime(byte[] data, int length) { | |
boolean valid = false; | |
int dataStart = 0; | |
byte idleBit = 1; | |
for (int i = dataStart + 1; i < length - 85; i++) { | |
if (data[i] == data[dataStart]) { | |
continue; | |
} | |
if ((i - dataStart) >= 10) { | |
this.invertedSignal = (data[dataStart] == 0); | |
idleBit = data[dataStart]; | |
dataStart = i; | |
valid = true; | |
break; | |
} | |
dataStart = i; | |
} | |
if (!valid) { | |
logPs.println("No datastart found!"); | |
logPs.flush(); | |
System.err.println("No datastart found!"); | |
this.gui.setTimerState(null); | |
return false; | |
} | |
// we have at least 90 data bits, so we just skip them to find another | |
// idle | |
valid = false; | |
int dataEnd = dataStart + 85; | |
for (int i = dataEnd + 1; i < length; i++) { | |
if (data[i] == data[dataEnd] && i < length - 1) { | |
continue; | |
} | |
if ((i - dataEnd) >= 10) { | |
if (data[dataEnd] != idleBit) { | |
valid = false; | |
break; | |
} | |
valid = true; | |
dataEnd++; // the first one was the last bit of last byte | |
break; | |
} | |
dataEnd = i; | |
} | |
if (!valid) { | |
logPs.println("No dataend found!"); | |
logPs.flush(); | |
System.err.println("No dataend found!"); | |
this.gui.setTimerState(null); | |
return false; | |
} | |
int packageSize = dataEnd - dataStart; | |
if (packageSize == 90) { | |
this.pro = false; | |
} else if (packageSize == 100) { | |
this.pro = true; | |
// not valid data length | |
} else { | |
System.err.println("Invalid packageSize: " + packageSize); | |
logPs.println("Invalid packageSize: " + packageSize); | |
logPs.flush(); | |
this.gui.setTimerState(null); | |
return false; | |
} | |
valid = true; | |
for (int i = 0; i < packageSize; i += 10) { | |
if (data[dataStart + i] == idleBit | |
|| data[dataStart + i + 9] != idleBit) { | |
System.err.println("Invalid data!"); | |
this.gui.setTimerState(null); | |
return false; | |
} | |
} | |
for (int i = 0; i < packageSize / 10; i++) { | |
this.timingInfo[i] = 0; | |
for (int j = 8; j >= 1; j--) { | |
if (this.invertedSignal) { | |
this.timingInfo[i] |= (1 - data[dataStart + i * 10 + j]) << (j - 1); | |
} else { | |
this.timingInfo[i] |= data[dataStart + i * 10 + j] << (j - 1); | |
} | |
} | |
} | |
this.gui.setTimerState(this.timingInfo); | |
return true; | |
} | |
public byte[] getTimingInfo() { | |
return this.timingInfo; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment