Merge branch 'master' into legacy

legacy
sh123 2022-08-06 21:47:52 +03:00
commit f9fbcef17e
16 zmienionych plików z 283 dodań i 15 usunięć

Wyświetl plik

@ -10,8 +10,8 @@ android {
applicationId "com.radio.codec2talkie"
minSdkVersion 21
targetSdkVersion 30
versionCode 132
versionName "1.32"
versionCode 133
versionName "1.33"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

Wyświetl plik

@ -110,6 +110,7 @@ public class MainActivity extends AppCompatActivity implements ServiceConnection
private boolean _isConnecting = false;
private boolean _isAppExit = false;
private boolean _isAppRestart = false;
private boolean _isRigCtlUsbConnected = false;
private long _backPressedTimestamp;
@ -262,7 +263,11 @@ public class MainActivity extends AppCompatActivity implements ServiceConnection
break;
case "sound_modem":
_textConnInfo.setText(R.string.main_status_sound_modem);
startAppService(TransportFactory.TransportType.SOUND_MODEM);
String rig = _sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_RIG, "Disabled");
if (rig.equals("Disabled"))
startAppService(TransportFactory.TransportType.SOUND_MODEM);
else
startUsbConnectActivity();
break;
case "tcp_ip":
startTcpIpConnectActivity();
@ -284,7 +289,11 @@ public class MainActivity extends AppCompatActivity implements ServiceConnection
Intent data = result.getData();
assert data != null;
int resultCode = result.getResultCode();
if (resultCode == RESULT_CANCELED) {
String transportType = _sharedPreferences.getString(PreferenceKeys.PORTS_TYPE, "loopback");
if (transportType.equals("sound_modem")) {
_isRigCtlUsbConnected = resultCode == RESULT_OK;
startAppService(TransportFactory.TransportType.SOUND_MODEM);
} else if (resultCode == RESULT_CANCELED) {
_textConnInfo.setText(R.string.main_status_loopback_test);
startAppService(TransportFactory.TransportType.LOOPBACK);
} else if (resultCode == RESULT_OK) {
@ -296,6 +305,7 @@ public class MainActivity extends AppCompatActivity implements ServiceConnection
protected void startUsbConnectActivity() {
_isConnecting = true;
_isRigCtlUsbConnected = false;
_usbActivityLauncher.launch(new Intent(this, UsbConnectActivity.class));
}
@ -456,6 +466,12 @@ public class MainActivity extends AppCompatActivity implements ServiceConnection
status += getString(R.string.kiss_scrambler_label);
}
// rig CAT control
String rigName = _sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_RIG, "Disabled");
if (!rigName.equals("Disabled") && _isRigCtlUsbConnected) {
status += getString(R.string.ports_sound_modem_rig_label);
}
// aprs
boolean aprsEnabled = _sharedPreferences.getBoolean(PreferenceKeys.APRS_ENABLED, false);
if (aprsEnabled) {

Wyświetl plik

@ -92,7 +92,7 @@ public class UsbConnectActivity extends AppCompatActivity {
customTable.addProduct(0x1b4f, 0x9204, CdcAcmSerialDriver.class);
// Arduino Due
customTable.addProduct(0x2341, 0x003d, CdcAcmSerialDriver.class);
// STM
// STM, MCHF
customTable.addProduct(0x0483, 0x5732, CdcAcmSerialDriver.class);
return new UsbSerialProber(customTable);
}

Wyświetl plik

@ -15,6 +15,7 @@ import com.radio.codec2talkie.transport.SoundModem;
import com.radio.codec2talkie.transport.Transport;
import java.io.IOException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.util.Arrays;
@ -121,7 +122,12 @@ public class Hdlc implements Protocol {
_readByte = 0;
_prevHdlc = 0;
} else {
_currentFrameBuffer.put(bit);
try {
_currentFrameBuffer.put(bit);
} catch (BufferOverflowException e) {
e.printStackTrace();
_currentFrameBuffer.clear();
}
_prevHdlc++;
}
}

