Skip to content

Instantly share code, notes, and snippets.

@oyyq99999
Last active December 17, 2015 04:49
Show Gist options
  • Save oyyq99999/5553436 to your computer and use it in GitHub Desktop.
Save oyyq99999/5553436 to your computer and use it in GitHub Desktop.
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