kopia lustrzana https://github.com/N0BOY/FT8CN
893 wiersze
36 KiB
Java
Executable File
893 wiersze
36 KiB
Java
Executable File
package com.bg7yoz.ft8cn;
|
||
/**
|
||
* -----2022.5.6-----
|
||
* MainViewModel类,用于解码FT8信号以及保存与解码有关的变量数据。生存于APP的整个生命周期。
|
||
* 1.解码的总条数。decoded_counter和mutable_Decoded_Counter。
|
||
* 2.解码消息的列表。消息以Ft8Message展示,列表用ArrayList泛型实现。ft8Messages,mutableFt8MessageList。
|
||
* 3.解码和录音都需要时间同步,也就是以UTC时间的每15秒为一个周期。同步事件的触发由UtcTimer类来实现。
|
||
* 录音方法runRecode,解码暂时用testFt8实现,后续应改为类方式。--------TODO------------
|
||
* 4.当前的UTC时间。timerSec,更新频率(心跳频率)由UtcTimer确定,暂定100毫秒。
|
||
* <p>
|
||
* 5.通过类方法getInstance获取当前的MainViewModel的实例,确保有唯一的实例。
|
||
* 6.用HamAudioRecorder类实现录音,目前只实现录音成文件,然后读取文件的数据给解码模块,后面要改成直接给数组的方式----TO DO---
|
||
* <p>
|
||
* 7.解码采用JNI接口调用原生C语言。调用接口名时ft8cn,由cpp文件夹下的CMakeLists.txt维护。各函数的调用接口在decode_ft8.cpp中。
|
||
* <p>
|
||
* -----2022.5.9-----
|
||
* 如果系统没有发射信号,触发器会在每一个周期触发录音动作,因录音开始和结束要浪费一些时间,如果不干预上一个录音的动作,将出现
|
||
* 连续的周期内录音动作重叠,造成第二个录音动作失败。所以,第二个周期的录音开始前,要停止前一个周期的录音,造成的结果就是每一次录音
|
||
* 的开始时间要晚于周期开始300毫秒(模拟器的结果),实际录音的长度一般在14.77秒左右
|
||
* <p>
|
||
* @author BG7YOZ
|
||
* @date 2022.5.6
|
||
*/
|
||
|
||
import static com.bg7yoz.ft8cn.GeneralVariables.getStringFromResource;
|
||
|
||
import android.annotation.SuppressLint;
|
||
import android.bluetooth.BluetoothAdapter;
|
||
import android.bluetooth.BluetoothDevice;
|
||
import android.bluetooth.BluetoothProfile;
|
||
import android.content.Context;
|
||
import android.media.AudioManager;
|
||
import android.os.Handler;
|
||
import android.util.Log;
|
||
|
||
import androidx.lifecycle.MutableLiveData;
|
||
import androidx.lifecycle.ViewModel;
|
||
import androidx.lifecycle.ViewModelProvider;
|
||
import androidx.lifecycle.ViewModelStoreOwner;
|
||
|
||
import com.bg7yoz.ft8cn.callsign.CallsignDatabase;
|
||
import com.bg7yoz.ft8cn.callsign.CallsignInfo;
|
||
import com.bg7yoz.ft8cn.callsign.OnAfterQueryCallsignLocation;
|
||
import com.bg7yoz.ft8cn.connector.BluetoothRigConnector;
|
||
import com.bg7yoz.ft8cn.connector.CableConnector;
|
||
import com.bg7yoz.ft8cn.connector.CableSerialPort;
|
||
import com.bg7yoz.ft8cn.connector.ConnectMode;
|
||
import com.bg7yoz.ft8cn.connector.FlexConnector;
|
||
import com.bg7yoz.ft8cn.connector.IComWifiConnector;
|
||
import com.bg7yoz.ft8cn.database.ControlMode;
|
||
import com.bg7yoz.ft8cn.database.DatabaseOpr;
|
||
import com.bg7yoz.ft8cn.database.OnAfterQueryFollowCallsigns;
|
||
import com.bg7yoz.ft8cn.database.OperationBand;
|
||
import com.bg7yoz.ft8cn.flex.FlexRadio;
|
||
import com.bg7yoz.ft8cn.ft8listener.FT8SignalListener;
|
||
import com.bg7yoz.ft8cn.ft8listener.OnFt8Listen;
|
||
import com.bg7yoz.ft8cn.ft8transmit.FT8TransmitSignal;
|
||
import com.bg7yoz.ft8cn.ft8transmit.OnDoTransmitted;
|
||
import com.bg7yoz.ft8cn.ft8transmit.OnTransmitSuccess;
|
||
import com.bg7yoz.ft8cn.html.LogHttpServer;
|
||
import com.bg7yoz.ft8cn.icom.IComWifiRig;
|
||
import com.bg7yoz.ft8cn.log.QSLCallsignRecord;
|
||
import com.bg7yoz.ft8cn.log.QSLRecord;
|
||
import com.bg7yoz.ft8cn.log.SWLQsoList;
|
||
import com.bg7yoz.ft8cn.rigs.BaseRig;
|
||
import com.bg7yoz.ft8cn.rigs.BaseRigOperation;
|
||
import com.bg7yoz.ft8cn.rigs.ElecraftRig;
|
||
import com.bg7yoz.ft8cn.rigs.Flex6000Rig;
|
||
import com.bg7yoz.ft8cn.rigs.FlexNetworkRig;
|
||
import com.bg7yoz.ft8cn.rigs.GuoHeQ900Rig;
|
||
import com.bg7yoz.ft8cn.rigs.IcomRig;
|
||
import com.bg7yoz.ft8cn.rigs.InstructionSet;
|
||
import com.bg7yoz.ft8cn.rigs.KenwoodKT90Rig;
|
||
import com.bg7yoz.ft8cn.rigs.KenwoodTS590Rig;
|
||
import com.bg7yoz.ft8cn.rigs.OnRigStateChanged;
|
||
import com.bg7yoz.ft8cn.rigs.XieGu6100Rig;
|
||
import com.bg7yoz.ft8cn.rigs.XieGuRig;
|
||
import com.bg7yoz.ft8cn.rigs.Yaesu2Rig;
|
||
import com.bg7yoz.ft8cn.rigs.Yaesu38Rig;
|
||
import com.bg7yoz.ft8cn.rigs.Yaesu38_450Rig;
|
||
import com.bg7yoz.ft8cn.rigs.Yaesu39Rig;
|
||
import com.bg7yoz.ft8cn.rigs.YaesuDX10Rig;
|
||
import com.bg7yoz.ft8cn.spectrum.SpectrumListener;
|
||
import com.bg7yoz.ft8cn.timer.OnUtcTimer;
|
||
import com.bg7yoz.ft8cn.timer.UtcTimer;
|
||
import com.bg7yoz.ft8cn.ui.ToastMessage;
|
||
import com.bg7yoz.ft8cn.wave.HamRecorder;
|
||
import com.bg7yoz.ft8cn.wave.OnGetVoiceDataDone;
|
||
|
||
import java.io.File;
|
||
import java.io.IOException;
|
||
import java.util.ArrayList;
|
||
import java.util.Objects;
|
||
import java.util.concurrent.ExecutorService;
|
||
import java.util.concurrent.Executors;
|
||
|
||
|
||
public class MainViewModel extends ViewModel {
|
||
String TAG = "ft8cn MainViewModel";
|
||
public boolean configIsLoaded=false;
|
||
|
||
private static MainViewModel viewModel = null;//当前存在的实例。
|
||
//public static Application application;
|
||
|
||
|
||
//public int decoded_counter = 0;//解码的总条数
|
||
public final ArrayList<Ft8Message> ft8Messages = new ArrayList<>();//消息列表
|
||
public UtcTimer utcTimer;//同步触发动作的计时器。
|
||
|
||
//public boolean showTrackerInfo=true;
|
||
|
||
//public CallsignDatabase callsignDatabase = null;//呼号信息的数据库
|
||
public DatabaseOpr databaseOpr;//配置信息,和相关数据的数据库
|
||
|
||
|
||
public MutableLiveData<Integer> mutable_Decoded_Counter = new MutableLiveData<>();//解码的总条数
|
||
public int currentDecodeCount = 0;//本次解码的条数
|
||
public MutableLiveData<ArrayList<Ft8Message>> mutableFt8MessageList = new MutableLiveData<>();//消息列表
|
||
public MutableLiveData<Long> timerSec = new MutableLiveData<>();//当前UTC时间。更新频率由UtcTimer确定,未触发时约100毫秒。
|
||
public MutableLiveData<Boolean> mutableIsRecording = new MutableLiveData<>();//是否处于录音状态
|
||
public MutableLiveData<Boolean> mutableHamRecordIsRunning = new MutableLiveData<>();//HamRecord是否运转
|
||
public MutableLiveData<Float> mutableTimerOffset = new MutableLiveData<>();//本周期的时间延迟
|
||
public MutableLiveData<Boolean> mutableIsDecoding = new MutableLiveData<>();//会触发频谱图中的标记动作
|
||
public ArrayList<Ft8Message> currentMessages = null;//本周期解码的消息(用于画到频谱上)
|
||
|
||
public MutableLiveData<Boolean> mutableIsFlexRadio=new MutableLiveData<>();//是不是flex电台
|
||
|
||
private final ExecutorService getQTHThreadPool = Executors.newCachedThreadPool();
|
||
private final ExecutorService sendWaveDataThreadPool = Executors.newCachedThreadPool();
|
||
private final GetQTHRunnable getQTHRunnable=new GetQTHRunnable(this);
|
||
private final SendWaveDataRunnable sendWaveDataRunnable=new SendWaveDataRunnable();
|
||
|
||
|
||
public HamRecorder hamRecorder;//用于录音的对象
|
||
public FT8SignalListener ft8SignalListener;//用于监听FT8信号并解码的对象
|
||
public FT8TransmitSignal ft8TransmitSignal;//用于发射信号用的对象
|
||
public SpectrumListener spectrumListener;//用于画频谱的对象
|
||
public boolean markMessage = true;//是否标记消息开关
|
||
|
||
//控制电台的方式
|
||
public OperationBand operationBand = null;
|
||
|
||
private SWLQsoList swlQsoList=new SWLQsoList();//用于记录SWL的QSO对象,对SWL QSO做判断,防止重复。
|
||
|
||
|
||
public MutableLiveData<ArrayList<CableSerialPort.SerialPort>> mutableSerialPorts = new MutableLiveData<>();
|
||
private ArrayList<CableSerialPort.SerialPort> serialPorts;//串口列表
|
||
public BaseRig baseRig;//电台
|
||
private final OnRigStateChanged onRigStateChanged = new OnRigStateChanged() {
|
||
@Override
|
||
public void onDisconnected() {
|
||
//与电台连接中断
|
||
ToastMessage.show(getStringFromResource(R.string.disconnect_rig));
|
||
}
|
||
|
||
@Override
|
||
public void onConnected() {
|
||
//与电台建立连接
|
||
ToastMessage.show(getStringFromResource(R.string.connected_rig));
|
||
}
|
||
|
||
@Override
|
||
public void onPttChanged(boolean isOn) {
|
||
|
||
}
|
||
|
||
@Override
|
||
public void onFreqChanged(long freq) {
|
||
//当前频率:%s
|
||
ToastMessage.show(String.format(getStringFromResource(R.string.current_frequency)
|
||
, BaseRigOperation.getFrequencyAllInfo(freq)));
|
||
//把频率的变化写回到全局变量中
|
||
GeneralVariables.band = freq;
|
||
GeneralVariables.bandListIndex = OperationBand.getIndexByFreq(freq);
|
||
GeneralVariables.mutableBandChange.postValue(GeneralVariables.bandListIndex);
|
||
|
||
databaseOpr.getAllQSLCallsigns();//通联成功的呼号读出来
|
||
|
||
}
|
||
|
||
@Override
|
||
public void onRunError(String message) {
|
||
//与电台通讯出现错误,
|
||
ToastMessage.show(String.format(getStringFromResource(R.string.radio_communication_error)
|
||
, message));
|
||
}
|
||
};
|
||
|
||
//发射信号用的消息列表
|
||
//public ArrayList<Ft8Message> transmitMessages = new ArrayList<>();
|
||
//public MutableLiveData<ArrayList<Ft8Message>> mutableTransmitMessages = new MutableLiveData<>();
|
||
public MutableLiveData<Integer> mutableTransmitMessagesCount=new MutableLiveData<>();
|
||
|
||
|
||
public boolean deNoise = false;//在频谱中抑制噪声
|
||
|
||
//*********日志查询需要的变量********************
|
||
public boolean logListShowCallsign = false;//在日志查询列表的表现形式
|
||
public String queryKey = "";//查询的关键字
|
||
public int queryFilter = 0;//过滤,0全部,1,确认,2,未确认
|
||
public MutableLiveData<Integer> mutableQueryFilter = new MutableLiveData<>();
|
||
public ArrayList<QSLCallsignRecord> callsignRecords=new ArrayList<>();
|
||
//public ArrayList<QSLRecordStr> qslRecords=new ArrayList<>();
|
||
//********************************************
|
||
//关注呼号的列表
|
||
//public ArrayList<String> followCallsign = new ArrayList<>();
|
||
|
||
|
||
//日志管理HTTP SERVER
|
||
private final LogHttpServer httpServer;
|
||
|
||
/**
|
||
* 获取MainViewModel的实例,确保存在唯一的MainViewModel实例,该实例在APP的全部生存周期中。
|
||
*
|
||
* @param owner ViewModelStoreOwner 所有者,一般为Activity或Fragment。
|
||
* @return MainViewModel 返回一个MainViewModel实例
|
||
*/
|
||
public static MainViewModel getInstance(ViewModelStoreOwner owner) {
|
||
if (viewModel == null) {
|
||
viewModel = new ViewModelProvider(owner).get(MainViewModel.class);
|
||
}
|
||
return viewModel;
|
||
}
|
||
|
||
/**
|
||
* 获取消息列表中指定的消息
|
||
*
|
||
* @param position 在Mutable类型的列表中的位置
|
||
* @return 返回一个Ft8Message类型的解码后的信息
|
||
*/
|
||
public Ft8Message getFt8Message(int position) {
|
||
return Objects.requireNonNull(ft8Messages.get(position));
|
||
}
|
||
|
||
/**
|
||
* MainViewModel的构造函数主要完成一下事情:
|
||
* 1.创建与UTC同步的时钟,时钟是UtcTimer类,内核是用Timer和TimerTask实现的。回调函数是多线程的,要考虑线程安全的问题。
|
||
* 2.创建Mutable型的解码消息列表。
|
||
*/
|
||
//@RequiresApi(api = Build.VERSION_CODES.N)
|
||
public MainViewModel() {
|
||
|
||
//获取配置信息。
|
||
databaseOpr = DatabaseOpr.getInstance(GeneralVariables.getMainContext()
|
||
, "data.db");
|
||
mutableIsDecoding.postValue(false);//解码状态
|
||
//创录音对象
|
||
hamRecorder = new HamRecorder(null);
|
||
hamRecorder.startRecord();
|
||
|
||
mutableIsFlexRadio.setValue(false);
|
||
|
||
//创建用于显示时间的计时器
|
||
utcTimer = new UtcTimer(10, false, new OnUtcTimer() {
|
||
@Override
|
||
public void doHeartBeatTimer(long utc) {//不触发时的时钟信息
|
||
|
||
}
|
||
|
||
@Override
|
||
public void doOnSecTimer(long utc) {//当指定间隔时触发时
|
||
timerSec.postValue(utc);//发送当前UTC时间
|
||
mutableIsRecording.postValue(hamRecorder.isRunning());
|
||
mutableHamRecordIsRunning.postValue(hamRecorder.isRunning());//发送当前计时器状态
|
||
}
|
||
});
|
||
utcTimer.start();//启动计时器
|
||
|
||
//同步一下时间。microsoft的NTP服务器
|
||
UtcTimer.syncTime(null);
|
||
|
||
mutableFt8MessageList.setValue(ft8Messages);
|
||
|
||
//创建监听对象,回调中的动作用于处理解码、发射、关注的呼号列表添加等操作
|
||
ft8SignalListener = new FT8SignalListener(databaseOpr, new OnFt8Listen() {
|
||
@Override
|
||
public void beforeListen(long utc) {
|
||
mutableIsDecoding.postValue(true);
|
||
}
|
||
|
||
@Override
|
||
public void afterDecode(long utc, float time_sec, int sequential, ArrayList<Ft8Message> messages) {
|
||
|
||
synchronized (ft8Messages) {
|
||
ft8Messages.addAll(messages);//添加消息到列表
|
||
}
|
||
GeneralVariables.deleteArrayListMore(ft8Messages);//删除多余的消息,FT8CN限定的可展示消息的总数量
|
||
|
||
mutableFt8MessageList.postValue(ft8Messages);//触发添加消息的动作,让界面能观察到
|
||
mutableTimerOffset.postValue(time_sec);//本次时间偏移量
|
||
|
||
|
||
findIncludedCallsigns(messages);//查找符合条件的消息,放到呼叫列表中
|
||
|
||
//检查发射程序。从消息列表中解析发射的程序
|
||
ft8TransmitSignal.parseMessageToFunction(messages);
|
||
|
||
mutableIsDecoding.postValue(false);//解码的状态,会触发频谱图中的标记动作
|
||
|
||
currentMessages = messages;//保存本次解码的消息
|
||
|
||
getQTHRunnable.messages=messages;
|
||
getQTHThreadPool.execute(getQTHRunnable);//用线程池的方式查询归属地
|
||
|
||
if (GeneralVariables.saveSWLMessage) {
|
||
databaseOpr.writeMessage(messages);//把SWL消息写到数据库
|
||
}
|
||
//检查QSO of SWL,并保存到SWLQSOTable中的通联列表qsoList中
|
||
if (GeneralVariables.saveSWL_QSO){
|
||
swlQsoList.findSwlQso(messages, ft8Messages, new SWLQsoList.OnFoundSwlQso() {
|
||
@Override
|
||
public void doFound(QSLRecord record) {
|
||
databaseOpr.addSWL_QSO(record);//把SWL QSO保存到数据库
|
||
ToastMessage.show(record.swlQSOInfo());
|
||
}
|
||
});
|
||
}
|
||
//从列表中查找呼号和网格对应关系,并添加到表中
|
||
getCallsignAndGrid(messages);
|
||
}
|
||
});
|
||
|
||
ft8SignalListener.setOnWaveDataListener(new FT8SignalListener.OnWaveDataListener() {
|
||
@Override
|
||
public void getVoiceData(int duration, boolean afterDoneRemove, OnGetVoiceDataDone getVoiceDataDone) {
|
||
hamRecorder.getVoiceData(duration, afterDoneRemove, getVoiceDataDone);
|
||
}
|
||
});
|
||
|
||
|
||
ft8SignalListener.startListen();
|
||
|
||
//频谱监听对象
|
||
spectrumListener = new SpectrumListener(hamRecorder);
|
||
|
||
|
||
//创建发射对象,回调:发射前,发射后、QSL成功后。
|
||
ft8TransmitSignal = new FT8TransmitSignal(databaseOpr, new OnDoTransmitted() {
|
||
@Override
|
||
public void onBeforeTransmit(Ft8Message message, int functionOder) {
|
||
if (GeneralVariables.controlMode == ControlMode.CAT
|
||
|| GeneralVariables.controlMode == ControlMode.RTS
|
||
|| GeneralVariables.controlMode == ControlMode.DTR) {
|
||
if (baseRig != null) {
|
||
if (GeneralVariables.connectMode != ConnectMode.NETWORK) stopSco();
|
||
baseRig.setPTT(true);
|
||
}
|
||
}
|
||
if (ft8TransmitSignal.isActivated()) {
|
||
GeneralVariables.transmitMessages.add(message);
|
||
//mutableTransmitMessages.postValue(GeneralVariables.transmitMessages);
|
||
mutableTransmitMessagesCount.postValue(1);
|
||
}
|
||
}
|
||
|
||
@Override
|
||
public void onAfterTransmit(Ft8Message message, int functionOder) {
|
||
if (GeneralVariables.controlMode == ControlMode.CAT
|
||
|| GeneralVariables.controlMode == ControlMode.RTS
|
||
|| GeneralVariables.controlMode == ControlMode.DTR) {
|
||
if (baseRig != null) {
|
||
baseRig.setPTT(false);
|
||
if (GeneralVariables.connectMode != ConnectMode.NETWORK) startSco();
|
||
}
|
||
}
|
||
}
|
||
|
||
@Override
|
||
public void onAfterGenerate(float[] data) {
|
||
if (GeneralVariables.connectMode == ConnectMode.NETWORK) {
|
||
if (baseRig != null) {
|
||
if (baseRig.isConnected()) {
|
||
sendWaveDataRunnable.baseRig=baseRig;
|
||
sendWaveDataRunnable.data=data;
|
||
//以线程池的方式执行网络数据包发送
|
||
sendWaveDataThreadPool.execute(sendWaveDataRunnable);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}, new OnTransmitSuccess() {//当通联成功时
|
||
@Override
|
||
public void doAfterTransmit(QSLRecord qslRecord) {
|
||
databaseOpr.addQSL_Callsign(qslRecord);//两个操作,把呼号和QSL记录下来
|
||
if (qslRecord.getToCallsign() != null) {//把通联成功的分区加入到分区列表
|
||
GeneralVariables.callsignDatabase.getCallsignInformation(qslRecord.getToCallsign()
|
||
, new OnAfterQueryCallsignLocation() {
|
||
@Override
|
||
public void doOnAfterQueryCallsignLocation(CallsignInfo callsignInfo) {
|
||
GeneralVariables.addDxcc(callsignInfo.DXCC);
|
||
GeneralVariables.addItuZone(callsignInfo.ITUZone);
|
||
GeneralVariables.addCqZone(callsignInfo.CQZone);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
});
|
||
|
||
|
||
//打开HTTP SERVER
|
||
httpServer = new LogHttpServer(this, LogHttpServer.DEFAULT_PORT);
|
||
try {
|
||
httpServer.start();
|
||
} catch (IOException e) {
|
||
Log.e(TAG, "http server error:" + e.getMessage());
|
||
}
|
||
}
|
||
|
||
public void setTransmitIsFreeText(boolean isFreeText){
|
||
if (ft8TransmitSignal!=null) {
|
||
ft8TransmitSignal.setTransmitFreeText(isFreeText);
|
||
}
|
||
}
|
||
public boolean getTransitIsFreeText(){
|
||
if (ft8TransmitSignal!=null){
|
||
return ft8TransmitSignal.isTransmitFreeText();
|
||
}
|
||
return false;
|
||
}
|
||
|
||
|
||
/**
|
||
* 查找符合条件的消息,放到呼叫列表中
|
||
*
|
||
* @param messages 消息
|
||
*/
|
||
private void findIncludedCallsigns(ArrayList<Ft8Message> messages) {
|
||
Log.d(TAG, "findIncludedCallsigns: 查找关注的呼号");
|
||
if (ft8TransmitSignal.isActivated() && ft8TransmitSignal.sequential != UtcTimer.getNowSequential()) {
|
||
return;
|
||
}
|
||
int count=0;
|
||
for (Ft8Message msg : messages) {
|
||
//与我的呼号有关,与关注的呼号有关
|
||
if (msg.getCallsignFrom().equals(GeneralVariables.myCallsign)
|
||
|| msg.getCallsignTo().equals(GeneralVariables.myCallsign)
|
||
|| GeneralVariables.callsignInFollow(msg.getCallsignFrom())
|
||
|| (GeneralVariables.callsignInFollow(msg.getCallsignTo()) && (msg.getCallsignTo() != null))
|
||
|| (GeneralVariables.autoFollowCQ && msg.checkIsCQ())) {//是CQ,并且允许关注CQ
|
||
//看不是通联成功的呼号的消息
|
||
msg.isQSL_Callsign = GeneralVariables.checkQSLCallsign(msg.getCallsignFrom());
|
||
if (!GeneralVariables.checkIsExcludeCallsign(msg.callsignFrom)) {//不在排除呼号前缀的,才加入列表
|
||
count++;
|
||
GeneralVariables.transmitMessages.add(msg);
|
||
}
|
||
}
|
||
}
|
||
GeneralVariables.deleteArrayListMore(GeneralVariables.transmitMessages);//删除多余的消息
|
||
//mutableTransmitMessages.postValue(GeneralVariables.transmitMessages);
|
||
mutableTransmitMessagesCount.postValue(count);
|
||
}
|
||
|
||
/**
|
||
* 清除传输消息列表
|
||
*/
|
||
public void clearTransmittingMessage() {
|
||
GeneralVariables.transmitMessages.clear();
|
||
mutableTransmitMessagesCount.postValue(0);
|
||
}
|
||
|
||
|
||
/**
|
||
* 从消息列表中查找呼号和网格的对应关系
|
||
*
|
||
* @param messages 消息列表
|
||
*/
|
||
private void getCallsignAndGrid(ArrayList<Ft8Message> messages) {
|
||
for (Ft8Message msg : messages) {
|
||
if (GeneralVariables.checkFun1(msg.extraInfo)) {//检查是不是网格
|
||
//如果内存表中没有,或不一致,就写入数据库中
|
||
if (!GeneralVariables.getCallsignHasGrid(msg.getCallsignFrom(), msg.maidenGrid)) {
|
||
databaseOpr.addCallsignQTH(msg.getCallsignFrom(), msg.maidenGrid);//写数据库
|
||
}
|
||
GeneralVariables.addCallsignAndGrid(msg.getCallsignFrom(), msg.maidenGrid);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 清除消息列表
|
||
*/
|
||
public void clearFt8MessageList() {
|
||
ft8Messages.clear();
|
||
mutable_Decoded_Counter.postValue(ft8Messages.size());
|
||
mutableFt8MessageList.postValue(ft8Messages);
|
||
}
|
||
|
||
|
||
/**
|
||
* 删除单个文件
|
||
*
|
||
* @param fileName 要删除的文件的文件名
|
||
*/
|
||
public static void deleteFile(String fileName) {
|
||
File file = new File(fileName);
|
||
// 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
|
||
if (file.exists() && file.isFile()) {
|
||
file.delete();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 向关注的呼号列表添加呼号
|
||
*
|
||
* @param callsign 呼号
|
||
*/
|
||
public void addFollowCallsign(String callsign) {
|
||
if (!GeneralVariables.followCallsign.contains(callsign)) {
|
||
GeneralVariables.followCallsign.add(callsign);
|
||
databaseOpr.addFollowCallsign(callsign);
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* 从数据库中获取关注的呼号列表
|
||
*/
|
||
public void getFollowCallsignsFromDataBase() {
|
||
databaseOpr.getFollowCallsigns(new OnAfterQueryFollowCallsigns() {
|
||
@Override
|
||
public void doOnAfterQueryFollowCallsigns(ArrayList<String> callsigns) {
|
||
for (String s : callsigns) {
|
||
if (!GeneralVariables.followCallsign.contains(s)) {
|
||
GeneralVariables.followCallsign.add(s);
|
||
}
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
|
||
/**
|
||
* 设置操作载波频率。如果电台没有连接,就有操作
|
||
*/
|
||
public void setOperationBand() {
|
||
if (!isRigConnected()) {
|
||
return;
|
||
}
|
||
|
||
//先设置上边带,再设置频率
|
||
baseRig.setUsbModeToRig();//设置上边带
|
||
|
||
//此处延迟1秒发送第二个指令,是防止协谷X6100断开连接的问题
|
||
new Handler().postDelayed(new Runnable() {
|
||
@Override
|
||
public void run() {
|
||
baseRig.setFreq(GeneralVariables.band);//设置频率
|
||
baseRig.setFreqToRig();
|
||
}
|
||
}, 800);
|
||
}
|
||
|
||
public void setCivAddress() {
|
||
if (baseRig != null) {
|
||
baseRig.setCivAddress(GeneralVariables.civAddress);
|
||
}
|
||
}
|
||
|
||
public void setControlMode() {
|
||
if (baseRig != null) {
|
||
baseRig.setControlMode(GeneralVariables.controlMode);
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* 通过USB连接电台
|
||
*
|
||
* @param context context
|
||
* @param port 串口
|
||
*/
|
||
public void connectCableRig(Context context, CableSerialPort.SerialPort port) {
|
||
if (GeneralVariables.controlMode == ControlMode.VOX) {//如果当前是VOX,就改成CAT模式
|
||
GeneralVariables.controlMode = ControlMode.CAT;
|
||
}
|
||
connectRig();
|
||
|
||
if (baseRig == null) {
|
||
return;
|
||
}
|
||
baseRig.setControlMode(GeneralVariables.controlMode);
|
||
CableConnector connector = new CableConnector(context, port, GeneralVariables.baudRate
|
||
, GeneralVariables.controlMode);
|
||
baseRig.setOnRigStateChanged(onRigStateChanged);
|
||
baseRig.setConnector(connector);
|
||
connector.connect();
|
||
|
||
//晚1秒钟设置模式,防止有的电台反应不过来
|
||
new Handler().postDelayed(new Runnable() {
|
||
@Override
|
||
public void run() {
|
||
setOperationBand();//设置载波频率
|
||
}
|
||
}, 1000);
|
||
|
||
}
|
||
|
||
public void connectBluetoothRig(Context context, BluetoothDevice device) {
|
||
GeneralVariables.controlMode = ControlMode.CAT;//蓝牙控制模式,只能是CAT控制
|
||
connectRig();
|
||
if (baseRig == null) {
|
||
return;
|
||
}
|
||
baseRig.setControlMode(GeneralVariables.controlMode);
|
||
BluetoothRigConnector connector = BluetoothRigConnector.getInstance(context, device.getAddress()
|
||
, GeneralVariables.controlMode);
|
||
baseRig.setOnRigStateChanged(onRigStateChanged);
|
||
baseRig.setConnector(connector);
|
||
|
||
new Handler().postDelayed(new Runnable() {//蓝牙连接是需要时间的,等2秒再设置频率
|
||
@Override
|
||
public void run() {
|
||
setOperationBand();//设置载波频率
|
||
}
|
||
}, 5000);
|
||
}
|
||
|
||
public void connectIComWifiRig(Context context, IComWifiRig iComWifiRig) {
|
||
if (GeneralVariables.connectMode == ConnectMode.NETWORK) {
|
||
if (baseRig != null) {
|
||
if (baseRig.getConnector() != null) {
|
||
baseRig.getConnector().disconnect();
|
||
}
|
||
}
|
||
}
|
||
|
||
GeneralVariables.controlMode = ControlMode.CAT;//网络控制模式
|
||
IComWifiConnector iComWifiConnector = new IComWifiConnector(GeneralVariables.controlMode
|
||
, iComWifiRig);
|
||
iComWifiConnector.setOnWifiDataReceived(new IComWifiConnector.OnWifiDataReceived() {
|
||
@Override
|
||
public void OnWaveReceived(int bufferLen, float[] buffer) {
|
||
hamRecorder.doOnWaveDataReceived(bufferLen, buffer);
|
||
}
|
||
|
||
@Override
|
||
public void OnCivReceived(byte[] data) {
|
||
|
||
}
|
||
});
|
||
iComWifiConnector.connect();
|
||
connectRig();
|
||
|
||
baseRig.setControlMode(GeneralVariables.controlMode);
|
||
baseRig.setOnRigStateChanged(onRigStateChanged);
|
||
baseRig.setConnector(iComWifiConnector);
|
||
//
|
||
new Handler().postDelayed(new Runnable() {//蓝牙连接是需要时间的,等2秒再设置频率
|
||
@Override
|
||
public void run() {
|
||
setOperationBand();//设置载波频率
|
||
}
|
||
}, 1000);
|
||
}
|
||
|
||
/**
|
||
* 连接到flexRadio
|
||
*
|
||
* @param context context
|
||
* @param flexRadio flexRadio对象
|
||
*/
|
||
public void connectFlexRadioRig(Context context, FlexRadio flexRadio) {
|
||
if (GeneralVariables.connectMode == ConnectMode.NETWORK) {
|
||
if (baseRig != null) {
|
||
if (baseRig.getConnector() != null) {
|
||
baseRig.getConnector().disconnect();
|
||
}
|
||
}
|
||
}
|
||
GeneralVariables.controlMode = ControlMode.CAT;//网络控制模式
|
||
FlexConnector flexConnector = new FlexConnector(context, flexRadio, GeneralVariables.controlMode);
|
||
flexConnector.setOnWaveDataReceived(new FlexConnector.OnWaveDataReceived() {
|
||
@Override
|
||
public void OnDataReceived(int bufferLen, float[] buffer) {
|
||
hamRecorder.doOnWaveDataReceived(bufferLen, buffer);
|
||
}
|
||
});
|
||
flexConnector.connect();
|
||
connectRig();
|
||
|
||
baseRig.setOnRigStateChanged(onRigStateChanged);
|
||
baseRig.setConnector(flexConnector);
|
||
//
|
||
new Handler().postDelayed(new Runnable() {//连接是需要时间的,等2秒再设置频率
|
||
@Override
|
||
public void run() {
|
||
setOperationBand();//设置载波频率
|
||
}
|
||
}, 3000);
|
||
}
|
||
|
||
|
||
/**
|
||
* 根据指令集创建不同型号的电台
|
||
*/
|
||
private void connectRig() {
|
||
if ((GeneralVariables.instructionSet == InstructionSet.FLEX_NETWORK)
|
||
|| (GeneralVariables.instructionSet == InstructionSet.ICOM
|
||
&& GeneralVariables.connectMode == ConnectMode.NETWORK)) {
|
||
hamRecorder.setDataFromLan();
|
||
} else {
|
||
hamRecorder.setDataFromMic();
|
||
}
|
||
baseRig = null;
|
||
//此处判断是用什么类型的电台,ICOM,YAESU 2,YAESU 3
|
||
switch (GeneralVariables.instructionSet) {
|
||
case InstructionSet.ICOM:
|
||
baseRig = new IcomRig(GeneralVariables.civAddress);
|
||
break;
|
||
case InstructionSet.YAESU_2:
|
||
baseRig = new Yaesu2Rig();
|
||
break;
|
||
case InstructionSet.YAESU_3_9:
|
||
baseRig = new Yaesu39Rig();//yaesu3代指令,9位频率
|
||
break;
|
||
case InstructionSet.YAESU_3_8:
|
||
baseRig = new Yaesu38Rig();//yaesu3代指令,8位频率
|
||
break;
|
||
case InstructionSet.YAESU_3_450:
|
||
baseRig = new Yaesu38_450Rig();//yaesu3代指令,8位频率
|
||
break;
|
||
case InstructionSet.KENWOOD_TK90:
|
||
baseRig = new KenwoodKT90Rig();//建伍TK90
|
||
break;
|
||
case InstructionSet.YAESU_DX10:
|
||
baseRig = new YaesuDX10Rig();//YAESU DX10 DX101
|
||
break;
|
||
case InstructionSet.KENWOOD_TS590:
|
||
baseRig = new KenwoodTS590Rig();//KENWOOD TS590
|
||
break;
|
||
case InstructionSet.GUOHE_Q900:
|
||
baseRig = new GuoHeQ900Rig();//国赫Q900
|
||
break;
|
||
case InstructionSet.XIEGUG90S://协谷,USB模式
|
||
baseRig = new XieGuRig(GeneralVariables.civAddress);//协谷G90S
|
||
break;
|
||
case InstructionSet.ELECRAFT:
|
||
baseRig = new ElecraftRig();//ELECRAFT
|
||
break;
|
||
case InstructionSet.FLEX_CABLE:
|
||
baseRig = new Flex6000Rig();//FLEX6000
|
||
break;
|
||
case InstructionSet.FLEX_NETWORK:
|
||
baseRig = new FlexNetworkRig();
|
||
break;
|
||
case InstructionSet.XIEGU_6100:
|
||
baseRig = new XieGu6100Rig(GeneralVariables.civAddress);//协谷6100
|
||
break;
|
||
}
|
||
|
||
mutableIsFlexRadio.postValue(GeneralVariables.instructionSet==InstructionSet.FLEX_NETWORK);
|
||
|
||
}
|
||
|
||
|
||
/**
|
||
* 检察电台是否处于连接状态,两种情况:rigBaseClass没建立,串口没连接成功
|
||
*
|
||
* @return 是否连接
|
||
*/
|
||
public boolean isRigConnected() {
|
||
if (baseRig == null) {
|
||
return false;
|
||
} else {
|
||
return baseRig.isConnected();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取串口设备列表
|
||
*/
|
||
public void getUsbDevice() {
|
||
serialPorts =
|
||
CableSerialPort.listSerialPorts(GeneralVariables.getMainContext());
|
||
mutableSerialPorts.postValue(serialPorts);
|
||
}
|
||
|
||
|
||
public void startSco() {
|
||
AudioManager audioManager = (AudioManager) GeneralVariables.getMainContext()
|
||
.getSystemService(Context.AUDIO_SERVICE);
|
||
if (audioManager == null) return;
|
||
if (!audioManager.isBluetoothScoAvailableOffCall()) {
|
||
//蓝牙设备不支持录音
|
||
ToastMessage.show(getStringFromResource(R.string.does_not_support_recording));
|
||
return;
|
||
}
|
||
audioManager.setBluetoothScoOn(true);
|
||
audioManager.startBluetoothSco();//71毫秒
|
||
audioManager.setSpeakerphoneOn(false);//进入耳机模式
|
||
}
|
||
|
||
public void stopSco() {
|
||
AudioManager audioManager = (AudioManager) GeneralVariables.getMainContext()
|
||
.getSystemService(Context.AUDIO_SERVICE);
|
||
if (audioManager == null) return;
|
||
if (audioManager.isBluetoothScoOn()) {
|
||
audioManager.setBluetoothScoOn(false);
|
||
audioManager.stopBluetoothSco();
|
||
audioManager.setSpeakerphoneOn(true);//退出耳机模式
|
||
}
|
||
|
||
}
|
||
|
||
|
||
public void setBlueToothOn() {
|
||
AudioManager audioManager = (AudioManager) GeneralVariables.getMainContext()
|
||
.getSystemService(Context.AUDIO_SERVICE);
|
||
if (audioManager == null) return;
|
||
if (!audioManager.isBluetoothScoAvailableOffCall()) {
|
||
//蓝牙设备不支持录音
|
||
ToastMessage.show(getStringFromResource(R.string.does_not_support_recording));
|
||
}
|
||
|
||
/*
|
||
播放音乐的对应的就是MODE_NORMAL, 如果使用外放播则调用audioManager.setSpeakerphoneOn(true)即可.
|
||
若使用耳机和听筒,则需要先设置模式为MODE_IN_CALL(3.0以前)或MODE_IN_COMMUNICATION(3.0以后).
|
||
*/
|
||
audioManager.setMode(AudioManager.MODE_NORMAL);//178毫秒
|
||
audioManager.setBluetoothScoOn(true);
|
||
audioManager.stopBluetoothSco();
|
||
audioManager.startBluetoothSco();//71毫秒
|
||
audioManager.setSpeakerphoneOn(false);//进入耳机模式
|
||
|
||
//进入到蓝牙耳机模式
|
||
ToastMessage.show(getStringFromResource(R.string.bluetooth_headset_mode));
|
||
|
||
}
|
||
|
||
public void setBlueToothOff() {
|
||
|
||
AudioManager audioManager = (AudioManager) GeneralVariables.getMainContext()
|
||
.getSystemService(Context.AUDIO_SERVICE);
|
||
if (audioManager == null) return;
|
||
if (audioManager.isBluetoothScoOn()) {
|
||
audioManager.setMode(AudioManager.MODE_NORMAL);
|
||
audioManager.setBluetoothScoOn(false);
|
||
audioManager.stopBluetoothSco();
|
||
audioManager.setSpeakerphoneOn(true);//退出耳机模式
|
||
}
|
||
//离开蓝牙耳机模式
|
||
ToastMessage.show(getStringFromResource(R.string.bluetooth_Headset_mode_cancelled));
|
||
|
||
}
|
||
|
||
|
||
/**
|
||
* 查询蓝牙是否连接
|
||
*
|
||
* @return 是否
|
||
*/
|
||
@SuppressLint("MissingPermission")
|
||
public boolean isBTConnected() {
|
||
BluetoothAdapter blueAdapter = BluetoothAdapter.getDefaultAdapter();
|
||
if (blueAdapter == null) return false;
|
||
|
||
//蓝牙头戴式耳机,支持语音输入输出
|
||
int headset = blueAdapter.getProfileConnectionState(BluetoothProfile.HEADSET);
|
||
int a2dp = blueAdapter.getProfileConnectionState(BluetoothProfile.A2DP);
|
||
return headset == BluetoothAdapter.STATE_CONNECTED || a2dp == BluetoothAdapter.STATE_CONNECTED;
|
||
}
|
||
|
||
private static class GetQTHRunnable implements Runnable {
|
||
MainViewModel mainViewModel;
|
||
ArrayList<Ft8Message> messages;
|
||
public GetQTHRunnable(MainViewModel mainViewModel) {
|
||
this.mainViewModel=mainViewModel;
|
||
}
|
||
|
||
|
||
@Override
|
||
public void run() {
|
||
CallsignDatabase.getMessagesLocation(
|
||
GeneralVariables.callsignDatabase.getDb(), messages);
|
||
|
||
mainViewModel.currentDecodeCount = messages.size();
|
||
//此变量也是告诉消息列表变化的
|
||
mainViewModel.mutable_Decoded_Counter.postValue(
|
||
mainViewModel.currentDecodeCount);//告知界面消息的总数量
|
||
}
|
||
}
|
||
private static class SendWaveDataRunnable implements Runnable{
|
||
BaseRig baseRig;
|
||
float[] data;
|
||
@Override
|
||
public void run() {
|
||
if (baseRig!=null&&data!=null){
|
||
baseRig.sendWaveData(data);//实际生成的数据是12.64+0.04,0.04是生成的0数据
|
||
}
|
||
}
|
||
}
|
||
|
||
} |