Demodulator bug fixing

legacy
sh123 2022-08-01 22:22:00 +03:00
rodzic b96ff124ae
commit 2b0f1609b1
5 zmienionych plików z 180 dodań i 2 usunięć

Wyświetl plik

@ -2,30 +2,47 @@ package com.radio.codec2talkie.protocol;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Debug;
import android.util.Log;
import com.radio.codec2talkie.protocol.message.TextMessage;
import com.radio.codec2talkie.protocol.position.Position;
import com.radio.codec2talkie.settings.PreferenceKeys;
import com.radio.codec2talkie.tools.BitTools;
import com.radio.codec2talkie.tools.ChecksumTools;
import com.radio.codec2talkie.tools.DebugTools;
import com.radio.codec2talkie.transport.SoundModem;
import com.radio.codec2talkie.transport.Transport;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
public class Hdlc implements Protocol {
private static final String TAG = Hdlc.class.getSimpleName();
private static final int RX_BUFFER_SIZE = 8192;
protected Transport _transport;
private ProtocolCallback _parentProtocolCallback;
protected final byte[] _rxDataBuffer;
protected final ByteBuffer _currentFrameBuffer;
private final int _prefixSymCount;
private int _readByte = 0;
private int _prevHdlc = 0;
public Hdlc(SharedPreferences sharedPreferences) {
double preambleLenSec = Integer.parseInt(sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_PREAMBLE, "200")) / 1000.0;
String modemType = sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_TYPE, "1200");
// FIXME if more modulation schemes
int modemSpeed = modemType.equals("300") ? 300 : 1200;
_prefixSymCount = (int) (preambleLenSec * modemSpeed / 8);
_rxDataBuffer = new byte[RX_BUFFER_SIZE];
_currentFrameBuffer = ByteBuffer.allocate(RX_BUFFER_SIZE);
}
@Override
@ -61,6 +78,38 @@ public class Hdlc implements Protocol {
@Override
public boolean receive() throws IOException {
int bitsRead = _transport.read(_rxDataBuffer);
if (bitsRead > 0) {
byte[] data = Arrays.copyOf(_rxDataBuffer, bitsRead);
for (byte bit : data) {
_readByte <<= 1;
_readByte |= bit;
_readByte &= 0xff;
if (_readByte == 0x7e) {
Log.i(TAG, "HDLC " + _prevHdlc/8);
int pos = _currentFrameBuffer.position();
if (pos >= 7) {
_currentFrameBuffer.position(_currentFrameBuffer.position() - 7);
} else {
_currentFrameBuffer.position(0);
}
_currentFrameBuffer.flip();
byte[] packetBits = new byte[_currentFrameBuffer.remaining()];
_currentFrameBuffer.get(packetBits);
byte[] packetBytes = BitTools.convertFromHDLCBitArray(packetBits);
if (packetBytes != null) {
Log.i(TAG, DebugTools.byteBitsToString(packetBits));
Log.i(TAG, DebugTools.bytesToHex(packetBytes));
}
_currentFrameBuffer.clear();
_readByte = 0;
_prevHdlc = 0;
} else {
_currentFrameBuffer.put(bit);
_prevHdlc++;
}
}
}
return false;
}

Wyświetl plik

@ -1,5 +1,7 @@
package com.radio.codec2talkie.tools;
import android.util.Log;
import java.nio.ByteBuffer;
public class BitTools {
@ -19,6 +21,25 @@ public class BitTools {
return r;
}
public static byte[] convertFromNRZI(byte[] bitsAsBytes, byte prevLastBit) {
ByteBuffer buffer = ByteBuffer.allocate(bitsAsBytes.length);
byte last = prevLastBit;
for (byte bitAsByte : bitsAsBytes) {
// no transition -> 1
if (last == bitAsByte) {
buffer.put((byte) 1);
// transition -> 0
} else {
buffer.put((byte) 0);
}
last = bitAsByte;
}
buffer.flip();
byte[] r = new byte[buffer.remaining()];
buffer.get(r);
return r;
}
public static byte[] convertToHDLCBitArray(byte[] data, boolean shouldBitStuff) {
ByteBuffer bitBuffer = ByteBuffer.allocate(2 * data.length * 8);
@ -40,9 +61,57 @@ public class BitTools {
cntOnes = 0;
}
}
// return
bitBuffer.flip();
byte[] r = new byte[bitBuffer.remaining()];
bitBuffer.get(r);
return r;
}
public static byte[] convertFromHDLCBitArray(byte[] dataBitsAsBytes) {
ByteBuffer byteBuffer = ByteBuffer.allocate(dataBitsAsBytes.length / 8);
int currentByte = 0;
int cntOnes = 0;
int bitStuffCnt = 5;
boolean skipNext = false;
StringBuffer s = new StringBuffer();
int cntBits = 0;
for (int i = 0; i < dataBitsAsBytes.length; i++) {
byte currentBit = dataBitsAsBytes[i];
if (skipNext) {
// cannot have 6 consecutive 1, non-HDLC data
if (currentBit == 1) return null;
s.append(String.format("[%d]", currentBit));
skipNext = false;
continue;
}
currentByte >>= 1;
s.append(String.format("%d", currentBit));
if (currentBit == 1) {
currentByte |= (1 << 7);
cntOnes++;
} else {
cntOnes = 0;
}
if (i % 8 == 7) {
s.append(' ');
byteBuffer.put((byte)(currentByte & 0xff));
currentByte = 0;
}
// 5 ones, skip next
if (cntOnes == bitStuffCnt) {
skipNext = true;
cntOnes = 0;
}
cntBits++;
}
//if (cntBits % 8 != 0) return null;
Log.i("----", s.toString());
// return
byteBuffer.flip();
byte[] r = new byte[byteBuffer.remaining()];
byteBuffer.get(r);
return r;
}
}