Wyświetl plik

@ -0,0 +1,21 @@
package com.radio.codec2talkie.rigctl;
import android.content.Context;
import com.radio.codec2talkie.transport.Transport;
import java.io.IOException;
public class Disabled implements RigCtl{
@Override
public void initialize(Transport transport, Context context, RigCtlCallback protocolCallback) throws IOException {
}
@Override
public void pttOn() {
}
@Override
public void pttOff() {
}
}

Wyświetl plik

@ -0,0 +1,51 @@
package com.radio.codec2talkie.rigctl;
import android.content.Context;
import android.util.Log;
import com.radio.codec2talkie.transport.Transport;
import java.io.IOException;
import java.nio.ByteBuffer;
// http://www.ka7oei.com/ft817_meow.html
public class Ft817 implements RigCtl {
private static final String TAG = Ft817.class.getSimpleName();
private Transport _transport;
@Override
public void initialize(Transport transport, Context context, RigCtlCallback protocolCallback) throws IOException {
_transport = transport;
}
@Override
public void pttOn() throws IOException {
// 0x00, 0x00, 0x00, 0x00, 0x08
// returns 0x00 (was un-keyed), 0xf0 (already keyed)
Log.i(TAG, "PTT ON");
ByteBuffer cmd = ByteBuffer.allocate(5);
cmd.put((byte)0x00).put((byte)0x00).put((byte)0x00).put((byte)0x00).put((byte)0x08);
_transport.write(cmd.array());
Log.i(TAG, "PTT ON done");
byte[] response = new byte[1];
int bytesRead = _transport.read(response);
Log.i(TAG, "PTT ON response: " + bytesRead + " " + response[0]);
}
@Override
public void pttOff() throws IOException {
// 0x00, 0x00, 0x00, 0x00, 0x88
// returns 0x00 (was keyed), 0xf0 (already un-keyed)
Log.i(TAG, "PTT OFF");
ByteBuffer cmd = ByteBuffer.allocate(5);
cmd.put((byte)0x00).put((byte)0x00).put((byte)0x00).put((byte)0x00).put((byte)0x88);
_transport.write(cmd.array());
Log.i(TAG, "PTT OFF done");
byte[] response = new byte[1];
int bytesRead = _transport.read(response);
Log.i(TAG, "PTT OFF response: " + bytesRead + " " + response[0]);
}
}

Wyświetl plik

@ -0,0 +1,15 @@
package com.radio.codec2talkie.rigctl;
import android.content.Context;
import com.radio.codec2talkie.protocol.ProtocolCallback;
import com.radio.codec2talkie.transport.Transport;
import java.io.IOException;
public interface RigCtl {
void initialize(Transport transport, Context context, RigCtlCallback protocolCallback) throws IOException;
void pttOn() throws IOException;
void pttOff() throws IOException;
}

Wyświetl plik

@ -0,0 +1,4 @@
package com.radio.codec2talkie.rigctl;
public interface RigCtlCallback {
}

Wyświetl plik

@ -0,0 +1,29 @@
package com.radio.codec2talkie.rigctl;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import androidx.preference.PreferenceManager;
import com.radio.codec2talkie.connect.UsbPortHandler;
import com.radio.codec2talkie.settings.PreferenceKeys;
public class RigCtlFactory {
private static final String TAG = RigCtlFactory.class.getSimpleName();
public static RigCtl create(Context context) {
if (UsbPortHandler.getPort() == null)
return new Disabled();
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
String rigName = sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_RIG, "Disabled");
try {
Class<?> loadClass = Class.forName(String.format("com.radio.codec2talkie.rigctl.%s", rigName));
Log.i(TAG, "Using rig " + rigName);
return (RigCtl)loadClass.newInstance();
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
return new Disabled();
}
}
}

Wyświetl plik

