FT8CN/ft8cn/app/src/main/java/com/bg7yoz/ft8cn/ft8transmit/GenerateFT8.java

257 wiersze
9.1 KiB
Java
Czysty Zwykły widok Historia

package com.bg7yoz.ft8cn.ft8transmit;
/**
* FT832
* @author BGY70Z
* @date 2023-03-20
*/
import android.util.Log;
import com.bg7yoz.ft8cn.Ft8Message;
import com.bg7yoz.ft8cn.GeneralVariables;
import com.bg7yoz.ft8cn.R;
import com.bg7yoz.ft8cn.ft8signal.FT8Package;
import com.bg7yoz.ft8cn.ui.ToastMessage;
public class GenerateFT8 {
private static final String TAG = "GenerateFT8";
private static final int FTX_LDPC_K = 91;
public static final int FTX_LDPC_K_BYTES = (FTX_LDPC_K + 7) / 8;
private static final int FT8_NN = 79;
private static final float FT8_SYMBOL_PERIOD = 0.160f;
private static final float FT8_SYMBOL_BT = 2.0f;
private static final float FT8_SLOT_TIME = 15.0f;
private static final int Ft8num_samples = 15 * 12000;
private static final float M_PI = 3.14159265358979323846f;
public static final int num_tones = FT8_NN;//符号数量FT8是79个FT4是105个。
public static final float symbol_period = FT8_SYMBOL_PERIOD;//FT8_SYMBOL_PERIOD=0.160f
private static final float symbol_bt = FT8_SYMBOL_BT;//FT8_SYMBOL_BT=2.0f
private static final float slot_time = FT8_SLOT_TIME;//FT8_SLOT_TIME=15f
//public static int sample_rate = 48000;//采样率
//public static int sample_rate = 12000;//采样率
static {
System.loadLibrary("ft8cn");
}
public static int checkI3ByCallsign(String callsign) {
String substring = callsign.substring(callsign.length() - 2);
if (substring.equals("/P")) {
if (callsign.length() <= 8) {
return 2;//i3=2消息
} else {
return 4;//说明时非标准呼号
}
}
if (substring.equals("/R")) {
if (callsign.length() <= 8) {
return 1;//i3=2消息
} else {
return 4;//说明时非标准呼号
}
}
if (callsign.contains("/")) {//除了/P /R以外其余的都是非标准呼号
return 4;
}
if (callsign.length() > 6) {//呼号大于6位也是非标准呼号
return 4;
}
if (callsign.length() == 0) {//没有呼号,就是自由文本
return 0;
}
return 1;
}
public static String byteToBinString(byte[] data) {
if (data == null) {
return "";
}
StringBuilder string = new StringBuilder();
for (int i = 0; i < data.length; i++) {
string.append(String.format(",%8s", Integer.toBinaryString(data[i] & 0xff)).replace(" ", "0"));
}
return string.toString();
}
public static String byteToHexString(byte[] data) {
StringBuilder string = new StringBuilder();
for (int i = 0; i < data.length; i++) {
string.append(String.format(",%02X", data[i]));
}
return string.toString();
}
/**
*
*
* @param callsign
* @return
*/
public static boolean checkIsStandardCallsign(String callsign) {
String temp;
if (callsign.endsWith("/P") || callsign.endsWith("/R")){
temp=callsign.substring(0,callsign.length()-2);
}else {
temp=callsign;
}
//FT8的认定标准业余呼号由一个或两个字符的前缀组成其中至少一个必须是字母后跟一个十进制数字和最多三个字母的后缀。
return temp.matches("[A-Z0-9]?[A-Z0-9][0-9][A-Z][A-Z0-9]?[A-Z]?");
}
/**
*
*
* @param extraInfo
* @return
*/
private static boolean checkIsReport(String extraInfo) {
if (extraInfo.equals("73") || extraInfo.equals("RRR")
|| extraInfo.equals("RR73")||extraInfo.equals("")) {
return false;
}
return !extraInfo.trim().matches("[A-Z][A-Z][0-9][0-9]");
}
public static float[] generateFt8(Ft8Message msg, float frequency,int sample_rate){
return generateFt8(msg,frequency,sample_rate,true);
}
/**
* FT8
* @param msg
* @param frequency
* @param sample_rate
* @param hasModifier
* @return
*/
public static float[] generateFt8(Ft8Message msg, float frequency,int sample_rate,boolean hasModifier) {
if (msg.callsignFrom.length()<3){
ToastMessage.show(GeneralVariables.getStringFromResource(R.string.callsign_error));
return null;
}
// 首先,将文本数据打包为二进制消息,共12个字节
byte[] packed = new byte[FTX_LDPC_K_BYTES];
//把"<>"去掉
msg.callsignTo = msg.callsignTo.replace("<", "").replace(">", "");
msg.callsignFrom = msg.callsignFrom.replace("<", "").replace(">", "");
if (hasModifier) {
msg.modifier = GeneralVariables.toModifier;//修饰符
}else {
msg.modifier="";
}
//判定用非标准呼号i3=4的条件
//1.FROMCALL为非标准呼号 ,且 符合2或3
//2.扩展消息时 网格、RR73,RRR,73
//3.CQ,QRZ,DE
if (msg.i3 != 0) {//目前只支持i3=1,i3=2,i3=4,i3=0 && n3=0
if (!checkIsStandardCallsign(msg.callsignFrom)
&& (!checkIsReport(msg.extraInfo) || msg.checkIsCQ())) {
msg.i3 = 4;
} else if (msg.callsignFrom.endsWith("/P")||(msg.callsignTo.endsWith("/P"))) {
msg.i3 = 2;
} else {
msg.i3 = 1;
}
}
if (msg.i3 == 1 || msg.i3 == 2) {
packed = FT8Package.generatePack77_i1(msg);
} else if (msg.i3 == 4) {//说明是非标准呼号
packed = FT8Package.generatePack77_i4(msg);
} else {
packFreeTextTo77(msg.getMessageText(), packed);
}
return generateFt8ByA91(packed,frequency,sample_rate);
/*
// 其次将二进制消息编码为FSK音调序列,79个字节
byte[] tones = new byte[num_tones]; // 79音调符号数组
//此处是88个字节91+7/8可以使用a91生成音频
ft8_encode(packed, tones);
// 第三将FSK音调转换为音频信号b
int num_samples = (int) (0.5f + num_tones * symbol_period * sample_rate); // 数据信号中的采样数0.5+79*0.16*12000
//float[] signal = new float[Ft8num_samples];
float[] signal = new float[num_samples];
//Ft8num_sampleFT8声音的总采样数不是字节数。15*12000
//for (int i = 0; i < Ft8num_samples; i++)//把数据全部静音。
for (int i = 0; i < num_samples; i++)//把数据全部静音。
{
signal[i] = 0;
}
// 用79个字节符号生成FT8音频
synth_gfsk(tones, num_tones, frequency, symbol_bt, symbol_period, sample_rate, signal, 0);
for (int i = 0; i < num_samples; i++)//把数据全部静音。
{
if (signal[i]>1.0||signal[i]<-1.0){
Log.e(TAG, "generateFt8: "+signal[i] );
}
}
return signal;
*/
}
public static float[] generateFt8ByA91(byte[] a91, float frequency,int sample_rate){
byte[] tones = new byte[num_tones]; // 79音调符号数组
//此处是12个字节91+7/8可以使用a91生成音频
ft8_encode(a91, tones);
// 第三将FSK音调转换为音频信号b
int num_samples = (int) (0.5f + num_tones * symbol_period * sample_rate); // 数据信号中的采样数0.5+79*0.16*12000
//int num_silence = (int) ((slot_time * sample_rate - num_samples) / 2); // 两端填充静音到15秒15*12000-num_samples/21.18秒的样本数)
//int num_total_samples = num_silence + num_samples + num_silence; // 填充信号中的样本数2.36秒+12.64秒=15秒的样本数
//float[] signal = new float[Ft8num_samples];
float[] signal = new float[num_samples];
//Ft8num_sampleFT8声音的总采样数不是字节数。15*12000
//for (int i = 0; i < Ft8num_samples; i++)//把数据全部静音。
for (int i = 0; i < num_samples; i++)//把数据全部静音。
{
signal[i] = 0;
}
// 用79个字节符号生成FT8音频
synth_gfsk(tones, num_tones, frequency, symbol_bt, symbol_period, sample_rate, signal, 0);
// for (int i = 0; i < num_samples; i++)//把数据全部静音。
// {
// if (signal[i]>1.0||signal[i]<-1.0){
// Log.e(TAG, "generateFt8: "+signal[i] );
// }
// }
return signal;
}
private static native int packFreeTextTo77(String msg, byte[] c77);
private static native int pack77(String msg, byte[] c77);
private static native void ft8_encode(byte[] payload, byte[] tones);
private static native void synth_gfsk(byte[] symbols, int n_sym, float f0,
float symbol_bt, float symbol_period,
int signal_rate, float[] signal, int offset);
}