Wyświetl plik

@ -7,6 +7,7 @@ import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Debug;
import android.util.Log;
import androidx.preference.PreferenceManager;
@ -17,9 +18,11 @@ import com.radio.codec2talkie.tools.DebugTools;
import com.ustadmobile.codec2.Codec2;
import java.io.IOException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.util.Arrays;
public class SoundModem implements Transport {
public class SoundModem implements Transport, Runnable {
private static final String TAG = SoundModem.class.getSimpleName();
@ -36,10 +39,13 @@ public class SoundModem implements Transport {
private final short[] _playbackAudioBuffer;
private final byte[] _playbackBitBuffer;
private final int _samplesPerSymbol;
private final ByteBuffer _bitBuffer;
private final Context _context;
private final SharedPreferences _sharedPreferences;
private boolean _isRunning = true;
private final long _fskModem;
public SoundModem(Context context) {
@ -59,8 +65,11 @@ public class SoundModem implements Transport {
_playbackAudioBuffer = new short[Codec2.fskModSamplesBufSize(_fskModem)];
_playbackBitBuffer = new byte[Codec2.fskModBitsBufSize(_fskModem)];
_samplesPerSymbol = Codec2.fskSamplesPerSymbol(_fskModem);
_bitBuffer = ByteBuffer.allocate(10 * _recordBitBuffer.length);
constructSystemAudioDevices();
new Thread(this).start();
}
private void constructSystemAudioDevices() {
@ -81,6 +90,7 @@ public class SoundModem implements Transport {
AUDIO_SAMPLE_SIZE,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);
_systemAudioRecorder.startRecording();
int usage = AudioAttributes.USAGE_MEDIA;
_systemAudioPlayer = new AudioTrack.Builder()
@ -107,6 +117,16 @@ public class SoundModem implements Transport {
@Override
public int read(byte[] data) throws IOException {
synchronized (_bitBuffer) {
if (_bitBuffer.position() > 0) {
_bitBuffer.flip();
int len = _bitBuffer.remaining();
_bitBuffer.get(data, 0, len);
//Log.i(TAG, "-- " + DebugTools.byteBitsToString(data));
_bitBuffer.compact();
return len;
}
}
return 0;
}
@ -133,6 +153,36 @@ public class SoundModem implements Transport {
@Override
public void close() throws IOException {
Log.i(TAG, "close()");
_isRunning = false;
_systemAudioRecorder.stop();
_systemAudioPlayer.stop();
_systemAudioRecorder.release();
_systemAudioPlayer.release();
Codec2.fskDestroy(_fskModem);
}
@Override
public void run() {
byte prevLastBit = 0;
while (_isRunning) {
// TODO, take readCnt into account, do not read if playback is active
int readCnt = _systemAudioRecorder.read(_recordAudioBuffer, 0, Codec2.fskNin(_fskModem));
//Log.i(TAG, DebugTools.shortsToHex(_recordAudioBuffer));
//Log.i(TAG, readCnt + " " + _recordAudioBuffer.length + " " + Codec2.fskNin(_fskModem));
Codec2.fskDemodulate(_fskModem, _recordAudioBuffer, _recordBitBuffer);
//Log.i(TAG, "-- " + DebugTools.byteBitsToString(_recordBitBuffer));
//Log.i(TAG, "== " + DebugTools.byteBitsToString(BitTools.convertFromNRZI(_recordBitBuffer, prevLastBit)));
synchronized (_bitBuffer) {
try {
_bitBuffer.put(BitTools.convertFromNRZI(_recordBitBuffer, prevLastBit));
prevLastBit = _recordBitBuffer[_recordBitBuffer.length - 1];
} catch (BufferOverflowException e) {
e.printStackTrace();
_bitBuffer.clear();
}
}
}
}
}

Wyświetl plik

@ -74,6 +74,9 @@ namespace Java_com_ustadmobile_codec2_Codec2 {
conFsk->demodBits = (uint8_t*)malloc(sizeof(uint8_t) * fsk->Nbits);
conFsk->demodBuf = (int16_t*)malloc(sizeof(short) * (fsk->N + 2 * fsk->Ts));
fsk_set_freq_est_limits(fsk, -sampleFrequency / 2, sampleFrequency / 2);
fsk_set_freq_est_alg(fsk, 1);
auto pv = (unsigned long) conFsk;
return pv;
}
@ -113,6 +116,11 @@ namespace Java_com_ustadmobile_codec2_Codec2 {
return conFsk->Ts;
}
static jint fskNin(JNIEnv * env, jclass clazz, jlong n) {
ContextFsk *conFsk = getContextFsk(n);
return fsk_nin(conFsk->fsk);
}
static jint destroy(JNIEnv *env, jclass clazz, jlong n) {
Context *con = getContext(n);
codec2_destroy(con->c2);
@ -201,7 +209,8 @@ namespace Java_com_ustadmobile_codec2_Codec2 {
{"fskModSamplesBufSize","(J)I", (void *) fskModSamplesBufSize},
{"fskDemodSamplesBufSize","(J)I", (void *) fskDemodSamplesBufSize},
{"fskModBitsBufSize", "(J)I", (void *) fskModBitsBufSize},
{"fskSamplesPerSymbol","(J)I", (void *) fskSamplesPerSymbol}
{"fskSamplesPerSymbol","(J)I", (void *) fskSamplesPerSymbol},
{"fskNin", "(J)I", (void *) fskNin}
};
}

Wyświetl plik

@ -43,6 +43,7 @@ public class Codec2 {
public native static int fskDemodSamplesBufSize(long conFsk);
public native static int fskModBitsBufSize(long conFsk);
public native static int fskSamplesPerSymbol(long conFsk);
public native static int fskNin(long conFsk);
public native static long fskModulate(long conFsk, short[] outputSamples, byte[] inputBits);
public native static long fskDemodulate(long conFsk, short[] inputSamples, byte[] outputBits);