@ -20,6 +20,8 @@ public final class PreferenceKeys {
public static String PORTS_SOUND_MODEM_TYPE = "ports_sound_modem_type";
public static String PORTS_SOUND_MODEM_PREAMBLE = "ports_sound_modem_preamble";
public static String PORTS_SOUND_MODEM_DISABLE_RX = "ports_sound_modem_disable_rx";
public static String PORTS_SOUND_MODEM_RIG = "ports_sound_modem_rig";
public static String PORTS_SOUND_MODEM_GAIN ="ports_sound_modem_gain";
public static String CODEC2_MODE = "codec2_mode";
public static String CODEC2_RECORDING_ENABLED = "codec2_recording_enabled";

Wyświetl plik

@ -12,6 +12,8 @@ import android.util.Log;
import androidx.preference.PreferenceManager;
import com.radio.codec2talkie.rigctl.RigCtl;
import com.radio.codec2talkie.rigctl.RigCtlFactory;
import com.radio.codec2talkie.settings.PreferenceKeys;
import com.radio.codec2talkie.tools.AudioTools;
import com.radio.codec2talkie.tools.BitTools;
@ -22,13 +24,18 @@ import java.io.IOException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;
public class SoundModem implements Transport, Runnable {
private static final String TAG = SoundModem.class.getSimpleName();
private static final int PTT_OFF_DELAY_MS = 1000;
// NOTE, codec2 library requires that sample_rate % bit_rate == 0
public static final int SAMPLE_RATE = 19200;
//public static final int SAMPLE_RATE = 48000;
private final String _name;
@ -52,20 +59,25 @@ public class SoundModem implements Transport, Runnable {
private final long _fskModem;
private final RigCtl _rigCtl;
private Timer _pttOffTimer;
private boolean _isPttOn = false;
public SoundModem(Context context) {
_context = context;
_sharedPreferences = PreferenceManager.getDefaultSharedPreferences(_context);
boolean disableRx = _sharedPreferences.getBoolean(PreferenceKeys.PORTS_SOUND_MODEM_DISABLE_RX, false);
int bitRate = Integer.parseInt(_sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_TYPE, "1200"));
int gain = Integer.parseInt(_sharedPreferences.getString(PreferenceKeys.PORTS_SOUND_MODEM_GAIN, "10000"));
_name = "SoundModem" + bitRate;
if (bitRate == 300) {
// <230 spacing for 300 bps does not work with codec2 fsk for receive
_fskModem = Codec2.fskCreate(SAMPLE_RATE, 300, 1600, 200);
_fskModem = Codec2.fskCreate(SAMPLE_RATE, 300, 1600, 200, gain);
} else if (bitRate == 1200) {
_fskModem = Codec2.fskCreate(SAMPLE_RATE, 1200, 1200, 1000);
_fskModem = Codec2.fskCreate(SAMPLE_RATE, 1200, 1200, 1000, gain);
} else {
_fskModem = Codec2.fskCreate(SAMPLE_RATE, 2400, 2165, 1805);
_fskModem = Codec2.fskCreate(SAMPLE_RATE, 2400, 2165, 1805, gain);
}
_recordAudioBuffer = new short[Codec2.fskDemodSamplesBufSize(_fskModem)];
@ -82,6 +94,15 @@ public class SoundModem implements Transport, Runnable {
else
_sampleBuffer = ByteBuffer.allocate(0);
_rigCtl = RigCtlFactory.create(context);
try {
_rigCtl.initialize(TransportFactory.create(TransportFactory.TransportType.USB, context), context, null);
} catch (IOException e) {
e.printStackTrace();
}
_isPttOn = false;
if (!disableRx)
new Thread(this).start();
}
@ -147,6 +168,8 @@ public class SoundModem implements Transport, Runnable {
@Override
public int write(byte[] srcDataBytesAsBits) throws IOException {
pttOn();
//Log.v(TAG, "write " + DebugTools.byteBitsToFlatString(srcDataBytesAsBits));
byte[] dataBytesAsBits = BitTools.convertToNRZI(srcDataBytesAsBits);
//Log.v(TAG, "write NRZ " + DebugTools.byteBitsToFlatString(dataBytesAsBits));
@ -184,6 +207,7 @@ public class SoundModem implements Transport, Runnable {
} else {
_systemAudioPlayer.write(_playbackAudioBuffer, 0, bitBufferTail.length * _samplesPerSymbol);
}
pttOff();
return 0;
}
@ -226,8 +250,10 @@ public class SoundModem implements Transport, Runnable {
}
} else {
int readCnt = _systemAudioRecorder.read(_recordAudioBuffer, 0, nin);
// TODO, read tail
if (readCnt != nin) {
Log.e(TAG, "" + readCnt + " != " + nin);
Log.w(TAG, "" + readCnt + " != " + nin);
continue;
}
//Log.v(TAG, "read samples: " + DebugTools.shortsToHex(_recordAudioBuffer));
}
@ -248,4 +274,36 @@ public class SoundModem implements Transport, Runnable {
}
}
}
private void pttOn() {
if (_isPttOn) return;
try {
_rigCtl.pttOn();
_isPttOn = true;
} catch (IOException e) {
e.printStackTrace();
}
}
private void pttOff() {
if (!_isPttOn) return;
if (_pttOffTimer != null) {
_pttOffTimer.cancel();
_pttOffTimer.purge();
_pttOffTimer = null;
}
_pttOffTimer = new Timer();
_pttOffTimer.schedule(new TimerTask() {
@Override
public void run() {
try {
_rigCtl.pttOff();
_isPttOn = false;
} catch (IOException e) {
e.printStackTrace();
}
}
}, PTT_OFF_DELAY_MS);
}
}

