FT8CN/ft8cn/app/src/main/java/com/bg7yoz/ft8cn/rigs/TrUSDXRig.java

402 wiersze
13 KiB
Java
Czysty Wina Historia

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* (tr)uSDX, fork from KENWOOD TS590.
* 基于0.9版增加TrSDXRig的支持。
*
* @author Sunguk Lee
* 2023-08-16
*/
package com.bg7yoz.ft8cn.rigs;
import static com.bg7yoz.ft8cn.GeneralVariables.QUERY_FREQ_TIMEOUT;
import static com.bg7yoz.ft8cn.GeneralVariables.START_QUERY_FREQ_DELAY;
import android.os.Handler;
import android.util.Log;
import com.bg7yoz.ft8cn.Ft8Message;
import com.bg7yoz.ft8cn.GeneralVariables;
import com.bg7yoz.ft8cn.R;
import com.bg7yoz.ft8cn.database.ControlMode;
import com.bg7yoz.ft8cn.ft8transmit.GenerateFT8;
import com.bg7yoz.ft8cn.ui.ToastMessage;
import com.bg7yoz.ft8cn.wave.FT8Resample;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;
/**
* (tr)uSDX, fork from KENWOOD TS590.
* 2023-08-16 由DS1UFX提交修改基于0.9版),用于对(tr)uSDX audio over cat的支持。
*/
public class TrUSDXRig extends BaseRig {
private static final String TAG = "TrUSDXRig";
private static final int rxSampling = 7812;
private static final int txSampling = 11520;
private final StringBuilder buffer = new StringBuilder();
private final ByteArrayOutputStream rxStreamBuffer = new ByteArrayOutputStream();
private Timer readFreqTimer = new Timer();
private int swr = 0;
private int alc = 0;
private boolean alcMaxAlert = false;
private boolean swrAlert = false;
private boolean rxStreaming = false;
private TimerTask readTask() {
return new TimerTask() {
@Override
public void run() {
try {
if (!isConnected()) {
readFreqTimer.cancel();
readFreqTimer.purge();
readFreqTimer = null;
return;
}
if (isPttOn()) {
clearBufferData();
} else {
readFreqFromRig();//读频率
}
} catch (Exception e) {
Log.e(TAG, "readFreq error:" + e.getMessage());
}
}
};
}
/**
* 清空缓存数据
*/
private void clearBufferData() {
buffer.setLength(0);
}
@Override
public void setPTT(boolean on) {
super.setPTT(on);
if (getConnector() != null) {
switch (getControlMode()) {
case ControlMode.CAT:
if (on) {
rxStreaming = false;
}
getConnector().setPttOn(KenwoodTK90RigConstant.setTrUSDXPTTState(on));
break;
case ControlMode.RTS:
case ControlMode.DTR:
getConnector().setPttOn(on);
break;
}
}
}
@Override
public boolean isConnected() {
if (getConnector() == null) {
return false;
}
return getConnector().isConnected();
}
@Override
public void setUsbModeToRig() {
if (getConnector() != null) {
getConnector().sendData(KenwoodTK90RigConstant.setTS590OperationUSBMode());
}
}
@Override
public void setFreqToRig() {
if (getConnector() != null) {
getConnector().sendData(KenwoodTK90RigConstant.setTS590OperationFreq(getFreq()));
}
}
@Override
public void onReceiveData(byte[] data) {
byte[] remain = data;
String s = new String(data);
while (s.contains(";")) { // ;
// TODO apply effective way
int idx = s.indexOf(";");
byte[] cutted = Arrays.copyOf(remain, idx);
remain = Arrays.copyOfRange(remain, idx + 1, remain.length);
s = new String(remain);
if (rxStreaming) {
onReceivedWaveData(cutted, true);
rxStreaming = false;
} else {
buffer.append(new String(cutted));
//开始分析数据
Yaesu3Command yaesu3Command = Yaesu3Command.getCommand(buffer.toString());
clearBufferData();//清一下缓存
if (yaesu3Command == null) {
continue;
}
String cmd = yaesu3Command.getCommandID();
if (cmd.equalsIgnoreCase("FA")) {//频率
long tempFreq = Yaesu3Command.getFrequency(yaesu3Command);
if (tempFreq != 0) {//如果tempFreq==0说明频率不正常
setFreq(Yaesu3Command.getFrequency(yaesu3Command));
}
} else if (cmd.equalsIgnoreCase("US")) {
rxStreaming = true;
byte[] wave = Arrays.copyOfRange(cutted, 2, cutted.length);
onReceivedWaveData(wave);
}
}
}
if (remain.length <= 0) {
return;
}
if (rxStreaming) {
onReceivedWaveData(remain);
} else if (remain.length >= 2 && remain[0] == 0x55 && remain[1] == 0x53) {// US
clearBufferData();
rxStreaming = true;
byte[] wave = Arrays.copyOfRange(remain, 2, remain.length);
onReceivedWaveData(wave);
} else {
buffer.append(s);
}
}
private void showAlert() {
if (swr >= KenwoodTK90RigConstant.ts_590_swr_alert_max) {
if (!swrAlert) {
swrAlert = true;
ToastMessage.show(GeneralVariables.getStringFromResource(R.string.swr_high_alert));
}
} else {
swrAlert = false;
}
if (alc > KenwoodTK90RigConstant.ts_590_alc_alert_max) {//网络模式下不警告ALC
if (!alcMaxAlert) {
alcMaxAlert = true;
ToastMessage.show(GeneralVariables.getStringFromResource(R.string.alc_high_alert));
}
} else {
alcMaxAlert = false;
}
}
@Override
public void readFreqFromRig() {
if (getConnector() != null) {
clearBufferData();//清空一下缓存
// force reset
getConnector().sendData(KenwoodTK90RigConstant.setTrUSDXPTTState(false));
getConnector().sendData(KenwoodTK90RigConstant.setTS590ReadOperationFreq());
}
}
@Override
public String getName() {
return "(tr)uSDX";
}
@Override
public boolean supportWaveOverCAT() {
return true;
}
@Override
public void onDisconnecting() {
if (getConnector() != null) {
clearBufferData();
getConnector().sendData(KenwoodTK90RigConstant.setTrUSDXStreaming(false));
}
}
/**
* 当接收到音频数据后把音频数据的采样率7812Hz转换为12000Hz发送给Connector。
*
* @param data 接收到的音频7812Hz
*/
public void onReceivedWaveData(byte[] data) {
onReceivedWaveData(data, false);
}
/**
* 当接收到音频数据后把音频数据的采样率7812Hz转换为12000Hz发送给Connector。
*
* @param data 接收到的音频7812Hz
* @param force 是否强制转换
*/
public void onReceivedWaveData(byte[] data, boolean force) {
if (data.length == 0) {
return;
}
if (getConnector() == null) {
return;
}
//Resample rxResample = new Resample(Resample.ConverterType.SRC_LINEAR, 1
// , rxSampling, 12000);
rxStreamBuffer.write(data, 0, data.length);
if (rxStreamBuffer.size() >= 256 || force) {//8位转16位7812Hz转12000Hz
//byte[] resampled = rxResample.processCopy(toWaveSamples8To16(rxStreamBuffer.toByteArray()));
float[] resampled = FT8Resample.get32Resample16(
toWaveSamples8To16Int(rxStreamBuffer.toByteArray()), rxSampling, 12000,1);
rxStreamBuffer.reset();
getConnector().receiveWaveData(resampled);
}
//rxResample.close();
}
@Override
public void sendWaveData(Ft8Message message) {
if (getConnector() == null) {
return;
}
float[] wave = GenerateFT8.generateFt8(message, GeneralVariables.getBaseFrequency()
, 24000);
if (wave == null) {
setPTT(false);
return;
}
//调整信号强度
for (int i = 0; i < wave.length; i++) {
wave[i]=wave[i]*GeneralVariables.volumePercent;
}
//
// byte[] pcm16 = toWaveFloatToPCM16(wave);
// Resample txResample = new Resample(Resample.ConverterType.SRC_SINC_FASTEST, 1
// , 24000, txSampling);
// byte[] resampled = txResample.processCopy(pcm16);
// txResample.close();
// byte[] pcm8 = toWaveSamples16To8(resampled);
byte[] pcm8 = FT8Resample.get8Resample32(wave, 24000, txSampling,1);
for (int i = 0; i < pcm8.length; i++) {
if (pcm8[i] == 0x3B) pcm8[i] = 0x3A; // ; to :
}
while (pcm8.length > 0) {
if (pcm8.length <= 256) {
getConnector().sendData(pcm8);
break;
} else {
getConnector().sendData(Arrays.copyOfRange(pcm8, 0, 256));
pcm8 = Arrays.copyOfRange(pcm8, 256, pcm8.length);
}
}
}
/**
* 音频8bit采样转换为16bit采样位深
*
* @param in 8 bit 数据
* @return 16 bit数据byte类型
*/
private static byte[] toWaveSamples8To16(byte[] in) {
ByteBuffer buf = ByteBuffer.allocate(in.length * 2);
for (int i = 0; i < in.length; i++) {
short v = (short) (((short) in[i] - 128) << 8);
buf.putShort(v);
}
return buf.array();
}
/**
* 音频8bitcaiyang转换为16bit采样位深
*
* @param in 8 bit 数据
* @return 16 bit 数据short类型
*/
private static short[] toWaveSamples8To16Int(byte[] in) {
short[] buf = new short[in.length];
for (int i = 0; i < in.length; i++) {
buf[i] = (short) (((short) in[i] - 128) << 8);
}
return buf;
}
private static byte[] toWaveFloatToPCM16(float[] in) {
ByteBuffer buf = ByteBuffer.allocate(in.length * 2);
buf.order(ByteOrder.LITTLE_ENDIAN);
for (int i = 0; i < in.length; i++) {
float x = in[i];
short v = (short) (x * 32767.0f);
buf.putShort(v);
}
return buf.array();
}
private static byte[] toWaveFloatToPCM8(float[] in) {
byte[] out = new byte[in.length];
for (int i = 0; i < in.length; i++) {
float x = in[i];
short v = (short) (x * 32767.0f);
out[i] = (byte) ((byte) (v >> 8) + 128);
}
return out;
}
/**
* 把16 bit 数据转成8 bit
*
* @param in 16 bit 数据(字节)
* @return 8 bit 字节
*/
private static byte[] toWaveSamples16To8(byte[] in) {
byte[] out = new byte[in.length / 2];
for (int i = 0; i < out.length; i++) {
short v = readShortBigEndianData(in, i * 2);
out[i] = (byte) (((byte) (v >> 8)) + 128);
}
return out;
}
private static byte[] toWaveSamples16To8(short[] in) {
byte[] out = new byte[in.length];
for (int i = 0; i < out.length; i++) {
out[i] = (byte) (((byte) (in[i] >> 8)) + 128);
}
return out;
}
public TrUSDXRig() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (getConnector() != null) {
getConnector().sendData(KenwoodTK90RigConstant.setTS590VFOMode());
//改成设置usb模式
getConnector().sendData(KenwoodTK90RigConstant.setTS590OperationUSBMode());
getConnector().sendData(KenwoodTK90RigConstant.setTrUSDXStreaming(true));
}
}
}, START_QUERY_FREQ_DELAY - 500);
readFreqTimer.schedule(readTask(), START_QUERY_FREQ_DELAY, QUERY_FREQ_TIMEOUT);
}
/**
* 从流数据中读取小端模式的Short
*
* @param data 流数据
* @param start 起始点
* @return Int16
*/
public static short readShortBigEndianData(byte[] data, int start) {
if (data.length - start < 2) return 0;
return (short) ((short) data[start] & 0xff
| ((short) data[start + 1] & 0xff) << 8);
}
}