kopia lustrzana https://github.com/N0BOY/FT8CN
commit
ae6ce5a2c6
Plik binarny nie jest wyświetlany.
|
@ -6,5 +6,8 @@
|
|||
<option name="m_reportAllNonLibraryCalls" value="false" />
|
||||
<option name="callCheckString" value="java.io.File,.*,java.io.InputStream,read|skip|available|markSupported,java.io.Reader,read|skip|ready|markSupported,java.lang.AbstractStringBuilder,capacity|codePointAt|codePointBefore|codePointCount|indexOf|lastIndexOf|offsetByCodePoints|substring|subSequence,java.lang.Boolean,.*,java.lang.Byte,.*,java.lang.Character,.*,java.lang.Double,.*,java.lang.Float,.*,java.lang.Integer,.*,java.lang.Long,.*,java.lang.Math,.*,java.lang.Object,equals|hashCode|toString,java.lang.Short,.*,java.lang.StrictMath,.*,java.lang.String,.*,java.lang.Thread,interrupted,java.math.BigDecimal,.*,java.math.BigInteger,.*,java.net.InetAddress,.*,java.net.URI,.*,java.nio.channels.AsynchronousChannelGroup,.*,java.util.Arrays,.*,java.util.Collections,(?!addAll).*,java.util.List,of,java.util.Map,of|ofEntries|entry,java.util.Set,of,java.util.UUID,.*,java.util.concurrent.CountDownLatch,await|getCount,java.util.concurrent.ExecutorService,awaitTermination|isShutdown|isTerminated,java.util.concurrent.ForkJoinPool,awaitQuiescence,java.util.concurrent.Semaphore,tryAcquire|availablePermits|isFair|hasQueuedThreads|getQueueLength|getQueuedThreads,java.util.concurrent.locks.Condition,await|awaitNanos|awaitUntil,java.util.concurrent.locks.Lock,tryLock|newCondition,java.util.regex.Matcher,pattern|toMatchResult|start|end|group|groupCount|matches|find|lookingAt|quoteReplacement|replaceAll|replaceFirst|regionStart|regionEnd|hasTransparentBounds|hasAnchoringBounds|hitEnd|requireEnd,java.util.regex.Pattern,.*,java.util.stream.BaseStream,.*,java.util.stream.DoubleStream,.*,java.util.stream.IntStream,.*,java.util.stream.LongStream,.*,java.util.stream.Stream,.*" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="JavadocDeclaration" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ADDITIONAL_TAGS" value="date" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
|
@ -172,4 +172,11 @@
|
|||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
<component name="VisualizationToolProject">
|
||||
<option name="state">
|
||||
<ProjectState>
|
||||
<option name="scale" value="0.027632950990615225" />
|
||||
</ProjectState>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
|
@ -22,7 +22,7 @@ android {
|
|||
minSdk 23
|
||||
targetSdk 33
|
||||
versionCode 1
|
||||
versionName '0.89'
|
||||
versionName '0.9'
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
dataBinding{
|
||||
|
@ -80,13 +80,10 @@ dependencies {
|
|||
implementation 'androidx.navigation:navigation-ui:2.4.1'
|
||||
implementation 'com.google.android.gms:play-services-maps:18.0.2'
|
||||
|
||||
// implementation 'com.google.code.gson:gson:2.7'
|
||||
implementation 'commons-net:commons-net:3.6'//用于时间同步
|
||||
implementation 'com.google.guava:guava:31.1-jre'//用于HashTable(多key的HashMap)
|
||||
|
||||
//testImplementation 'junit:junit:4.13.2'
|
||||
//androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
//androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
|
||||
|
||||
implementation files('src/libs/MPAndroidChartv_3.1.0.jar')
|
||||
implementation files('src/libs/nanohttpd-2.2.0.jar')
|
||||
|
|
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
|
@ -28,6 +28,7 @@
|
|||
android:theme="@style/Theme.Ft8CN">
|
||||
<activity
|
||||
android:name=".grid_tracker.GridTrackerMainActivity"
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.app.lib_name"
|
||||
|
|
|
@ -14,6 +14,13 @@ Please click "FAQ" if you have good suggestions or questions .
|
|||
BG7YOZ
|
||||
2022-07-01
|
||||
|
||||
2023-08-07(0.90)
|
||||
1.增加日志导入时Web界面交互模式。
|
||||
2.修正当日志数据量过大时,地图崩溃的问题。
|
||||
3.优化数据库结构,提升日志数据导入、更新速度(更新此版本前,建议备份日志以防不测)。
|
||||
4.修正部分单词拼写错误。
|
||||
5.增加电台UA3REO Wolf SDR。
|
||||
6.增加电台GUOHE(国赫) PMR-171。
|
||||
|
||||
2023-07-08(0.89)
|
||||
1.增加多重解码功能,在多重解码模式下,提高解码深度,尝试解码叠加的信号。
|
||||
|
@ -265,7 +272,8 @@ BG7YOZ
|
|||
BG7YXN,提供某型号电台用于测试。
|
||||
BG7YRB,对呼号规则运算提供帮助。
|
||||
BG8KAH,提供设备用于测试。
|
||||
BA7LVG、JE6WUD,完成日文的翻译校对工作。
|
||||
BA7LVG,完成日文的翻译校对工作。
|
||||
JE6WUD,完成日文的翻译校对工作。
|
||||
BG6RI,帮助解决日志的信号报告问题。
|
||||
SV1EEX,完成希腊文、西班牙文UI的翻译工作。
|
||||
VR2VRC,帮助修正历史呼号读取规则。
|
||||
|
@ -284,4 +292,5 @@ BG7YOZ
|
|||
BH4FTI,发现并协助对一些BUG进行调试。
|
||||
BG8BXM(M哥),为FT8CN的使用做推广,抖音和B站上有很多他的教学视频。
|
||||
BG7MFQ,为FT8CN的使用做推广,帮助测试。
|
||||
BG2EFX,提供大数据量的日志用于测试。
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ XIEGU(协谷) X6100/G90S(USB),70,19200,9
|
|||
XIEGU(协谷) X5105,70,19200,9
|
||||
XIEGU(协谷) X108,70,19200,9
|
||||
GUOHE(国赫) Q900,00,19200,8
|
||||
GUOHE(国赫) PMR-171,00,19200,8
|
||||
YAESU FT-450(D),00,4800,4
|
||||
YAESU FT-817,00,4800,1
|
||||
YAESU FT-818,00,4800,1
|
||||
|
@ -47,4 +48,6 @@ Elecraft K3S\K3\KX3\KX2,00,38400,10
|
|||
mcHF-QRP sdr,00,4800,1
|
||||
FlexRadio 6000 series,00,00,12
|
||||
FX-4CR,00,115200,7
|
||||
Qrp Labs QDX,00,9600,7
|
||||
Qrp Labs QDX,00,9600,7
|
||||
UA3REO Wolf SDR(DIGU),00,4800,15
|
||||
UA3REO Wolf SDR(USB),00,4800,16
|
|
@ -71,6 +71,7 @@ import com.bg7yoz.ft8cn.rigs.KenwoodKT90Rig;
|
|||
import com.bg7yoz.ft8cn.rigs.KenwoodTS2000Rig;
|
||||
import com.bg7yoz.ft8cn.rigs.KenwoodTS590Rig;
|
||||
import com.bg7yoz.ft8cn.rigs.OnRigStateChanged;
|
||||
import com.bg7yoz.ft8cn.rigs.Wolf_sdr_450Rig;
|
||||
import com.bg7yoz.ft8cn.rigs.XieGu6100Rig;
|
||||
import com.bg7yoz.ft8cn.rigs.XieGuRig;
|
||||
import com.bg7yoz.ft8cn.rigs.Yaesu2Rig;
|
||||
|
@ -767,6 +768,12 @@ public class MainViewModel extends ViewModel {
|
|||
case InstructionSet.KENWOOD_TS2000:
|
||||
baseRig = new KenwoodTS2000Rig();//建伍TS2000
|
||||
break;
|
||||
case InstructionSet.WOLF_SDR_DIGU:
|
||||
baseRig = new Wolf_sdr_450Rig(false);
|
||||
break;
|
||||
case InstructionSet.WOLF_SDR_USB:
|
||||
baseRig = new Wolf_sdr_450Rig(true);
|
||||
break;
|
||||
}
|
||||
|
||||
mutableIsFlexRadio.postValue(GeneralVariables.instructionSet == InstructionSet.FLEX_NETWORK);
|
||||
|
|
|
@ -164,6 +164,9 @@ public class FlexConnector extends BaseRigConnector {
|
|||
|
||||
|
||||
flexRadio.commandSetDaxAudio(1, 0, true);//打开DAX
|
||||
//todo 防止流的端口没有释放,把端口变换一下?
|
||||
//FlexRadio.streamPort++;
|
||||
|
||||
flexRadio.commandUdpPort();//设置UDP端口
|
||||
|
||||
|
||||
|
@ -176,7 +179,7 @@ public class FlexConnector extends BaseRigConnector {
|
|||
|
||||
|
||||
flexRadio.commandMeterList();//列一下仪表
|
||||
//flexRadio.commandSubMeterAll();//显示全部仪表消息
|
||||
//flexRadio.commandSubMeterAll();//此处订阅指令放到了接收响应部分
|
||||
|
||||
setMaxRfPower(maxRfPower);//设置发射功率
|
||||
setMaxTunePower(maxTunePower);//设置调谐功率
|
||||
|
@ -258,9 +261,8 @@ public class FlexConnector extends BaseRigConnector {
|
|||
|
||||
@Override
|
||||
public void sendWaveData(float[] data) {
|
||||
Log.e(TAG, "sendWaveData: flexConnector:"+data.length );
|
||||
//Log.e(TAG, "sendWaveData: flexConnector:"+data.length );
|
||||
flexRadio.sendWaveData(data);
|
||||
//super.sendWaveData(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -51,7 +51,7 @@ public class DatabaseOpr extends SQLiteOpenHelper {
|
|||
|
||||
public static DatabaseOpr getInstance(@Nullable Context context, @Nullable String databaseName) {
|
||||
if (instance == null) {
|
||||
instance = new DatabaseOpr(context, databaseName, null, 13);
|
||||
instance = new DatabaseOpr(context, databaseName, null, 14);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
@ -93,6 +93,8 @@ public class DatabaseOpr extends SQLiteOpenHelper {
|
|||
//创建SWL相关的表
|
||||
createSWLTables(sqLiteDatabase);
|
||||
|
||||
//创建索引
|
||||
createIndex(sqLiteDatabase);
|
||||
|
||||
}
|
||||
|
||||
|
@ -116,6 +118,9 @@ public class DatabaseOpr extends SQLiteOpenHelper {
|
|||
//创建SWL相关的表
|
||||
createSWLTables(sqLiteDatabase);
|
||||
|
||||
//创建索引
|
||||
createIndex(sqLiteDatabase);
|
||||
|
||||
//删除DXCC呼号列表中的等号
|
||||
//deleteDxccPrefixEqual(sqLiteDatabase);
|
||||
}
|
||||
|
@ -173,6 +178,21 @@ public class DatabaseOpr extends SQLiteOpenHelper {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查索引是不是存在
|
||||
* @param db
|
||||
* @param indexName
|
||||
* @return
|
||||
*/
|
||||
private boolean checkIndexExists(SQLiteDatabase db, String indexName) {
|
||||
Cursor cursor = db.rawQuery("select * from sqlite_master where type = 'index' and name = ?"
|
||||
, new String[]{indexName});
|
||||
if (cursor.moveToNext()) {
|
||||
cursor.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private void deleteDxccPrefixEqual(SQLiteDatabase db) {
|
||||
db.execSQL("DELETE from dxcc_prefix where prefix LIKE \"=%\"");
|
||||
}
|
||||
|
@ -385,6 +405,20 @@ public class DatabaseOpr extends SQLiteOpenHelper {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建索引,以提高导入速度
|
||||
* @param sqLiteDatabase 数据库
|
||||
*/
|
||||
private void createIndex(SQLiteDatabase sqLiteDatabase) {
|
||||
if (!checkIndexExists(sqLiteDatabase, "QslCallsigns_callsign_IDX")) {
|
||||
sqLiteDatabase.execSQL("CREATE INDEX QslCallsigns_callsign_IDX ON QslCallsigns (callsign,startTime,finishTime,mode)");
|
||||
}
|
||||
if (!checkIndexExists(sqLiteDatabase, "QSLTable_call_IDX")) {
|
||||
sqLiteDatabase.execSQL("CREATE INDEX QSLTable_call_IDX ON QSLTable (\"call\",qso_date,time_on,mode)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void loadItuDataFromFile(SQLiteDatabase db) {
|
||||
AssetManager assetManager = context.getAssets();
|
||||
InputStream inputStream;
|
||||
|
@ -818,8 +852,11 @@ public class DatabaseOpr extends SQLiteOpenHelper {
|
|||
}
|
||||
|
||||
@SuppressLint("Range")
|
||||
public boolean doInsertQSLData(QSLRecord record) {
|
||||
public boolean doInsertQSLData(QSLRecord record,AfterInsertQSLData afterInsertQSLData) {
|
||||
if (record.getToCallsign() == null) {
|
||||
if (afterInsertQSLData!=null){
|
||||
afterInsertQSLData.doAfterInsert(true,true);//说明是无效的QSL
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -892,6 +929,10 @@ public class DatabaseOpr extends SQLiteOpenHelper {
|
|||
, record.getMyCallsign()
|
||||
, record.getMyMaidenGrid()
|
||||
, record.getComment()});
|
||||
if (afterInsertQSLData!=null){
|
||||
afterInsertQSLData.doAfterInsert(false,true);//说明是新的QSL
|
||||
}
|
||||
|
||||
} else {
|
||||
if (record.isQSL) {
|
||||
db.execSQL("UPDATE QSLTable SET isQSL=? " +
|
||||
|
@ -949,6 +990,10 @@ public class DatabaseOpr extends SQLiteOpenHelper {
|
|||
, record.getTime_on()
|
||||
, record.getMode()});
|
||||
}
|
||||
|
||||
if (afterInsertQSLData!=null){
|
||||
afterInsertQSLData.doAfterInsert(false,false);//说明已经存在,需要更新的QSL
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1198,7 +1243,7 @@ public class DatabaseOpr extends SQLiteOpenHelper {
|
|||
@SuppressLint("Range")
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
databaseOpr.doInsertQSLData(qslRecord);//添加日志和通联成功的呼号
|
||||
databaseOpr.doInsertQSLData(qslRecord,null);//添加日志和通联成功的呼号
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1273,7 +1318,7 @@ public class DatabaseOpr extends SQLiteOpenHelper {
|
|||
while (cursor.moveToNext()) {
|
||||
long s = cursor.getLong(cursor.getColumnIndex("BAND")); //获取频段
|
||||
int total = cursor.getInt(cursor.getColumnIndex("c")); //获取数量
|
||||
callsigns.add(String.format("%.3fMhz \t %d", s / 1000000f, total));
|
||||
callsigns.add(String.format("%.3fMHz \t %d", s / 1000000f, total));
|
||||
sum = sum + total;
|
||||
}
|
||||
callsigns.add(String.format("-----------Total %d -----------", sum));
|
||||
|
@ -1387,7 +1432,6 @@ public class DatabaseOpr extends SQLiteOpenHelper {
|
|||
|
||||
static class GetQsoGrids extends AsyncTask<Void, Void, Void> {
|
||||
SQLiteDatabase db;
|
||||
|
||||
HashMap<String, Boolean> grids = new HashMap<>();
|
||||
OnGetQsoGrids onGetQsoGrids;
|
||||
|
||||
|
@ -1534,7 +1578,7 @@ public class DatabaseOpr extends SQLiteOpenHelper {
|
|||
limitStr="limit 100 offset "+offset;
|
||||
}
|
||||
String querySQL = "select q.[call] as callsign ,q.gridsquare as grid" +
|
||||
",q.band||\"(\"||q.freq||\" Mhz)\" as band \n" +
|
||||
",q.band||\"(\"||q.freq||\" MHz)\" as band \n" +
|
||||
",q.qso_date as last_time ,q.mode ,q.isQSL,q.isLotW_QSL\n" +
|
||||
"from QSLTable q inner join QSLTable q2 ON q.id =q2.id \n" +
|
||||
"where (q.[call] like ?)\n" +
|
||||
|
|
|
@ -147,7 +147,7 @@ public class OperationBand {
|
|||
}
|
||||
@SuppressLint("DefaultLocale")
|
||||
public String getBandInfo(){
|
||||
return String.format("%s %.3f Mhz (%s)"
|
||||
return String.format("%s %.3f MHz (%s)"
|
||||
,marked?"*":" "
|
||||
,(float)(band/1000000f)
|
||||
,waveLength);
|
||||
|
|
|
@ -34,7 +34,7 @@ public class FlexRadio {
|
|||
|
||||
|
||||
private static final String TAG = "FlexRadio";
|
||||
private static int streamPort = 7051;
|
||||
public static int streamPort = 7051;
|
||||
private int flexStreamPort = 4993;
|
||||
public boolean isPttOn = false;
|
||||
public long streamTxId = 0x084000000;
|
||||
|
@ -443,15 +443,14 @@ public class FlexRadio {
|
|||
* @param data 音频
|
||||
*/
|
||||
public void sendWaveData(float[] data) {
|
||||
float[] temp = new float[data.length * 4];
|
||||
for (int i = 0; i < data.length; i++) {//转成立体声,12000采样率转24000采样率
|
||||
temp[i * 4] = data[i];
|
||||
temp[i * 4 + 1] = data[i];
|
||||
temp[i * 4 + 2] = data[i];
|
||||
temp[i * 4 + 3] = data[i];
|
||||
float[] temp = new float[data.length * 2];
|
||||
for (int i = 0; i < data.length; i++) {//转成立体声,24000采样率
|
||||
temp[i * 2] = data[i];
|
||||
temp[i * 2 + 1] = data[i];
|
||||
}
|
||||
//port=4991;
|
||||
//streamTxId=0x084000001;
|
||||
//每5毫秒一个包?立体声,共256个float
|
||||
Log.e(TAG, String.format("sendWaveData: streamid:0x%x,ip:%s,port:%d",streamTxId,ip, port) );
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
|
@ -463,9 +462,14 @@ public class FlexRadio {
|
|||
int packetCount=0;
|
||||
while (count<temp.length){
|
||||
long now = System.currentTimeMillis() - 1;//获取当前时间
|
||||
float[] voice=new float[64];
|
||||
for (int j = 0; j <3 ; j++) {
|
||||
for (int i = 0; i < 64; i++) {
|
||||
|
||||
|
||||
|
||||
float[] voice=new float[256];//因为是立体声,240*2
|
||||
|
||||
|
||||
//for (int j = 0; j <3 ; j++) {
|
||||
for (int i = 0; i < voice.length; i++) {
|
||||
voice[i] = temp[count];
|
||||
count++;
|
||||
if (count > temp.length) break;
|
||||
|
@ -479,14 +483,14 @@ public class FlexRadio {
|
|||
throw new RuntimeException(e);
|
||||
}
|
||||
if (count>temp.length) break;
|
||||
}
|
||||
//}
|
||||
while (isPttOn) {
|
||||
if (System.currentTimeMillis() - now >= 41) {//40毫秒一个周期,每个周期3个包,每个包64个float。
|
||||
if (System.currentTimeMillis() - now >= 5) {//5毫秒一个周期,每个周期256个float。
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isPttOn){
|
||||
Log.e(TAG, String.format("count:%d,temp.length:%d",count,temp.length ));
|
||||
// Log.e(TAG, String.format("count:%d,temp.length:%d",count,temp.length ));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -531,6 +535,7 @@ public class FlexRadio {
|
|||
}
|
||||
return s.toString();
|
||||
}
|
||||
@SuppressLint("DefaultLocale")
|
||||
public static String floatToStr(float[] data) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
|
@ -815,7 +820,7 @@ public class FlexRadio {
|
|||
@SuppressLint("DefaultLocale")
|
||||
public synchronized void commandStreamCreateDaxTx(int channel) {
|
||||
//sendCommand(FlexCommand.STREAM_CREATE_DAX_TX, String.format("stream create type=dax_tx dax_channel=%d", channel));
|
||||
//sendCommand(FlexCommand.STREAM_CREATE_DAX_TX, String.format("stream create type=dax_tx compression=none"));
|
||||
// sendCommand(FlexCommand.STREAM_CREATE_DAX_TX, String.format("stream create type=dax_tx compression=none"));
|
||||
sendCommand(FlexCommand.STREAM_CREATE_DAX_TX, String.format("stream create type=remote_audio_tx"));
|
||||
}
|
||||
|
||||
|
|
|
@ -43,18 +43,6 @@ public class RadioUdpClient {
|
|||
sendDataRunnable.address=address;
|
||||
sendDataRunnable.port=port;
|
||||
sendDataThreadPool.execute(sendDataRunnable);
|
||||
// new Thread(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
|
||||
// try {
|
||||
// sendSocket.send(packet);
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// Log.e(TAG, "run: " + e.getMessage());
|
||||
// }
|
||||
// }
|
||||
// }).start();
|
||||
}
|
||||
|
||||
private static class SendDataRunnable implements Runnable{
|
||||
|
@ -88,7 +76,7 @@ public class RadioUdpClient {
|
|||
if (activated) {//通过activated判断是否结束接收线程,并清空sendSocket指针
|
||||
sendSocket = new DatagramSocket(null);//绑定的端口号随机
|
||||
sendSocket.bind(new InetSocketAddress(port));
|
||||
Log.e(TAG, "openUdpPort: "+sendSocket.getLocalPort());
|
||||
// Log.e(TAG, "openUdpPort: "+sendSocket.getLocalPort());
|
||||
receiveData();
|
||||
}else {
|
||||
if (sendSocket!=null){
|
||||
|
|
|
@ -111,6 +111,13 @@ public class FT8SignalListener {
|
|||
|
||||
public void decodeFt8(long utc, float[] voiceData) {
|
||||
|
||||
//此处是测试用代码-------------------------
|
||||
// String fileName = getCacheFileName("test_01.wav");
|
||||
// Log.e(TAG, "onClick: fileName:" + fileName);
|
||||
// WaveFileReader reader = new WaveFileReader(fileName);
|
||||
// int data[][] = reader.getData();
|
||||
//----------------------------------------------------------
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -119,17 +126,20 @@ public class FT8SignalListener {
|
|||
onFt8Listen.beforeListen(utc);
|
||||
}
|
||||
|
||||
|
||||
// float[] tempData = ints2floats(data);
|
||||
|
||||
|
||||
///读入音频数据,并做预处理
|
||||
//其实这种方式要注意一个问题,在一个周期之内,必须解码完毕,否则新的解码又要开始了
|
||||
long ft8Decoder = InitDecoder(utc, FT8Common.SAMPLE_RATE
|
||||
, voiceData.length, true);
|
||||
// , tempData.length, true);
|
||||
DecoderMonitorPressFloat(voiceData, ft8Decoder);//读入音频数据
|
||||
// DecoderMonitorPressFloat(tempData, ft8Decoder);//读入音频数据
|
||||
|
||||
|
||||
ArrayList<Ft8Message> allMsg = new ArrayList<>();
|
||||
// ArrayList<Ft8Message> msgs = runDecode(utc, voiceData,false);
|
||||
ArrayList<Ft8Message> msgs = runDecode(ft8Decoder, utc, false);
|
||||
addMsgToList(allMsg, msgs);
|
||||
timeSec = System.currentTimeMillis() - time;
|
||||
|
@ -140,6 +150,7 @@ public class FT8SignalListener {
|
|||
|
||||
|
||||
if (GeneralVariables.deepDecodeMode) {//进入深度解码模式
|
||||
//float[] newSignal=tempData;
|
||||
msgs = runDecode(ft8Decoder, utc, true);
|
||||
addMsgToList(allMsg, msgs);
|
||||
timeSec = System.currentTimeMillis() - time;
|
||||
|
@ -274,14 +285,34 @@ public class FT8SignalListener {
|
|||
super.finalize();
|
||||
}
|
||||
|
||||
|
||||
public OnWaveDataListener getOnWaveDataListener() {
|
||||
return onWaveDataListener;
|
||||
}
|
||||
|
||||
public void setOnWaveDataListener(OnWaveDataListener onWaveDataListener) {
|
||||
this.onWaveDataListener = onWaveDataListener;
|
||||
}
|
||||
|
||||
|
||||
public String getCacheFileName(String fileName) {
|
||||
return GeneralVariables.getMainContext().getCacheDir() + "/" + fileName;
|
||||
}
|
||||
|
||||
public float[] ints2floats(int data[][]) {
|
||||
float temp[] = new float[data[0].length];
|
||||
for (int i = 0; i < data[0].length; i++) {
|
||||
temp[i] = data[0][i] / 32768.0f;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
public int[] floats2ints(float data[]) {
|
||||
int temp[] = new int[data.length];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
temp[i] = (int) (data[i] * 32767.0f);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解码的第一步,初始化解码器,获取解码器的地址。
|
||||
|
|
|
@ -280,8 +280,10 @@ public class GridOsmMapView {
|
|||
* @return 图层
|
||||
*/
|
||||
public GridPolygon getGridPolygon(String grid) {
|
||||
for (GridPolygon polygon : gridPolygons) {
|
||||
if (polygon.grid.equals(grid)) return polygon;
|
||||
synchronized (gridPolygons) {
|
||||
for (GridPolygon polygon : gridPolygons) {
|
||||
if (polygon.grid.equals(grid)) return polygon;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -380,13 +382,18 @@ public class GridOsmMapView {
|
|||
*/
|
||||
public synchronized GridPolygon addGridPolygon(String grid, GridMode gridMode) {
|
||||
if (gridMapView == null) return null;
|
||||
//here, we create a polygon using polygon class, note that you need 4 points in order to make a rectangle
|
||||
GridPolygon polygon = new GridPolygon(context, gridMapView, grid, gridMode);
|
||||
if (gridMapView.getRepository()==null) return null;
|
||||
try {//当日志量过多时,会出现闪退的问题,在此处做一个异常捕获,防止闪退
|
||||
|
||||
gridPolygons.add(polygon);
|
||||
gridMapView.getOverlays().add(polygon);
|
||||
GridPolygon polygon = new GridPolygon(context, gridMapView, grid, gridMode);
|
||||
gridPolygons.add(polygon);
|
||||
gridMapView.getOverlays().add(polygon);
|
||||
return polygon;
|
||||
|
||||
return polygon;
|
||||
} catch (Exception e) {
|
||||
//throw new RuntimeException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -689,40 +696,40 @@ public class GridOsmMapView {
|
|||
this.grid = grid;
|
||||
this.gridMode = gridMode;
|
||||
this.context = context;
|
||||
//infoWindow=new BasicInfoWindow(R.layout.tracker_grid_info_win,mapView);
|
||||
//this.details = details;
|
||||
|
||||
setTitle(grid);
|
||||
//setSubDescription(details);
|
||||
setStrokeWidth(3f);
|
||||
setStrokeColor(this.context.getColor(R.color.osm_grid_out_line_color));
|
||||
//setSnippet("445534343");
|
||||
|
||||
updateGridMode();
|
||||
|
||||
ArrayList<GeoPoint> pts = LatLngs2GeoPoints(MaidenheadGrid.gridToPolygon(grid));
|
||||
setPoints(pts);
|
||||
|
||||
|
||||
setVisible(true);
|
||||
|
||||
}
|
||||
|
||||
public void updateGridMode() {
|
||||
switch (gridMode) {
|
||||
case QSL:
|
||||
setFillColor(this.context.getColor(R.color.tracker_sample_qsl_color));
|
||||
break;
|
||||
case QSO:
|
||||
setFillColor(this.context.getColor(R.color.tracker_sample_qso_color));
|
||||
break;
|
||||
case QSX:
|
||||
setFillColor(this.context.getColor(R.color.tracker_sample_qsx_color));
|
||||
break;
|
||||
public synchronized void updateGridMode() {
|
||||
synchronized (this) {//防止闪退
|
||||
switch (gridMode) {
|
||||
case QSL:
|
||||
this.mFillPaint.setColor(this.context.getColor(R.color.tracker_sample_qsl_color));
|
||||
//setFillColor(this.context.getColor(R.color.tracker_sample_qsl_color));
|
||||
break;
|
||||
case QSO:
|
||||
this.mFillPaint.setColor(this.context.getColor(R.color.tracker_sample_qso_color));
|
||||
//setFillColor(this.context.getColor(R.color.tracker_sample_qso_color));
|
||||
break;
|
||||
case QSX:
|
||||
this.mFillPaint.setColor(this.context.getColor(R.color.tracker_sample_qsx_color));
|
||||
//setFillColor(this.context.getColor(R.color.tracker_sample_qsx_color));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void upgradeGridMode(GridMode mode) {
|
||||
public synchronized void upgradeGridMode(GridMode mode) {
|
||||
if (mode.ordinal() > gridMode.ordinal()) {
|
||||
gridMode = mode;
|
||||
updateGridMode();
|
||||
|
|
|
@ -10,6 +10,7 @@ import android.animation.Animator;
|
|||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.graphics.Canvas;
|
||||
|
@ -21,6 +22,7 @@ import android.os.Bundle;
|
|||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
@ -28,6 +30,7 @@ import android.view.WindowManager;
|
|||
import android.view.animation.AnimationUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
@ -127,11 +130,11 @@ public class GridTrackerMainActivity extends AppCompatActivity {
|
|||
//设置深色模式
|
||||
getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||
|
||||
//setContentView(R.layout.activity_grid_tracker_main);
|
||||
//全屏
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN
|
||||
, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//设定为横屏
|
||||
|
||||
|
||||
mainViewModel = MainViewModel.getInstance(this);
|
||||
binding = ActivityGridTrackerMainBinding.inflate(getLayoutInflater());
|
||||
|
||||
|
@ -187,30 +190,6 @@ public class GridTrackerMainActivity extends AppCompatActivity {
|
|||
@SuppressLint({"DefaultLocale", "NotifyDataSetChanged"})
|
||||
@Override
|
||||
public void onChanged(Integer integer) {
|
||||
// callingListAdapter.notifyDataSetChanged();
|
||||
//当列表下部稍微多出一些,自动上移
|
||||
// if (callMessagesRecyclerView.computeVerticalScrollRange()
|
||||
// - callMessagesRecyclerView.computeVerticalScrollExtent()
|
||||
// - callMessagesRecyclerView.computeVerticalScrollOffset() < 500) {
|
||||
// callMessagesRecyclerView.scrollToPosition(callingListAdapter.getItemCount() - 1);
|
||||
// }
|
||||
// if (mainViewModel.currentMessages != null) {
|
||||
//
|
||||
// ToastMessage.show(String.format(GeneralVariables.getStringFromResource(
|
||||
// R.string.tracker_decoded_new)
|
||||
// , mainViewModel.currentDecodeCount)
|
||||
// + " " + String.format(
|
||||
// getString(R.string.decoding_takes_milliseconds)
|
||||
// , mainViewModel.ft8SignalListener.decodeTimeSec.getValue()));
|
||||
// //画电台之间的连线
|
||||
// //对CQ的电台打点
|
||||
// gridOsmMapView.clearLines();
|
||||
// gridOsmMapView.clearMarkers();
|
||||
// for (Ft8Message msg : mainViewModel.currentMessages) {
|
||||
// drawMessage(msg);//在地图上画每一个消息
|
||||
// }
|
||||
// gridOsmMapView.showInfoWindows();
|
||||
// }
|
||||
}
|
||||
});
|
||||
mainViewModel.mutableIsDecoding.observe(this, new Observer<Boolean>() {
|
||||
|
@ -329,7 +308,6 @@ public class GridTrackerMainActivity extends AppCompatActivity {
|
|||
|
||||
//获取曾经通联过的网格
|
||||
mainViewModel.databaseOpr.getQsoGridQuery(new DatabaseOpr.OnGetQsoGrids() {
|
||||
//ConcurrentHashMap
|
||||
@Override
|
||||
public void onAfterQuery(HashMap<String, Boolean> grids) {
|
||||
for (Map.Entry<String, Boolean> entry : grids.entrySet()) {
|
||||
|
@ -377,6 +355,7 @@ public class GridTrackerMainActivity extends AppCompatActivity {
|
|||
setContentView(binding.getRoot());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 在地图上画消息,包括收发消息和CQ消息
|
||||
*
|
||||
|
|
|
@ -18,6 +18,7 @@ import com.bg7yoz.ft8cn.MainViewModel;
|
|||
import com.bg7yoz.ft8cn.R;
|
||||
import com.bg7yoz.ft8cn.connector.CableSerialPort;
|
||||
import com.bg7yoz.ft8cn.connector.ConnectMode;
|
||||
import com.bg7yoz.ft8cn.database.AfterInsertQSLData;
|
||||
import com.bg7yoz.ft8cn.database.ControlMode;
|
||||
import com.bg7yoz.ft8cn.database.RigNameList;
|
||||
import com.bg7yoz.ft8cn.log.LogFileImport;
|
||||
|
@ -42,6 +43,8 @@ public class LogHttpServer extends NanoHTTPD {
|
|||
public static int DEFAULT_PORT = 7050;
|
||||
private static final String TAG = "LOG HTTP";
|
||||
|
||||
private ImportTaskList importTaskList = new ImportTaskList();//导如日志的任务列表
|
||||
|
||||
|
||||
public LogHttpServer(MainViewModel viewModel, int port) {
|
||||
super(port);
|
||||
|
@ -100,6 +103,10 @@ public class LogHttpServer extends NanoHTTPD {
|
|||
msg = HTML_STRING(showQSLTable());
|
||||
} else if (uri.equalsIgnoreCase("IMPORTLOG")) {
|
||||
msg = HTML_STRING(showImportLog());
|
||||
} else if (uri.equalsIgnoreCase("GETIMPORTTASK")) {//这个是用户实时获取导入状态的URI
|
||||
msg = HTML_STRING(makeGetImportTaskHTML(session));
|
||||
} else if (uri.equalsIgnoreCase("CANCELTASK")) {//这个是用户取消导入的URI
|
||||
msg = HTML_STRING(doCancelImport(session));
|
||||
} else if (uri.equalsIgnoreCase("IMPORTLOGDATA")) {
|
||||
msg = HTML_STRING(doImportLogFile(session));
|
||||
} else if (uri.equalsIgnoreCase("SHOWALLQSL")) {
|
||||
|
@ -159,35 +166,27 @@ public class LogHttpServer extends NanoHTTPD {
|
|||
//Map<String, String> header = session.getHeaders();
|
||||
try {
|
||||
session.parseBody(files);
|
||||
|
||||
Log.e(TAG, "doImportLogFile: information:" + files.toString());
|
||||
String param = files.get("file1");//这个是post或put文件的key
|
||||
LogFileImport logFileImport = new LogFileImport(param);
|
||||
|
||||
ArrayList<HashMap<String, String>> recordList = logFileImport.getLogRecords();
|
||||
int importCount = 0;
|
||||
int recordCount = 0;
|
||||
for (HashMap<String, String> record : recordList) {
|
||||
QSLRecord qslRecord = new QSLRecord(record);
|
||||
recordCount++;
|
||||
if (mainViewModel.databaseOpr.doInsertQSLData(qslRecord)) {
|
||||
importCount++;
|
||||
ImportTaskList.ImportTask task = importTaskList.addTask(param.hashCode());//生成一个新的任务
|
||||
|
||||
LogFileImport logFileImport = new LogFileImport(task, param);
|
||||
|
||||
|
||||
//把提交的数据放到一个独立的线程运行,防止WEB页面停留太久
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
doImportADI(task, logFileImport);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
StringBuilder temp = new StringBuilder();
|
||||
temp.append(String.format(GeneralVariables.getStringFromResource(R.string.html_import_count) + "<br>"
|
||||
, recordCount, importCount, logFileImport.getErrorCount()));
|
||||
if (logFileImport.getErrorCount() > 0) {
|
||||
temp.append("<table>");
|
||||
temp.append(String.format("<tr><th></th><th>%d malformed logs</th></tr>\n", logFileImport.getErrorCount()));
|
||||
for (int key : logFileImport.getErrorLines().keySet()) {
|
||||
temp.append(String.format("<tr><td><pre>%d</pre></td><td><pre >%s</pre></td></tr>\n"
|
||||
, key, logFileImport.getErrorLines().get(key)));
|
||||
}
|
||||
//重定向,跳转到实时导入信息界面
|
||||
return String.format("<head>\n<meta http-equiv=\"Refresh\" content=\"0; URL=getImportTask?session=%d\" /></head><body></body>"
|
||||
, param.hashCode());
|
||||
|
||||
temp.append("</table>");
|
||||
}
|
||||
mainViewModel.databaseOpr.getQslDxccToMap();//更新一下已经通联的分区
|
||||
return temp.toString();
|
||||
} catch (IOException | ResponseException e) {
|
||||
e.printStackTrace();
|
||||
return String.format(GeneralVariables.getStringFromResource(R.string.html_import_failed)
|
||||
|
@ -197,6 +196,93 @@ public class LogHttpServer extends NanoHTTPD {
|
|||
return GeneralVariables.getStringFromResource(R.string.html_illegal_command);
|
||||
}
|
||||
|
||||
|
||||
private String makeGetImportTaskHTML(IHTTPSession session) {
|
||||
String script = "";
|
||||
script = "\n<script language=\"JavaScript\">\n" +
|
||||
"function refreshTask(){\n" +
|
||||
"window.location.reload();\n" +
|
||||
"}\n" +
|
||||
"setTimeout('refreshTask()',1000);\n" +
|
||||
" </script>\n";
|
||||
Map<String, String> pars = session.getParms();
|
||||
if (pars.get("session") != null) {
|
||||
String s = Objects.requireNonNull(pars.get("session"));
|
||||
int id = Integer.parseInt(s);
|
||||
if (!importTaskList.checkTaskIsRunning(id)) {//如果任务停止,就没有必要刷新了
|
||||
script = "";
|
||||
}
|
||||
return script + importTaskList.getTaskHTML(id);
|
||||
}
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private String doCancelImport(IHTTPSession session) {
|
||||
Map<String, String> pars = session.getParms();
|
||||
Log.e(TAG, "doCancelImport: " + pars.toString());
|
||||
if (pars.get("session") != null) {
|
||||
String s = Objects.requireNonNull(pars.get("session"));
|
||||
int id = Integer.parseInt(s);
|
||||
importTaskList.cancelTask(id);
|
||||
return String.format("<head>\n<meta http-equiv=\"Refresh\" content=\"0; URL=getImportTask?session=%d\" /></head><body></body>"
|
||||
, id);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private void doImportADI(ImportTaskList.ImportTask task, LogFileImport logFileImport) {
|
||||
task.setStatus(ImportTaskList.ImportState.IMPORTING);
|
||||
ArrayList<HashMap<String, String>> recordList = logFileImport.getLogRecords();//以正则表达式:[<][Ee][Oo][Rr][>]分行
|
||||
task.importedCount = 0;
|
||||
task.count = recordList.size();//总行数
|
||||
for (HashMap<String, String> record : recordList) {
|
||||
if (task.status == ImportTaskList.ImportState.CANCELED) break;//检查是不是取消导入
|
||||
|
||||
QSLRecord qslRecord = new QSLRecord(record);
|
||||
task.processCount++;
|
||||
if (mainViewModel.databaseOpr.doInsertQSLData(qslRecord, new AfterInsertQSLData() {
|
||||
@Override
|
||||
public void doAfterInsert(boolean isInvalid, boolean isNewQSL) {
|
||||
if (isInvalid) {
|
||||
task.invalidCount++;
|
||||
return;
|
||||
}
|
||||
if (isNewQSL) {
|
||||
task.newCount++;
|
||||
} else {
|
||||
task.updateCount++;
|
||||
}
|
||||
}
|
||||
})) {
|
||||
task.importedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//此处是显示错误的数据
|
||||
StringBuilder temp = new StringBuilder();
|
||||
if (logFileImport.getErrorCount() > 0) {
|
||||
temp.append("<table>");
|
||||
temp.append(String.format("<tr><th></th><th>%d malformed logs</th></tr>\n", logFileImport.getErrorCount()));
|
||||
for (int key : logFileImport.getErrorLines().keySet()) {
|
||||
temp.append(String.format("<tr><td><pre>%d</pre></td><td><pre >%s</pre></td></tr>\n"
|
||||
, key, logFileImport.getErrorLines().get(key)));
|
||||
}
|
||||
|
||||
temp.append("</table>");
|
||||
}
|
||||
|
||||
task.errorMsg = temp.toString();
|
||||
if (task.status!= ImportTaskList.ImportState.CANCELED) {
|
||||
task.setStatus(ImportTaskList.ImportState.FINISHED);
|
||||
}
|
||||
mainViewModel.databaseOpr.getQslDxccToMap();//更新一下已经通联的分区
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取配置信息
|
||||
*
|
||||
|
@ -1014,10 +1100,11 @@ public class LogHttpServer extends NanoHTTPD {
|
|||
|
||||
/**
|
||||
* 把swo的QSO日志导出到文件
|
||||
*
|
||||
* @param exportFile 文件名
|
||||
* @param callsign 呼号
|
||||
* @param callsign 呼号
|
||||
* @param start_date 起始日期
|
||||
* @param end_date 结束日期
|
||||
* @param end_date 结束日期
|
||||
* @return 数据
|
||||
*/
|
||||
@SuppressLint("Range")
|
||||
|
@ -1078,6 +1165,7 @@ public class LogHttpServer extends NanoHTTPD {
|
|||
|
||||
/**
|
||||
* 查询SWL日志
|
||||
*
|
||||
* @param session 会话
|
||||
* @return html
|
||||
*/
|
||||
|
@ -1263,10 +1351,11 @@ public class LogHttpServer extends NanoHTTPD {
|
|||
|
||||
/**
|
||||
* 把QSO日志导出到文件
|
||||
*
|
||||
* @param exportFile 文件名
|
||||
* @param callsign 呼号
|
||||
* @param callsign 呼号
|
||||
* @param start_date 起始日期
|
||||
* @param end_date 结束日期
|
||||
* @param end_date 结束日期
|
||||
* @return 数据
|
||||
*/
|
||||
@SuppressLint("Range")
|
||||
|
@ -1317,6 +1406,7 @@ public class LogHttpServer extends NanoHTTPD {
|
|||
|
||||
/**
|
||||
* 查询QSO日志
|
||||
*
|
||||
* @param session 会话
|
||||
* @return html
|
||||
*/
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.bg7yoz.ft8cn.log;
|
|||
|
||||
import android.util.Log;
|
||||
|
||||
import com.bg7yoz.ft8cn.html.ImportTaskList;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -22,6 +24,7 @@ public class LogFileImport {
|
|||
private static final String TAG = "LogFileImport";
|
||||
private final String fileContext;
|
||||
private final HashMap<Integer,String> errorLines=new HashMap<>();
|
||||
private ImportTaskList.ImportTask importTask;
|
||||
|
||||
/**
|
||||
* 构建函数,需要文件名,如果在读取文件时出错,会回抛异常
|
||||
|
@ -29,7 +32,8 @@ public class LogFileImport {
|
|||
* @param logFileName 日志文件名
|
||||
* @throws IOException 回抛异常
|
||||
*/
|
||||
public LogFileImport(String logFileName) throws IOException {
|
||||
public LogFileImport(ImportTaskList.ImportTask task, String logFileName) throws IOException {
|
||||
importTask=task;
|
||||
FileInputStream logFileStream = new FileInputStream(logFileName);
|
||||
byte[] bytes = new byte[logFileStream.available()];
|
||||
logFileStream.read(bytes);
|
||||
|
@ -99,6 +103,7 @@ public class LogFileImport {
|
|||
records.add(record);//保存记录
|
||||
}catch (Exception e){
|
||||
errorLines.put(count,s.replace("<","<"));//把错误的内容保存下来。
|
||||
importTask.readErrorCount=errorLines.size();
|
||||
}
|
||||
}
|
||||
return records;
|
||||
|
|
|
@ -48,6 +48,9 @@ public class QSLRecord {
|
|||
|
||||
public boolean saved = false;//是否被保存到数据库中
|
||||
|
||||
public boolean isInvalid=false;//是否解析出错
|
||||
public String errorMSG="";//如果解析出错,错误的消息
|
||||
|
||||
/**
|
||||
* 用于SWL QSO记录,记录SWL QSO的条件是收听到双方的信号报告
|
||||
*
|
||||
|
@ -137,6 +140,8 @@ public class QSLRecord {
|
|||
float freq = Float.parseFloat(Objects.requireNonNull(map.get("FREQ")));
|
||||
bandFreq = Math.round(freq * 1000000);
|
||||
} catch (NumberFormatException e) {
|
||||
isInvalid=true;
|
||||
errorMSG="freq:"+e.getMessage();
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "QSLRecord: freq" + e.getMessage());
|
||||
}
|
||||
|
@ -193,6 +198,8 @@ public class QSLRecord {
|
|||
try {//要把float转成Long
|
||||
receivedReport = Integer.parseInt(Objects.requireNonNull(map.get("RST_RCVD").trim()));
|
||||
} catch (NumberFormatException e) {
|
||||
isInvalid=true;
|
||||
errorMSG="RST_RCVD:"+e.getMessage();
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "QSLRecord: RST_RCVD:" + e.getMessage());
|
||||
}
|
||||
|
@ -204,6 +211,8 @@ public class QSLRecord {
|
|||
try {//要把float转成Long
|
||||
sendReport = Integer.parseInt(Objects.requireNonNull(map.get("RST_SENT").trim()));
|
||||
} catch (NumberFormatException e) {
|
||||
isInvalid=true;
|
||||
errorMSG="RST_SENT:"+e.getMessage();
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "QSLRecord: RST_SENT:" + e.getMessage());
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import android.annotation.SuppressLint;
|
|||
public class BaseRigOperation {
|
||||
@SuppressLint("DefaultLocale")
|
||||
public static String getFrequencyStr(long freq) {
|
||||
return String.format("%d.%03dMhz", freq / 1000000, (freq % 1000000) / 1000);
|
||||
return String.format("%d.%03dMHz", freq / 1000000, (freq % 1000000) / 1000);
|
||||
}
|
||||
/**
|
||||
* 检查是不是在WSPR2的频段内
|
||||
|
|
|
@ -4,15 +4,18 @@ import android.annotation.SuppressLint;
|
|||
import android.util.Log;
|
||||
|
||||
import com.bg7yoz.ft8cn.Ft8Message;
|
||||
import com.bg7yoz.ft8cn.GeneralVariables;
|
||||
import com.bg7yoz.ft8cn.connector.FlexConnector;
|
||||
import com.bg7yoz.ft8cn.flex.FlexCommand;
|
||||
import com.bg7yoz.ft8cn.flex.FlexRadio;
|
||||
import com.bg7yoz.ft8cn.ft8transmit.GenerateFT8;
|
||||
|
||||
public class FlexNetworkRig extends BaseRig{
|
||||
private static final String TAG="FlexNetworkRig";
|
||||
public class FlexNetworkRig extends BaseRig {
|
||||
private static final String TAG = "FlexNetworkRig";
|
||||
private int commandSeq = 1;//指令的序列
|
||||
private FlexCommand flexCommand;
|
||||
private String commandStr;
|
||||
|
||||
//private final int ctrAddress=0xE0;//接收地址,默认0xE0;电台回复命令有时也可以是0x00
|
||||
//private byte[] dataBuffer=new byte[0];//数据缓冲区
|
||||
@SuppressLint("DefaultLocale")
|
||||
|
@ -31,10 +34,12 @@ public class FlexNetworkRig extends BaseRig{
|
|||
public synchronized void commandSliceTune(int sliceOder, String freq) {
|
||||
sendCommand(FlexCommand.SLICE_TUNE, String.format("slice t %d %s", sliceOder, freq));
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
public synchronized void commandSliceSetMode(int sliceOder, FlexRadio.FlexMode mode) {
|
||||
sendCommand(FlexCommand.SLICE_SET_TX_ANT, String.format("slice s %d mode=%s", sliceOder, mode.toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPTT(boolean on) {
|
||||
getConnector().setPttOn(on);
|
||||
|
@ -43,7 +48,7 @@ public class FlexNetworkRig extends BaseRig{
|
|||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
if (getConnector()==null) {
|
||||
if (getConnector() == null) {
|
||||
return false;
|
||||
}
|
||||
return getConnector().isConnected();
|
||||
|
@ -51,7 +56,7 @@ public class FlexNetworkRig extends BaseRig{
|
|||
|
||||
@Override
|
||||
public void setUsbModeToRig() {
|
||||
if (getConnector()!=null){
|
||||
if (getConnector() != null) {
|
||||
commandSliceSetMode(0, FlexRadio.FlexMode.DIGU);//设置操作模式
|
||||
}
|
||||
}
|
||||
|
@ -59,13 +64,12 @@ public class FlexNetworkRig extends BaseRig{
|
|||
@SuppressLint("DefaultLocale")
|
||||
@Override
|
||||
public void setFreqToRig() {
|
||||
if (getConnector()!=null){
|
||||
commandSliceTune(0,String.format("%.3f", getFreq()/1000000f));
|
||||
if (getConnector() != null) {
|
||||
commandSliceTune(0, String.format("%.3f", getFreq() / 1000000f));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void onReceiveData(byte[] data) {
|
||||
//ToastMessage.show("--"+byteToStr(data));
|
||||
|
@ -74,18 +78,23 @@ public class FlexNetworkRig extends BaseRig{
|
|||
|
||||
@Override
|
||||
public void readFreqFromRig() {
|
||||
if (getConnector()!=null){
|
||||
if (getConnector() != null) {
|
||||
//getConnector().sendData(IcomRigConstant.setReadFreq(ctrAddress, getCivAddress()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendWaveData(Ft8Message message) {
|
||||
// Log.e(TAG, "sendWaveData: "+data.length );
|
||||
// if (getConnector()!=null){
|
||||
// getConnector().sendWaveData(data);
|
||||
// }
|
||||
|
||||
if (getConnector() != null) {
|
||||
float[] data = GenerateFT8.generateFt8(message, GeneralVariables.getBaseFrequency()
|
||||
, 24000);//flex音频的采样率是24000,todo 此处可改为动态设置24000,48000
|
||||
if (data == null) {
|
||||
setPTT(false);
|
||||
return;
|
||||
}
|
||||
getConnector().sendWaveData(data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,4 +16,7 @@ public class InstructionSet {
|
|||
public static final int FLEX_NETWORK=12;//FLEX网络模式连接;
|
||||
public static final int XIEGU_6100=13;//协谷X6100;
|
||||
public static final int KENWOOD_TS2000=14;//建武TS2000,发射指令是TX0;
|
||||
public static final int WOLF_SDR_DIGU=15;//UA3REO Wolf SDR,DIG-U模式,兼容YAESU 450D;
|
||||
public static final int WOLF_SDR_USB=16;//UA3REO Wolf SDR,USB模式,兼容YAESU 450D;
|
||||
|
||||
}
|
||||
|
|
|
@ -472,7 +472,18 @@
|
|||
<string name="deep_mode">Λειτουργία πολλαπλής αποκωδικοποίησης</string>
|
||||
<string name="export_null">Παρακαλώ χρησιμοποιήστε τον web browser των άλλων συσκευών για εξαγωγή στο παρασκήνιο στο ίδιο LAN που είναι αυτή η συσκευή.\nPlease connect to a valid Wi-Fi</string>
|
||||
<string name="deep_mode_help">decode_help_en.txt</string>
|
||||
<string name="null_task_html">Το έργο δεν υπάρχει!</string>
|
||||
<string name="log_importing_html">Εισαγωγή...</string>
|
||||
<string name="log_import_finished_html">Τελειώσει!</string>
|
||||
<string name="import_read_error_count_html">Error lines: %d</string>
|
||||
<string name="import_new_count_html">Append QSLs: %d</string>
|
||||
<string name="import_update_count_html">Update QSLs: %d</string>
|
||||
<string name="import_invalid_count_html">Invalid QSLs: %d</string>
|
||||
<string name="import_progress_html">"Progress: "</string>
|
||||
<string name="import_readed_html">Validated QSL: %d</string>
|
||||
<string name="import_canceled_html">Canceled!</string>
|
||||
<string name="import_cancel_button">Stop</string>
|
||||
|
||||
<!-- <string name="hello_blank_fragment">Hello blank fragment</string>-->
|
||||
<!-- <string name="hello_blank_fragment">Hello blank fragment</string>-->
|
||||
|
||||
</resources>
|
|
@ -166,7 +166,7 @@
|
|||
<string name="log_manual_confirmation">Confirmación manual (%s)</string>
|
||||
|
||||
<!-- QSL日志列表-->
|
||||
<string name="qsl_grid">Gird:%s</string>
|
||||
<string name="qsl_grid">Grid:%s</string>
|
||||
<string name="qsl_start_time">Hora de inicio : %s</string>
|
||||
<string name="qsl_end_time">Hora de finalización: %s</string>
|
||||
<string name="qsl_rst_rcvd">Rst recibido : %s</string>
|
||||
|
@ -472,6 +472,17 @@
|
|||
<string name="deep_mode">Modo de decodificación múltiple</string>
|
||||
<string name="export_null">Utilice el navegador web de otros dispositivos para exportar desde el fondo en la misma LAN que este dispositivo.\nPlease connect to a valid Wi-Fi</string>
|
||||
<string name="deep_mode_help">decode_help_en.txt</string>
|
||||
<!-- <string name="hello_blank_fragment">Hello blank fragment</string>-->
|
||||
<string name="null_task_html">¡La tarea no existe!</string>
|
||||
<string name="log_importing_html">Importador...</string>
|
||||
<string name="log_import_finished_html">¡Terminado!</string>
|
||||
<string name="import_read_error_count_html">Error lines: %d</string>
|
||||
<string name="import_new_count_html">Append QSLs: %d</string>
|
||||
<string name="import_update_count_html">Update QSLs: %d</string>
|
||||
<string name="import_invalid_count_html">Invalid QSLs: %d</string>
|
||||
<string name="import_progress_html">"Progress: "</string>
|
||||
<string name="import_readed_html">Validated QSL: %d</string>
|
||||
<string name="import_canceled_html">Canceled!</string>
|
||||
<string name="import_cancel_button">Stop</string>
|
||||
<!-- <string name="hello_blank_fragment">Hello blank fragment</string>-->
|
||||
|
||||
</resources>
|
|
@ -755,6 +755,17 @@
|
|||
<string name="deep_mode">ディープ</string>
|
||||
<string name="export_null">このデバイスと同じLANに接続し、ほかのデバイスでウェブブラウザーを利用してエクスポートしてください。\nブラウザーのアドレスバーに次の内容を入力してください:\n有効なWiFiに接続してください。</string>
|
||||
<string name="deep_mode_help">decode_help_en.txt</string>
|
||||
<string name="null_task_html">タスクが存在しません!</string>
|
||||
<string name="log_importing_html">インポート中…</string>
|
||||
<string name="log_import_finished_html">インポート済み!</string>
|
||||
<string name="import_read_error_count_html">エラー行: %d</string>
|
||||
<string name="import_new_count_html">新QSL数: %d</string>
|
||||
<string name="import_update_count_html">変更されたQSL数: %d</string>
|
||||
<string name="import_invalid_count_html">無効QSL数: %d</string>
|
||||
<string name="import_progress_html">進捗:</string>
|
||||
<string name="import_readed_html">確認済みQSL: %d</string>
|
||||
<string name="import_canceled_html">インポートが取り消されました!</string>
|
||||
<string name="import_cancel_button">インポートを取り消す</string>
|
||||
|
||||
|
||||
</resources>
|
|
@ -211,6 +211,7 @@
|
|||
<string name="html_qsl_start_time">通联开始时间</string>
|
||||
<string name="html_qsl_start_day">通联开始日期</string>
|
||||
<string name="html_qsl_end_time">通联结束时间</string>
|
||||
<string name="html_qsl_end_date">通联结束日期</string>
|
||||
<string name="html_qsl_mode">模式</string>
|
||||
<string name="html_qsl_grid">网格</string>
|
||||
<string name="html_qsl_band">频段</string>
|
||||
|
@ -470,6 +471,17 @@
|
|||
<string name="deep_mode">多次解码</string>
|
||||
<string name="export_null">请在与本机相同的局域网下,用其它设备的网页浏览器从后台导出。\n在浏览器的地址栏中输入如下内容:\n无法获取合适的IP地址,请连接到一个有效的Wifi。</string>
|
||||
<string name="deep_mode_help">decode_help.txt</string>
|
||||
<string name="null_task_html">任务不存在!</string>
|
||||
<string name="log_importing_html">正在导入...</string>
|
||||
<string name="log_import_finished_html">导入结束!</string>
|
||||
<string name="import_read_error_count_html">错误行数:%d</string>
|
||||
<string name="import_new_count_html">新增QSL:%d</string>
|
||||
<string name="import_update_count_html">更新QSL:%d</string>
|
||||
<string name="import_invalid_count_html">无效的QSL:%d</string>
|
||||
<string name="import_progress_html">进度:</string>
|
||||
<string name="import_readed_html">有效的QSL:%d</string>
|
||||
<string name="import_canceled_html">导入被取消!</string>
|
||||
<string name="import_cancel_button">停止导入</string>
|
||||
|
||||
|
||||
</resources>
|
|
@ -151,7 +151,7 @@
|
|||
<string name="calling">呼叫 %s(%s)</string>
|
||||
|
||||
<!-- 網格距離計算-->
|
||||
<string name="distance">%.0f仟米</string>
|
||||
<string name="distance">%.0f km</string>
|
||||
|
||||
<!-- 日誌列表-->
|
||||
<string name="confirmed">已確認</string>
|
||||
|
@ -471,6 +471,17 @@
|
|||
<string name="deep_mode">多次解碼</string>
|
||||
<string name="export_null">請在與本機相同的局域網下,用其它設備的網頁瀏覽器從後台導出。\n在瀏覽器的地址欄中輸入如下內容:\n無法獲取合適的IP地址,請連接到一個有效的Wifi。</string>
|
||||
<string name="deep_mode_help">decode_help.txt</string>
|
||||
<string name="null_task_html">任務不存在!</string>
|
||||
<string name="log_importing_html">正在匯入...</string>
|
||||
<string name="log_import_finished_html">匯入結束!</string>
|
||||
<string name="import_read_error_count_html">錯誤行數:%d</string>
|
||||
<string name="import_new_count_html">新增QSL:%d</string>
|
||||
<string name="import_update_count_html">更新QSL:%d</string>
|
||||
<string name="import_invalid_count_html">無效的QSL:%d</string>
|
||||
<string name="import_progress_html">進程:</string>
|
||||
<string name="import_readed_html">有效的QSL:%d</string>
|
||||
<string name="import_canceled_html">匯入被取消!</string>
|
||||
<string name="import_cancel_button">終止匯入</string>
|
||||
|
||||
|
||||
</resources>
|
|
@ -151,7 +151,7 @@
|
|||
<string name="calling">呼叫 %s(%s)</string>
|
||||
|
||||
<!-- 網格距離計算-->
|
||||
<string name="distance">%.0f仟米</string>
|
||||
<string name="distance">%.0f km</string>
|
||||
|
||||
<!-- 日誌列表-->
|
||||
<string name="confirmed">已確認</string>
|
||||
|
@ -471,6 +471,17 @@
|
|||
<string name="deep_mode">多次解碼</string>
|
||||
<string name="export_null">請在與本機相同的局域網下,用其它設備的網頁瀏覽器從後台導出。\n在瀏覽器的地址欄中輸入如下內容:\n無法獲取合適的IP地址,請連接到一個有效的Wifi。</string>
|
||||
<string name="deep_mode_help">decode_help.txt</string>
|
||||
<string name="null_task_html">任務不存在!</string>
|
||||
<string name="log_importing_html">正在匯入...</string>
|
||||
<string name="log_import_finished_html">匯入結束!</string>
|
||||
<string name="import_read_error_count_html">錯誤行數:%d</string>
|
||||
<string name="import_new_count_html">新增QSL:%d</string>
|
||||
<string name="import_update_count_html">更新QSL:%d</string>
|
||||
<string name="import_invalid_count_html">無效的QSL:%d</string>
|
||||
<string name="import_progress_html">進程:</string>
|
||||
<string name="import_readed_html">有效的QSL:%d</string>
|
||||
<string name="import_canceled_html">匯入被取消!</string>
|
||||
<string name="import_cancel_button">終止匯入</string>
|
||||
|
||||
|
||||
</resources>
|
|
@ -151,7 +151,7 @@
|
|||
<string name="calling">呼叫 %s(%s)</string>
|
||||
|
||||
<!-- 網格距離計算-->
|
||||
<string name="distance">%.0f仟米</string>
|
||||
<string name="distance">%.0f km</string>
|
||||
|
||||
<!-- 日誌列表-->
|
||||
<string name="confirmed">已確認</string>
|
||||
|
@ -471,6 +471,17 @@
|
|||
<string name="deep_mode">多次解碼</string>
|
||||
<string name="export_null">請在與本機相同的局域網下,用其它設備的網頁瀏覽器從後台導出。\n在瀏覽器的地址欄中輸入如下內容:\n無法獲取合適的IP地址,請連接到一個有效的Wifi。</string>
|
||||
<string name="deep_mode_help">decode_help.txt</string>
|
||||
<string name="null_task_html">任務不存在!</string>
|
||||
<string name="log_importing_html">正在匯入...</string>
|
||||
<string name="log_import_finished_html">匯入結束!</string>
|
||||
<string name="import_read_error_count_html">錯誤行數:%d</string>
|
||||
<string name="import_new_count_html">新增QSL:%d</string>
|
||||
<string name="import_update_count_html">更新QSL:%d</string>
|
||||
<string name="import_invalid_count_html">無效的QSL:%d</string>
|
||||
<string name="import_progress_html">進程:</string>
|
||||
<string name="import_readed_html">有效的QSL:%d</string>
|
||||
<string name="import_canceled_html">匯入被取消!</string>
|
||||
<string name="import_cancel_button">終止匯入</string>
|
||||
|
||||
|
||||
</resources>
|
|
@ -169,7 +169,7 @@
|
|||
<string name="log_manual_confirmation">Manual confirmation (%s)</string>
|
||||
|
||||
<!-- QSL日志列表-->
|
||||
<string name="qsl_grid">Gird:%s</string>
|
||||
<string name="qsl_grid">Grid:%s</string>
|
||||
<string name="qsl_start_time">Start time : %s</string>
|
||||
<string name="qsl_end_time">End time : %s</string>
|
||||
<string name="qsl_rst_rcvd">Rst received : %s</string>
|
||||
|
@ -475,6 +475,17 @@
|
|||
<string name="fast_mode">Fast decode</string>
|
||||
<string name="deep_mode">Deep decode</string>
|
||||
<string name="export_null">Export from WebUI via web browser on another device under the same LAN \n Please connect to a valid Wi-Fi</string>
|
||||
<string name="null_task_html">Task not exist!</string>
|
||||
<string name="log_importing_html">Importing...</string>
|
||||
<string name="log_import_finished_html">Finished !</string>
|
||||
<string name="import_read_error_count_html">Error lines: %d</string>
|
||||
<string name="import_new_count_html">Add QSLs: %d</string>
|
||||
<string name="import_update_count_html">Update QSLs: %d</string>
|
||||
<string name="import_invalid_count_html">Invalid QSLs: %d</string>
|
||||
<string name="import_progress_html">"Progress: "</string>
|
||||
<string name="import_readed_html">Validated QSL: %d</string>
|
||||
<string name="import_canceled_html">Canceled!</string>
|
||||
<string name="import_cancel_button">Stop</string>
|
||||
|
||||
|
||||
</resources>
|
|
@ -1,7 +1,7 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
id 'com.android.application' version '7.1.2' apply false
|
||||
id 'com.android.library' version '7.1.2' apply false
|
||||
id 'com.android.application' version '7.4.1' apply false
|
||||
id 'com.android.library' version '7.4.1' apply false
|
||||
}
|
||||
ext {
|
||||
var3 = 'G:\\coding\\ft8CN\\ft8CN.jks'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#Sat Jul 08 16:47:34 CST 2023
|
||||
#Fri Nov 11 20:54:19 CST 2022
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package com.bg7yoz.ft8cn.database;
|
||||
|
||||
public interface AfterInsertQSLData {
|
||||
void doAfterInsert(boolean isInvalid,boolean isNewQSL);
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
package com.bg7yoz.ft8cn.html;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
|
||||
import com.bg7yoz.ft8cn.GeneralVariables;
|
||||
import com.bg7yoz.ft8cn.R;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ImportTaskList extends HashMap<Integer, ImportTaskList.ImportTask> {
|
||||
|
||||
/**
|
||||
* 获取上传的任务,以session为key
|
||||
*
|
||||
* @param session session
|
||||
* @return 任务的HTML
|
||||
*/
|
||||
public String getTaskHTML(int session) {
|
||||
ImportTask task = this.get(session);
|
||||
if (task == null) {
|
||||
return GeneralVariables.getStringFromResource(R.string.null_task_html);
|
||||
}
|
||||
return task.getHtml();
|
||||
}
|
||||
public void cancelTask(int session){
|
||||
ImportTask task = this.get(session);
|
||||
if (task != null) {
|
||||
task.setStatus(ImportState.CANCELED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查任务是不是在运行。
|
||||
*
|
||||
* @param session 任务ID
|
||||
* @return false 没有任务或任务结束
|
||||
*/
|
||||
public boolean checkTaskIsRunning(int session) {
|
||||
ImportTask task = this.get(session);
|
||||
if (task == null) {
|
||||
return false;
|
||||
} else {
|
||||
return task.status == ImportState.STARTING || task.status == ImportState.IMPORTING;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加任务到列表,要确保线程安全
|
||||
*
|
||||
* @param session session
|
||||
* @param task 任务
|
||||
*/
|
||||
public synchronized ImportTask addTask(int session, ImportTask task) {
|
||||
this.put(session, task);
|
||||
return task;
|
||||
}
|
||||
|
||||
public ImportTask addTask(int session) {
|
||||
return addTask(session, new ImportTask(session));
|
||||
}
|
||||
|
||||
|
||||
enum ImportState {
|
||||
STARTING, IMPORTING, FINISHED, CANCELED
|
||||
}
|
||||
|
||||
public static class ImportTask {
|
||||
|
||||
|
||||
int session;//session,用于记录上传会话,是一个hash
|
||||
public int count = 0;//解析出总的数据量
|
||||
public int importedCount = 0;//导入的数量
|
||||
public int readErrorCount = 0;//读取数据错误数量
|
||||
public int processCount = 0;
|
||||
public int updateCount = 0;//更新的数量
|
||||
public int invalidCount = 0;//无效的QSL
|
||||
public int newCount = 0;//新导入的数量
|
||||
public ImportState status = ImportState.STARTING;//状态:0:开始,1:运行,2:结束,3:取消
|
||||
String message = "";//任务消息描述
|
||||
String errorMsg = "";
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
public String getHtml() {
|
||||
String htmlHeader = "<table bgcolor=#a1a1a1 border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n";
|
||||
String htmlEnder = "</table>\n";
|
||||
String progress = String.format("<FONT COLOR=\"BLUE\">%s %.1f%%(%d/%d)</FONT>\n", GeneralVariables.getStringFromResource(R.string.import_progress_html)
|
||||
, count == 0 ? 0 : processCount * 100f / count, processCount, count);
|
||||
String cell = "<tr><td>%s</td></tr>\n";
|
||||
String errorHtml = status == ImportState.FINISHED || status == ImportState.CANCELED ? errorMsg : "";
|
||||
String doCancelButton = status == ImportState.FINISHED || status == ImportState.CANCELED ? ""
|
||||
: String.format("<br><a href=\"cancelTask?session=%d\"><button>%s</button></a><br>"
|
||||
, session,GeneralVariables.getStringFromResource(R.string.import_cancel_button));
|
||||
return htmlHeader
|
||||
+ String.format(cell, progress)
|
||||
+ String.format(cell, String.format(GeneralVariables.getStringFromResource(R.string.import_read_error_count_html), readErrorCount))
|
||||
+ String.format(cell, String.format(GeneralVariables.getStringFromResource(R.string.import_new_count_html), newCount))
|
||||
+ String.format(cell, String.format(GeneralVariables.getStringFromResource(R.string.import_update_count_html), updateCount))
|
||||
+ String.format(cell, String.format(GeneralVariables.getStringFromResource(R.string.import_invalid_count_html), invalidCount))
|
||||
+ String.format(cell, String.format(GeneralVariables.getStringFromResource(R.string.import_readed_html), importedCount))
|
||||
+ String.format(cell, message)
|
||||
+ String.format(cell, errorHtml)
|
||||
+ htmlEnder
|
||||
+ doCancelButton;
|
||||
}
|
||||
|
||||
public ImportTask(int session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public void setStatus(ImportState status) {
|
||||
this.status = status;
|
||||
setStateMSG(status);
|
||||
}
|
||||
|
||||
private void setStateMSG(ImportState state) {
|
||||
switch (state) {
|
||||
case IMPORTING:
|
||||
this.message = String.format("<FONT COLOR=\"BLUE\"><B>%s</B></FONT>"
|
||||
,GeneralVariables.getStringFromResource(R.string.log_importing_html));
|
||||
break;
|
||||
case FINISHED:
|
||||
this.message = String.format("<FONT COLOR=\"GREEN\"><B>%s</B></FONT>"
|
||||
,GeneralVariables.getStringFromResource(R.string.log_import_finished_html));
|
||||
break;
|
||||
case CANCELED:
|
||||
this.message = String.format("<FONT COLOR=\"RED\"><B>%s</B></FONT>"
|
||||
,GeneralVariables.getStringFromResource(R.string.import_canceled_html));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
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.util.Log;
|
||||
|
||||
import com.bg7yoz.ft8cn.GeneralVariables;
|
||||
import com.bg7yoz.ft8cn.R;
|
||||
import com.bg7yoz.ft8cn.database.ControlMode;
|
||||
import com.bg7yoz.ft8cn.ui.ToastMessage;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* wolf 的cat指令集兼容yaesu 450d,但是有的ham在实际测试中发现,450d默认是dig-u,此模式在wolf上测试无法满功率发射,
|
||||
* 而采用usb模式就可以满功率发射,故增加一个usb模式的选项
|
||||
* 在创建rig时,用布尔参数是否时USB模式
|
||||
*/
|
||||
public class Wolf_sdr_450Rig extends BaseRig {
|
||||
private static final String TAG = "Wolf_sdr_450Rig";
|
||||
private final StringBuilder buffer = new StringBuilder();
|
||||
private int swr = 0;
|
||||
private int alc = 0;
|
||||
private boolean alcMaxAlert = false;
|
||||
private boolean swrAlert = false;
|
||||
|
||||
private Timer readFreqTimer = new Timer();
|
||||
private boolean isUsbMode=true;
|
||||
|
||||
private TimerTask readTask() {
|
||||
return new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (!isConnected()) {
|
||||
readFreqTimer.cancel();
|
||||
readFreqTimer.purge();
|
||||
readFreqTimer = null;
|
||||
return;
|
||||
}
|
||||
if (isPttOn()) {
|
||||
readMeters();
|
||||
} else {
|
||||
readFreqFromRig();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "readFreq error:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 读取Meter RM;
|
||||
*/
|
||||
private void readMeters() {
|
||||
if (getConnector() != null) {
|
||||
clearBufferData();//清空一下缓存
|
||||
getConnector().sendData(Yaesu3RigConstant.setRead39Meters_ALC());
|
||||
getConnector().sendData(Yaesu3RigConstant.setRead39Meters_SWR());
|
||||
}
|
||||
}
|
||||
|
||||
private void showAlert() {
|
||||
if (swr >= Yaesu3RigConstant.swr_39_alert_max) {
|
||||
if (!swrAlert) {
|
||||
swrAlert = true;
|
||||
ToastMessage.show(GeneralVariables.getStringFromResource(R.string.swr_high_alert));
|
||||
}
|
||||
} else {
|
||||
swrAlert = false;
|
||||
}
|
||||
if (alc > Yaesu3RigConstant.alc_39_alert_max) {//网络模式下不警告ALC
|
||||
if (!alcMaxAlert) {
|
||||
alcMaxAlert = true;
|
||||
ToastMessage.show(GeneralVariables.getStringFromResource(R.string.alc_high_alert));
|
||||
}
|
||||
} else {
|
||||
alcMaxAlert = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空缓存数据
|
||||
*/
|
||||
private void clearBufferData() {
|
||||
buffer.setLength(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPTT(boolean on) {
|
||||
super.setPTT(on);
|
||||
if (getConnector() != null) {
|
||||
switch (getControlMode()) {
|
||||
case ControlMode.CAT://以CIV指令
|
||||
getConnector().setPttOn(Yaesu3RigConstant.setPTT_TX_On(on));//针对YAESU 450指令
|
||||
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(Yaesu3RigConstant.setOperationDATA_U_Mode());
|
||||
//getConnector().sendData(Yaesu3RigConstant.setOperationUSB_Data_Mode());
|
||||
if (isUsbMode) {//usb模式
|
||||
getConnector().sendData(Yaesu3RigConstant.setOperationUSBMode());
|
||||
}else {//dig-u模式
|
||||
getConnector().sendData(Yaesu3RigConstant.setOperationDATA_U_Mode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFreqToRig() {
|
||||
if (getConnector() != null) {
|
||||
getConnector().sendData(Yaesu3RigConstant.setOperationFreq8Byte(getFreq()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveData(byte[] data) {
|
||||
String s = new String(data);
|
||||
//ToastMessage.showDebug("39 YAESU 读数据:"+new String(Yaesu3RigConstant.setReadOperationFreq()));
|
||||
|
||||
if (!s.contains(";")) {
|
||||
buffer.append(s);
|
||||
if (buffer.length()>1000) clearBufferData();
|
||||
//return;//说明数据还没接收完。
|
||||
} else {
|
||||
if (s.indexOf(";") > 0) {//说明接到结束的数据了,并且不是第一个字符是;
|
||||
buffer.append(s.substring(0, s.indexOf(";")));
|
||||
}
|
||||
|
||||
//开始分析数据
|
||||
Yaesu3Command yaesu3Command = Yaesu3Command.getCommand(buffer.toString());
|
||||
clearBufferData();//清一下缓存
|
||||
//要把剩下的数据放到缓存里
|
||||
buffer.append(s.substring(s.indexOf(";") + 1));
|
||||
|
||||
if (yaesu3Command == null) {
|
||||
return;
|
||||
}
|
||||
//long tempFreq = Yaesu3Command.getFrequency(yaesu3Command);
|
||||
//if (tempFreq != 0) {//如果tempFreq==0,说明频率不正常
|
||||
// setFreq(Yaesu3Command.getFrequency(yaesu3Command));
|
||||
//}
|
||||
|
||||
if (yaesu3Command.getCommandID().equalsIgnoreCase("FA")
|
||||
|| yaesu3Command.getCommandID().equalsIgnoreCase("FB")) {
|
||||
long tempFreq = Yaesu3Command.getFrequency(yaesu3Command);
|
||||
if (tempFreq != 0) {//如果tempFreq==0,说明频率不正常
|
||||
setFreq(Yaesu3Command.getFrequency(yaesu3Command));
|
||||
}
|
||||
} else if (yaesu3Command.getCommandID().equalsIgnoreCase("RM")) {//METER
|
||||
if (Yaesu3Command.isSWRMeter38(yaesu3Command)) {
|
||||
swr = Yaesu3Command.getALCOrSWR38(yaesu3Command);
|
||||
}
|
||||
if (Yaesu3Command.isALCMeter38(yaesu3Command)) {
|
||||
alc = Yaesu3Command.getALCOrSWR38(yaesu3Command);
|
||||
}
|
||||
showAlert();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFreqFromRig() {
|
||||
if (getConnector() != null) {
|
||||
clearBufferData();//清空一下缓存
|
||||
getConnector().sendData(Yaesu3RigConstant.setReadOperationFreq());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "WOLF SDR";
|
||||
}
|
||||
|
||||
public Wolf_sdr_450Rig(boolean usbMode) {
|
||||
isUsbMode=usbMode;
|
||||
readFreqTimer.schedule(readTask(), START_QUERY_FREQ_DELAY,QUERY_FREQ_TIMEOUT);
|
||||
}
|
||||
}
|
Ładowanie…
Reference in New Issue