Wyświetl plik

@ -352,4 +352,46 @@
<item>usb</item>
<item>sound_modem</item>
</string-array>
<string-array name="ports_sound_modem_rig_entries">
<item>Do not use rig control</item>
<item>FT-817/818/MCHF</item>
</string-array>
<string-array name="ports_sound_modem_rig_values">
<item>Disabled</item>
<item>Ft817</item>
</string-array>
<string-array name="ports_sound_modem_gain_entries">
<item>+0 db</item>
<item>+1 db</item>
<item>+2 db</item>
<item>+3 db</item>
<item>+4 db</item>
<item>+5 db</item>
<item>+6 db</item>
<item>+7 db</item>
<item>+8 db</item>
<item>+9 db</item>
<item>+10 db</item>
<item>+11 db</item>
<item>+12 db</item>
</string-array>
<string-array name="ports_sound_modem_gain_values">
<item>1000</item>
<item>1258</item>
<item>1584</item>
<item>1995</item>
<item>2511</item>
<item>3162</item>
<item>3981</item>
<item>5011</item>
<item>6309</item>
<item>7943</item>
<item>10000</item>
<item>12589</item>
<item>15848</item>
</string-array>
</resources>

Wyświetl plik

@ -302,4 +302,7 @@
<string name="ports_type_title">TNC transport type</string>
<string name="ports_sound_modem_disable_rx_title">Disable receive</string>
<string name="ports_sound_modem_disable_rx_summary">Run modem in transmit only mode, receive is disabled to save CPU cycles</string>
<string name="ports_sound_modem_rig_title">Select RIG model for CAT PTT control</string>
<string name="ports_sound_modem_gain_title">Set modem audio gain</string>
<string name="ports_sound_modem_rig_label">&#127899;</string>
</resources>

Wyświetl plik

@ -29,5 +29,23 @@
app:defaultValue="false">
</SwitchPreference>
<ListPreference
app:key="ports_sound_modem_rig"
app:title="@string/ports_sound_modem_rig_title"
app:entries="@array/ports_sound_modem_rig_entries"
app:entryValues="@array/ports_sound_modem_rig_values"
app:defaultValue="Disabled"
app:summary="%s">
</ListPreference>
<ListPreference
app:key="ports_sound_modem_gain"
app:title="@string/ports_sound_modem_gain_title"
app:entries="@array/ports_sound_modem_gain_entries"
app:entryValues="@array/ports_sound_modem_gain_values"
app:defaultValue="10000"
app:summary="%s">
</ListPreference>
</PreferenceCategory>
</PreferenceScreen>

Wyświetl plik

@ -25,6 +25,7 @@ namespace Java_com_ustadmobile_codec2_Codec2 {
int Nbits;
int N;
int Ts;
int gain;
};
static Context *getContext(jlong jp) {
@ -56,7 +57,7 @@ namespace Java_com_ustadmobile_codec2_Codec2 {
return pv;
}
static jlong fskCreate(JNIEnv *env, jclass clazz, int sampleFrequency, int symbolRate, int toneFreq, int toneSpacing) {
static jlong fskCreate(JNIEnv *env, jclass clazz, int sampleFrequency, int symbolRate, int toneFreq, int toneSpacing, int gain) {
struct ContextFsk *conFsk;
conFsk = (struct ContextFsk *) malloc(sizeof(struct ContextFsk));
struct FSK *fsk;
@ -74,6 +75,8 @@ 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));
conFsk->gain = gain;
fsk_set_freq_est_limits(fsk, 500, sampleFrequency / 4);
fsk_set_freq_est_alg(fsk, 0);
@ -168,7 +171,7 @@ namespace Java_com_ustadmobile_codec2_Codec2 {
fsk_mod(conFsk->fsk, conFsk->modBuf, conFsk->modBits, inputBitsSize);
jshort *jOutBuf = env->GetShortArrayElements(outputSamples, nullptr);
for (int i = 0; i < conFsk->N; i++) {
jOutBuf[i] = (int16_t)(conFsk->modBuf[i] * FDMDV_SCALE);
jOutBuf[i] = (int16_t)(conFsk->modBuf[i] * conFsk->gain);
}
env->ReleaseShortArrayElements(outputSamples, jOutBuf, 0);
return 0;
@ -186,7 +189,7 @@ namespace Java_com_ustadmobile_codec2_Codec2 {
ContextFsk *conFsk = getContextFsk(n);
env->GetShortArrayRegion(inputSamples, 0, conFsk->N, reinterpret_cast<jshort*>(conFsk->demodBuf));
for(int i = 0; i < fsk_nin(conFsk->fsk); i++){
conFsk->demodCBuf[i].real = ((float)conFsk->demodBuf[i]) / FDMDV_SCALE;
conFsk->demodCBuf[i].real = ((float)conFsk->demodBuf[i]) / conFsk->gain;
conFsk->demodCBuf[i].imag = 0.0;
}
fsk_demod(conFsk->fsk, conFsk->demodBits, conFsk->demodCBuf);
@ -201,7 +204,7 @@ namespace Java_com_ustadmobile_codec2_Codec2 {
{"destroy", "(J)I", (void *) destroy},
{"encode", "(J[S[C)J", (void *) encode},
{"decode", "(J[S[B)J", (void *) decode},
{"fskCreate", "(IIII)J", (void *) fskCreate},
{"fskCreate", "(IIIII)J", (void *) fskCreate},
{"fskDestroy", "(J)I", (void *) fskDestroy},
{"fskModulate", "(J[S[B)J", (void *) fskModulate},
{"fskDemodulate", "(J[S[B)J", (void *) fskDemodulate},

Wyświetl plik

@ -35,7 +35,7 @@ public class Codec2 {
public native static long encode(long con, short[] inputSamples, char[] outputBits);
public native static long decode(long con, short[] outputSamples, byte[] inputsBits);
public native static long fskCreate(int sampleFrequency, int symbolRate, int toneFreq, int toneSpacing);
public native static long fskCreate(int sampleFrequency, int symbolRate, int toneFreq, int toneSpacing, int gain);
public native static int fskDestroy(long conFsk);
public native static int fskDemodBitsBufSize(long conFsk);